import org.scalatest.FunSuite import exceptions._ class AccountTests extends FunSuite { val bank = new Bank() test("Test 01: Valid account withdrawal") { val acc = new Account(bank, 500) val result = acc.withdraw(250) assert(acc.getBalanceAmount == 250) assert(result.isLeft) } test("Test 02: Invalid account withdrawal should throw exception") { val acc = new Account(bank, 500) val result = acc.withdraw(750) assert(acc.getBalanceAmount == 500) assert(result.isRight) } test("Test 03: Withdrawal of negative amount should throw exception") { val acc = new Account(bank, 500) val result = acc.withdraw(-100) assert(acc.getBalanceAmount == 500) assert(result.isRight) } test("Test 04: Valid account deposit") { val acc = new Account(bank, 500) val result = acc.deposit(250) assert(acc.getBalanceAmount == 750) assert(result.isLeft) } test("Test 05: Deposit of negative amount should throw exception") { val acc = new Account(bank, 500) val result = acc.deposit(-50) assert(acc.getBalanceAmount == 500) assert(result.isRight) } test("Test 06: Correct balance amount after several withdrawals and deposits") { val acc = new Account(bank, 50000) val first = Main.thread { for (i <- 0 until 100) { acc.withdraw(10); Thread.sleep(10) } } val second = Main.thread { for (i <- 0 until 100) { acc.deposit(5); Thread.sleep(20) } } val third = Main.thread { for (i <- 0 until 100) { acc.withdraw(50); Thread.sleep(10) } } val fourth = Main.thread { for (i <- 0 until 100) { acc.deposit(100); Thread.sleep(10) } } first.join() second.join() third.join() fourth.join() assert(acc.getBalanceAmount == 54500) } } class AccountTransferTests extends FunSuite { test("Test 07: Valid transfer between accounts") { val bank = new Bank() val acc1 = bank.addAccount(100) val acc2 = bank.addAccount(200) acc1 transferTo(acc2, 50) while (bank.getProcessedTransactionsAsList.size != 1) { Thread.sleep(100) } assert(bank.getProcessedTransactionsAsList.last.status == TransactionStatus.SUCCESS) assert((acc1.getBalanceAmount == 50) && (acc2.getBalanceAmount == 250)) } test("Test 08: Transfer of negative amount between accounts should fail") { val bank = new Bank() val acc1 = bank.addAccount(500) val acc2 = bank.addAccount(1000) acc1 transferTo(acc2, -100) while (bank.getProcessedTransactionsAsList.size != 1) { Thread.sleep(100) } assert(bank.getProcessedTransactionsAsList.last.status == TransactionStatus.FAILED) assert((acc1.getBalanceAmount == 500) && (acc2.getBalanceAmount == 1000)) } test("Test 09: Invalid transfer between accounts due to insufficient funds should lead to transaction status FAILED and no money should be transferred between accounts") { val bank = new Bank() val acc1 = new Account(bank, 100) val acc2 = new Account(bank, 1000) acc1 transferTo(acc2, 150) while (bank.getProcessedTransactionsAsList.size != 1) { Thread.sleep(100) } assert(bank.getProcessedTransactionsAsList.last.status == TransactionStatus.FAILED) assert((acc1.getBalanceAmount == 100) && (acc2.getBalanceAmount == 1000)) } test("Test 10: Correct balance amounts after several transfers") { val bank = new Bank() val acc1 = new Account(bank, 3000) val acc2 = new Account(bank, 5000) val first = Main.thread { for (i <- 0 until 100) { bank addTransactionToQueue(acc1, acc2, 30) } } val second = Main.thread { for (i <- 0 until 100) { bank addTransactionToQueue(acc2, acc1, 23) } } first.join() second.join() while (bank.getProcessedTransactionsAsList.size != 200) { Thread.sleep(100) } assert((acc1.getBalanceAmount == 2300) && (acc2.getBalanceAmount == 5700)) } test("Test 11: Failed transactions should retry and potentially succeed with multiple allowed attempts") { var failed = 0 for (x <- 1 to 100) { val bank = new Bank(allowedAttempts = 3) val acc1 = new Account(bank, 100) val acc2 = new Account(bank, 100) val acc3 = new Account(bank, 100) for (i <- 1 to 6) { acc1 transferTo (acc2, 50) } for (j <- 1 to 2) { acc3 transferTo (acc1, 50) } while (bank.getProcessedTransactionsAsList.size != 8) { Thread.sleep(100) } if (!(acc1.getBalanceAmount == 0 && acc2.getBalanceAmount == 300 && acc3.getBalanceAmount == 0)) failed += 1 } assert(failed <= 5) } test("Test 12: Some transactions should be stopped with only one allowed attempt") { var failed = 0 for (x <- 1 to 100) { // This test is very unstable for more than 1 workers, // so we have edited it to only use one worker. val bank = new Bank(allowedAttempts = 1, workers = 1) val acc1 = new Account(bank, 100) val acc2 = new Account(bank, 100) val acc3 = new Account(bank, 100) for (i <- 1 to 6) { acc1 transferTo (acc2, 50) } for (j <- 1 to 2) { acc3 transferTo (acc1, 50) } while (bank.getProcessedTransactionsAsList.size != 8) { Thread.sleep(100) } if (!(acc2.getBalanceAmount != 300 && acc3.getBalanceAmount == 0)) failed += 1 } assert(failed <= 5) } }