Merge pull request 'Implement JUnit 5 test suite for concurrency and deadlock scenarios' (#1) from unit-test into dev
Reviewed-on: #1
This commit was merged in pull request #1.
This commit is contained in:
Generated
+8
@@ -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
|
||||
Generated
+13
@@ -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>
|
||||
Generated
+7
@@ -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>
|
||||
Generated
+20
@@ -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>
|
||||
Generated
+14
@@ -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
@@ -0,0 +1,6 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<project version="4">
|
||||
<component name="VcsDirectoryMappings">
|
||||
<mapping directory="" vcs="Git" />
|
||||
</component>
|
||||
</project>
|
||||
@@ -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>
|
||||
@@ -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()
|
||||
);
|
||||
}
|
||||
}
|
||||
@@ -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()
|
||||
);
|
||||
}
|
||||
}
|
||||
@@ -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
|
||||
)
|
||||
);
|
||||
}
|
||||
);
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user