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 ) ); } ); } }