Merge pull request 'Implement JUnit 5 test suite for concurrency and deadlock scenarios' (#1) from unit-test into dev

Reviewed-on: AdvancedProgramming1404/HW-09-Advanced-Multithreading#1
This commit is contained in:
2026-06-05 00:04:44 +00:00
10 changed files with 281 additions and 3 deletions
+8
View File
@@ -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
+13
View File
@@ -0,0 +1,13 @@
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<component name="CompilerConfiguration">
<annotationProcessing>
<profile name="Maven default annotation processors profile" enabled="true">
<sourceOutputDir name="target/generated-sources/annotations" />
<sourceTestOutputDir name="target/generated-test-sources/test-annotations" />
<outputRelativeToContentRoot value="true" />
<module name="HW-09-Advanced-Multithreading" />
</profile>
</annotationProcessing>
</component>
</project>
+7
View File
@@ -0,0 +1,7 @@
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<component name="Encoding">
<file url="file://$PROJECT_DIR$/src/main/java" charset="UTF-8" />
<file url="file://$PROJECT_DIR$/src/main/resources" charset="UTF-8" />
</component>
</project>
+20
View File
@@ -0,0 +1,20 @@
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<component name="RemoteRepositoriesConfiguration">
<remote-repository>
<option name="id" value="central" />
<option name="name" value="Central Repository" />
<option name="url" value="https://repo.maven.apache.org/maven2" />
</remote-repository>
<remote-repository>
<option name="id" value="central" />
<option name="name" value="Maven Central repository" />
<option name="url" value="https://repo1.maven.org/maven2" />
</remote-repository>
<remote-repository>
<option name="id" value="jboss.community" />
<option name="name" value="JBoss Community repository" />
<option name="url" value="https://repository.jboss.org/nexus/content/repositories/public/" />
</remote-repository>
</component>
</project>
+14
View File
@@ -0,0 +1,14 @@
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<component name="ExternalStorageConfigurationManager" enabled="true" />
<component name="MavenProjectsManager">
<option name="originalFiles">
<list>
<option value="$PROJECT_DIR$/pom.xml" />
</list>
</option>
</component>
<component name="ProjectRootManager" version="2" languageLevel="JDK_X" default="true" project-jdk-name="homebrew-24" project-jdk-type="JavaSDK">
<output url="file://$PROJECT_DIR$/out" />
</component>
</project>
Generated
+6
View File
@@ -0,0 +1,6 @@
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<component name="VcsDirectoryMappings">
<mapping directory="" vcs="Git" />
</component>
</project>
+19
View File
@@ -14,4 +14,23 @@
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
</properties>
<dependencies>
<dependency>
<groupId>org.junit.jupiter</groupId>
<artifactId>junit-jupiter</artifactId>
<version>5.12.2</version>
<scope>test</scope>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-surefire-plugin</artifactId>
<version>3.5.3</version>
</plugin>
</plugins>
</build>
</project>
+45
View File
@@ -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()
);
}
}
+52
View File
@@ -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()
);
}
}
+94
View File
@@ -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
)
);
}
);
}
}