From 73395fa1882ea3a04d30b38f32aa478d14362420 Mon Sep 17 00:00:00 2001 From: arya Date: Thu, 4 Jun 2026 21:00:09 +0330 Subject: [PATCH] test: add unit tests for multithreading scenarios --- .idea/.gitignore | 8 +++ .idea/compiler.xml | 13 +++++ .idea/encodings.xml | 7 +++ .idea/jarRepositories.xml | 20 +++++++ .idea/misc.xml | 14 +++++ .idea/vcs.xml | 6 ++ pom.xml | 19 +++++++ src/test/java/banking/TestA.java | 47 +++++++++++++++- src/test/java/banking/TestB.java | 54 +++++++++++++++++- src/test/java/banking/TestC.java | 96 +++++++++++++++++++++++++++++++- 10 files changed, 281 insertions(+), 3 deletions(-) create mode 100644 .idea/.gitignore create mode 100644 .idea/compiler.xml create mode 100644 .idea/encodings.xml create mode 100644 .idea/jarRepositories.xml create mode 100644 .idea/misc.xml create mode 100644 .idea/vcs.xml diff --git a/.idea/.gitignore b/.idea/.gitignore new file mode 100644 index 0000000..13566b8 --- /dev/null +++ b/.idea/.gitignore @@ -0,0 +1,8 @@ +# Default ignored files +/shelf/ +/workspace.xml +# Editor-based HTTP Client requests +/httpRequests/ +# Datasource local storage ignored files +/dataSources/ +/dataSources.local.xml diff --git a/.idea/compiler.xml b/.idea/compiler.xml new file mode 100644 index 0000000..812c3f9 --- /dev/null +++ b/.idea/compiler.xml @@ -0,0 +1,13 @@ + + + + + + + + + + + + + \ No newline at end of file diff --git a/.idea/encodings.xml b/.idea/encodings.xml new file mode 100644 index 0000000..aa00ffa --- /dev/null +++ b/.idea/encodings.xml @@ -0,0 +1,7 @@ + + + + + + + \ No newline at end of file diff --git a/.idea/jarRepositories.xml b/.idea/jarRepositories.xml new file mode 100644 index 0000000..712ab9d --- /dev/null +++ b/.idea/jarRepositories.xml @@ -0,0 +1,20 @@ + + + + + + + + + + + \ No newline at end of file diff --git a/.idea/misc.xml b/.idea/misc.xml new file mode 100644 index 0000000..856f2f3 --- /dev/null +++ b/.idea/misc.xml @@ -0,0 +1,14 @@ + + + + + + + + + + \ No newline at end of file diff --git a/.idea/vcs.xml b/.idea/vcs.xml new file mode 100644 index 0000000..35eb1dd --- /dev/null +++ b/.idea/vcs.xml @@ -0,0 +1,6 @@ + + + + + + \ No newline at end of file diff --git a/pom.xml b/pom.xml index 2182652..33ea6f3 100644 --- a/pom.xml +++ b/pom.xml @@ -14,4 +14,23 @@ UTF-8 + + + org.junit.jupiter + junit-jupiter + 5.12.2 + test + + + + + + + org.apache.maven.plugins + maven-surefire-plugin + 3.5.3 + + + + \ No newline at end of file diff --git a/src/test/java/banking/TestA.java b/src/test/java/banking/TestA.java index ce2cd6b..35659eb 100644 --- a/src/test/java/banking/TestA.java +++ b/src/test/java/banking/TestA.java @@ -1,4 +1,49 @@ package banking; +import dev.banking.model.BankAccount; +import org.junit.jupiter.api.Test; + +import java.util.concurrent.CountDownLatch; +import java.util.concurrent.ExecutorService; +import java.util.concurrent.Executors; + +import static org.junit.jupiter.api.Assertions.assertEquals; + public class TestA { -} + + @Test + void concurrentDeposits() throws Exception { + + BankAccount account = new BankAccount(1, 0); + + int threadCount = 100; + int depositsPerThread = 1000; + + ExecutorService executor = + Executors.newFixedThreadPool(threadCount); + + CountDownLatch latch = + new CountDownLatch(threadCount); + + for (int i = 0; i < threadCount; i++) { + + executor.submit(() -> { + + for (int j = 0; j < depositsPerThread; j++) { + account.deposit(1); + } + + latch.countDown(); + }); + } + + latch.await(); + + executor.shutdown(); + + assertEquals( + threadCount * depositsPerThread, + account.getBalance() + ); + } +} \ No newline at end of file diff --git a/src/test/java/banking/TestB.java b/src/test/java/banking/TestB.java index b5104e3..66daa64 100644 --- a/src/test/java/banking/TestB.java +++ b/src/test/java/banking/TestB.java @@ -1,4 +1,56 @@ package banking; +import dev.banking.model.BankAccount; +import org.junit.jupiter.api.Test; + +import java.util.concurrent.CountDownLatch; +import java.util.concurrent.ExecutorService; +import java.util.concurrent.Executors; + +import static org.junit.jupiter.api.Assertions.assertEquals; + public class TestB { -} + + @Test + void concurrentDepositWithdraw() throws Exception { + + BankAccount account = + new BankAccount(1, 1_000_000); + + ExecutorService executor = + Executors.newFixedThreadPool(100); + + CountDownLatch latch = + new CountDownLatch(100); + + for (int i = 0; i < 50; i++) { + + executor.submit(() -> { + + for (int j = 0; j < 10000; j++) { + account.deposit(1); + } + + latch.countDown(); + }); + + executor.submit(() -> { + + for (int j = 0; j < 10000; j++) { + account.withdraw(1); + } + + latch.countDown(); + }); + } + + latch.await(); + + executor.shutdown(); + + assertEquals( + 1_000_000, + account.getBalance() + ); + } +} \ No newline at end of file diff --git a/src/test/java/banking/TestC.java b/src/test/java/banking/TestC.java index 84da5d5..93ea4a2 100644 --- a/src/test/java/banking/TestC.java +++ b/src/test/java/banking/TestC.java @@ -1,4 +1,98 @@ package banking; +import dev.banking.model.BankAccount; +import org.junit.jupiter.api.Test; + +import java.time.Duration; +import java.util.concurrent.CountDownLatch; +import java.util.concurrent.ExecutorService; +import java.util.concurrent.Executors; +import java.util.concurrent.TimeUnit; + +import static org.junit.jupiter.api.Assertions.*; + public class TestC { -} + + @Test + void transferConservation() throws Exception { + + BankAccount a = + new BankAccount(1, 100_000); + + BankAccount b = + new BankAccount(2, 100_000); + + ExecutorService executor = + Executors.newFixedThreadPool(50); + + CountDownLatch latch = + new CountDownLatch(100); + + for (int i = 0; i < 50; i++) { + + executor.submit(() -> { + + for (int j = 0; j < 1000; j++) { + a.transfer(b, 1); + } + + latch.countDown(); + }); + + executor.submit(() -> { + + for (int j = 0; j < 1000; j++) { + b.transfer(a, 1); + } + + latch.countDown(); + }); + } + + latch.await(); + + executor.shutdown(); + + long total = + a.getBalance() + b.getBalance(); + + assertEquals(200_000, total); + } + + @Test + void deadlockFreeTransfers() { + + assertTimeoutPreemptively( + Duration.ofSeconds(5), + () -> { + + BankAccount a = + new BankAccount(1, 1_000_000); + + BankAccount b = + new BankAccount(2, 1_000_000); + + ExecutorService executor = + Executors.newFixedThreadPool(50); + + for (int i = 0; i < 50000; i++) { + + executor.submit(() -> + a.transfer(b, 1)); + + executor.submit(() -> + b.transfer(a, 1)); + } + + executor.shutdown(); + + assertTrue( + executor.awaitTermination( + 5, + TimeUnit.SECONDS + ) + ); + } + ); + } +} \ No newline at end of file