From 045a5a9f644aee7a814df7600d1272bdfbf54393 Mon Sep 17 00:00:00 2001 From: lionarius Date: Sun, 17 Nov 2024 23:05:53 +0300 Subject: [PATCH] bullshit --- .../java/ConcurrentCurrencyExchangeTest.java | 69 +++++----- src/test/java/CurrencyExchangeTest.java | 121 +++++++++--------- 2 files changed, 94 insertions(+), 96 deletions(-) diff --git a/src/test/java/ConcurrentCurrencyExchangeTest.java b/src/test/java/ConcurrentCurrencyExchangeTest.java index 42933f4..f491f58 100644 --- a/src/test/java/ConcurrentCurrencyExchangeTest.java +++ b/src/test/java/ConcurrentCurrencyExchangeTest.java @@ -191,22 +191,22 @@ class ConcurrentCurrencyExchangeTest { @Test void testConcurrentOrderPlacement() throws InterruptedException { - var numSellers = 5; - var numBuyers = 5; + var numSellers = 10; + var numBuyers = 10; var ordersPerClient = 20; var latch = new CountDownLatch(numSellers + numBuyers); var sellers = new ArrayList(); for (int i = 0; i < numSellers; i++) { var seller = exchange.createClient("Seller " + i).join(); - exchange.deposit(seller.id(), CNY, 1000.0).join(); + exchange.deposit(seller.id(), CNY, 1000000.0).join(); sellers.add(seller); } var buyers = new ArrayList(); for (int i = 0; i < numBuyers; i++) { var buyer = exchange.createClient("Buyer " + i).join(); - exchange.deposit(buyer.id(), RUB, 1200.0).join(); + exchange.deposit(buyer.id(), RUB, 1200000.0).join(); buyers.add(buyer); } @@ -214,7 +214,7 @@ class ConcurrentCurrencyExchangeTest { .map(seller -> CompletableFuture.runAsync(() -> { try { for (int i = 0; i < ordersPerClient; i++) { - exchange.placeOrder(seller.id(), RUB_CNY, OrderType.SELL, 1.2, 10.0).join(); + exchange.placeOrder(seller.id(), RUB_CNY, OrderType.SELL, 10.0, 10.0).join(); Thread.sleep(10); } } catch (InterruptedException e) { @@ -350,20 +350,22 @@ class ConcurrentCurrencyExchangeTest { } @Test - void testBalanceConsistencyWithConcurrentTradesAndWithdrawals() throws InterruptedException { - var numTraders = 5; + void testBalanceConsistencyWithConcurrentTrades() throws InterruptedException { + var numTraders = 10; + var numOrders = 1000; var latch = new CountDownLatch(numTraders * 2); var sellers = new ArrayList(); var buyers = new ArrayList(); - var initialAmount = 1000.0; - + var sellAmount = 100.0; + var buyAmount = 100.0; + for (var i = 0; i < numTraders; i++) { var seller = exchange.createClient("Seller " + i).join(); var buyer = exchange.createClient("Buyer " + i).join(); - exchange.deposit(seller.id(), CNY, initialAmount).join(); - exchange.deposit(buyer.id(), RUB, initialAmount).join(); + exchange.deposit(seller.id(), CNY, sellAmount * numOrders).join(); + exchange.deposit(buyer.id(), RUB, buyAmount * numOrders).join(); sellers.add(seller); buyers.add(buyer); @@ -374,17 +376,10 @@ class ConcurrentCurrencyExchangeTest { for (var seller : sellers) { var future = CompletableFuture.runAsync(() -> { try { - for (int i = 0; i < 10; i++) { - exchange.placeOrder(seller.id(), RUB_CNY, OrderType.SELL, 1.2, 10.0).join(); - try { - exchange.withdraw(seller.id(), CNY, 1.0).join(); - } catch (CompletionException ignored) { - - } - Thread.sleep(10); + for (var i = 0; i < numOrders; i++) + { + exchange.placeOrder(seller.id(), RUB_CNY, OrderType.SELL, buyAmount, sellAmount).join(); } - } catch (InterruptedException e) { - Thread.currentThread().interrupt(); } finally { latch.countDown(); } @@ -395,16 +390,10 @@ class ConcurrentCurrencyExchangeTest { for (var buyer : buyers) { var future = CompletableFuture.runAsync(() -> { try { - for (int i = 0; i < 10; i++) { - exchange.placeOrder(buyer.id(), RUB_CNY, OrderType.BUY, 1.2, 10.0).join(); - try { - exchange.withdraw(buyer.id(), RUB, 1.0).join(); - } catch (CompletionException ignored) { - } - Thread.sleep(10); + for (var i = 0; i < numOrders; i++) + { + exchange.placeOrder(buyer.id(), RUB_CNY, OrderType.BUY, sellAmount, buyAmount).join(); } - } catch (InterruptedException e) { - Thread.currentThread().interrupt(); } finally { latch.countDown(); } @@ -414,12 +403,22 @@ class ConcurrentCurrencyExchangeTest { latch.await(30, TimeUnit.SECONDS); CompletableFuture.allOf(futures.toArray(new CompletableFuture[0])).join(); - - for (var client : Stream.concat(sellers.stream(), buyers.stream()).toList()) { - var balances = exchange.getBalances(client.id()).join(); - assertTrue(balances.get(RUB) >= 0, "RUB balance should not be negative"); - assertTrue(balances.get(CNY) >= 0, "CNY balance should not be negative"); + var totalRubMoney = 0.0; + var totalCnyMoney = 0.0; + + for (var seller : sellers) { + var balances = exchange.getBalances(seller.id()).join(); + totalCnyMoney += balances.get(CNY); + totalRubMoney += balances.get(RUB); } + for (var buyer : buyers) { + var balances = exchange.getBalances(buyer.id()).join(); + totalCnyMoney += balances.get(CNY); + totalRubMoney += balances.get(RUB); + } + + assertEquals(totalRubMoney, sellAmount * numOrders * numTraders, 0.001); + assertEquals(totalCnyMoney, sellAmount * numOrders * numTraders, 0.001); } @AfterEach diff --git a/src/test/java/CurrencyExchangeTest.java b/src/test/java/CurrencyExchangeTest.java index 8729f74..379b84c 100644 --- a/src/test/java/CurrencyExchangeTest.java +++ b/src/test/java/CurrencyExchangeTest.java @@ -30,8 +30,7 @@ class CurrencyExchangeTest { Arrays.asList(RUB_CNY) ); } - - // Client Tests + @Test void testCreateClient() throws ExecutionException, InterruptedException { var client = exchange.createClient("Trader").get(); @@ -52,7 +51,7 @@ class CurrencyExchangeTest { assertThrows(Exception.class, () -> exchange.getBalances(nonexistentId).get()); } - // Deposit Tests + @Test void testDeposit() throws ExecutionException, InterruptedException { var client = exchange.createClient("Trader").get(); @@ -77,7 +76,7 @@ class CurrencyExchangeTest { assertThrows(ExecutionException.class, () -> exchange.deposit(client.id(), null, 100.0).get()); } - // Withdraw Tests + @Test void testWithdraw() throws ExecutionException, InterruptedException { var client = exchange.createClient("Trader").get(); @@ -104,16 +103,16 @@ class CurrencyExchangeTest { exchange.deposit(client.id(), RUB, 500.0).get(); var balancesAfterDeposit = exchange.getBalances(client.id()).get(); - assertEquals(500.0, balancesAfterDeposit.get(RUB)); // Trader has 500 RUB + assertEquals(500.0, balancesAfterDeposit.get(RUB)); exchange.withdraw(client.id(), RUB, 200.0).get(); var balancesAfterWithdraw = exchange.getBalances(client.id()).get(); - assertEquals(300.0, balancesAfterWithdraw.get(RUB)); // Trader has 300 RUB + assertEquals(300.0, balancesAfterWithdraw.get(RUB)); - assertThrows(ExecutionException.class, () -> exchange.withdraw(client.id(), RUB, 400.0).get()); // Trader has only 300 RUB left + assertThrows(ExecutionException.class, () -> exchange.withdraw(client.id(), RUB, 400.0).get()); } - // Order Tests + @Test void testPlaceOrder() throws ExecutionException, InterruptedException { var client = exchange.createClient("Trader").get(); @@ -156,7 +155,7 @@ class CurrencyExchangeTest { ); } - // Order Matching Tests + @Test void testMatchingOrders() throws ExecutionException, InterruptedException { var buyer = exchange.createClient("Buyer").get(); @@ -171,10 +170,10 @@ class CurrencyExchangeTest { Map buyerBalances = exchange.getBalances(buyer.id()).get(); Map sellerBalances = exchange.getBalances(seller.id()).get(); - assertEquals(100.0, buyerBalances.get(CNY)); // Buyer bought 100 CNY - assertEquals(0.0, buyerBalances.get(RUB)); // Buyer sold 120 RUB so he has no RUB left - assertEquals(120.0, sellerBalances.get(RUB)); // Seller bought 120 RUB - assertEquals(0.0, sellerBalances.get(CNY)); // Seller sold 100 CNY so he has no CNY left + assertEquals(100.0, buyerBalances.get(CNY)); + assertEquals(0.0, buyerBalances.get(RUB)); + assertEquals(120.0, sellerBalances.get(RUB)); + assertEquals(0.0, sellerBalances.get(CNY)); } @Test @@ -191,13 +190,13 @@ class CurrencyExchangeTest { var buyerBalances = exchange.getBalances(buyer.id()).get(); var sellerBalances = exchange.getBalances(seller.id()).get(); - assertEquals(50.0, buyerBalances.get(CNY)); // Buyer bought 50 CNY - assertEquals(60.0, sellerBalances.get(RUB)); // Seller bought 60 RUB + assertEquals(50.0, buyerBalances.get(CNY)); + assertEquals(60.0, sellerBalances.get(RUB)); var sellerOrders = exchange.getActiveOrders(seller.id()).get(); var remainingOrder = sellerOrders.iterator().next(); - // Seller has 60/50 RUB/CNY order left + assertEquals(RUB_CNY, remainingOrder.pair()); assertEquals(50.0, remainingOrder.quantity()); assertEquals(60.0, remainingOrder.price()); @@ -221,12 +220,12 @@ class CurrencyExchangeTest { var buyer2Balances = exchange.getBalances(buyer2.id()).get(); var sellerBalances = exchange.getBalances(seller.id()).get(); - assertEquals(50.0, buyer1Balances.get(CNY)); // Buyer1 bought 50 CNY - assertEquals(50.0, buyer2Balances.get(CNY)); // Buyer2 bought 50 CNY - assertEquals(120.0, sellerBalances.get(RUB)); // Seller bought 120 RUB + assertEquals(50.0, buyer1Balances.get(CNY)); + assertEquals(50.0, buyer2Balances.get(CNY)); + assertEquals(120.0, sellerBalances.get(RUB)); var sellerOrders = exchange.getActiveOrders(seller.id()).get(); - assertFalse(sellerOrders.iterator().hasNext()); // Seller has no orders left + assertFalse(sellerOrders.iterator().hasNext()); } @Test @@ -243,10 +242,10 @@ class CurrencyExchangeTest { var buyerBalances = exchange.getBalances(buyer.id()).get(); var sellerBalances = exchange.getBalances(seller.id()).get(); - assertEquals(100.0, buyerBalances.get(CNY)); // Buyer bought 100 CNY - assertEquals(180.0, buyerBalances.get(RUB)); // Buyer spends 120 RUB - assertEquals(120.0, sellerBalances.get(RUB)); // Seller bought 120 RUB - assertEquals(100.0, sellerBalances.get(CNY)); // Seller retains remaining CNY + assertEquals(100.0, buyerBalances.get(CNY)); + assertEquals(180.0, buyerBalances.get(RUB)); + assertEquals(120.0, sellerBalances.get(RUB)); + assertEquals(100.0, sellerBalances.get(CNY)); } @Test @@ -268,18 +267,18 @@ class CurrencyExchangeTest { var buyer2Balances = exchange.getBalances(buyer2.id()).get(); var sellerBalances = exchange.getBalances(seller.id()).get(); - assertEquals(30.0, buyer1Balances.get(CNY)); // Buyer1 bought 30 CNY - assertEquals(24.0, buyer1Balances.get(RUB)); // Buyer1 sold 36 CNY + assertEquals(30.0, buyer1Balances.get(CNY)); + assertEquals(24.0, buyer1Balances.get(RUB)); - assertEquals(30.0, buyer2Balances.get(CNY)); // Buyer2 bought 30 CNY - assertEquals(24.0, buyer2Balances.get(RUB)); // Buyer2 sold 36 CNY + assertEquals(30.0, buyer2Balances.get(CNY)); + assertEquals(24.0, buyer2Balances.get(RUB)); var sellerOrders = exchange.getActiveOrders(seller.id()).get(); var sellerOrder = sellerOrders.iterator().next(); - assertEquals(40.0, sellerOrder.quantity()); // 40 CNY reserved - assertEquals(48.0, sellerOrder.price()); // 1.2 RUB per CNY - assertEquals(72.0, sellerBalances.get(RUB)); // 72 RUB earned + assertEquals(40.0, sellerOrder.quantity()); + assertEquals(48.0, sellerOrder.price()); + assertEquals(72.0, sellerBalances.get(RUB)); } @Test @@ -314,8 +313,8 @@ class CurrencyExchangeTest { exchange.deposit(seller1.id(), CNY, 50.0).get(); exchange.deposit(seller2.id(), CNY, 50.0).get(); - exchange.placeOrder(seller1.id(), RUB_CNY, OrderType.SELL, 75, 50.0).get(); // Higher price - exchange.placeOrder(seller2.id(), RUB_CNY, OrderType.SELL, 60, 50.0).get(); // Lower price + exchange.placeOrder(seller1.id(), RUB_CNY, OrderType.SELL, 75, 50.0).get(); + exchange.placeOrder(seller2.id(), RUB_CNY, OrderType.SELL, 60, 50.0).get(); exchange.placeOrder(buyer.id(), RUB_CNY, OrderType.BUY, 75, 50.0).get(); @@ -323,14 +322,14 @@ class CurrencyExchangeTest { var seller1Balances = exchange.getBalances(seller1.id()).get(); var seller2Balances = exchange.getBalances(seller2.id()).get(); - assertEquals(50.0, buyerBalances.get(CNY)); // Buyer gets 50 CNY from the lower-priced seller - assertEquals(140.0, buyerBalances.get(RUB)); // Buyer spends 60 RUB + assertEquals(50.0, buyerBalances.get(CNY)); + assertEquals(140.0, buyerBalances.get(RUB)); - assertEquals(60.0, seller2Balances.get(RUB)); // Seller2 sells at 60 price - assertEquals(0.0, seller2Balances.get(CNY)); // Seller2 has no CNY left + assertEquals(60.0, seller2Balances.get(RUB)); + assertEquals(0.0, seller2Balances.get(CNY)); - assertNull(seller1Balances.get(RUB)); // Seller1 remains untouched - assertEquals(0.0, seller1Balances.get(CNY)); // Seller1 still has their CNY reserved + assertNull(seller1Balances.get(RUB)); + assertEquals(0.0, seller1Balances.get(CNY)); } @Test @@ -345,9 +344,9 @@ class CurrencyExchangeTest { exchange.deposit(seller2.id(), CNY, 50.0).get(); exchange.deposit(seller3.id(), CNY, 50.0).get(); - exchange.placeOrder(seller1.id(), RUB_CNY, OrderType.SELL, 75.0, 50.0).get(); // Highest price - exchange.placeOrder(seller2.id(), RUB_CNY, OrderType.SELL, 65.0, 50.0).get(); // Medium price - exchange.placeOrder(seller3.id(), RUB_CNY, OrderType.SELL, 60.0, 50.0).get(); // Lowest price + exchange.placeOrder(seller1.id(), RUB_CNY, OrderType.SELL, 75.0, 50.0).get(); + exchange.placeOrder(seller2.id(), RUB_CNY, OrderType.SELL, 65.0, 50.0).get(); + exchange.placeOrder(seller3.id(), RUB_CNY, OrderType.SELL, 60.0, 50.0).get(); exchange.placeOrder(buyer.id(), RUB_CNY, OrderType.BUY, 150.0, 100.0).get(); @@ -356,17 +355,17 @@ class CurrencyExchangeTest { var seller2Balances = exchange.getBalances(seller2.id()).get(); var seller3Balances = exchange.getBalances(seller3.id()).get(); - assertEquals(100.0, buyerBalances.get(CNY)); // Buyer receives 100 CNY (50 from seller3 and 50 from seller2) - assertEquals(175.0, buyerBalances.get(RUB)); // Buyer spends 125 RUB (60 + 65) + assertEquals(100.0, buyerBalances.get(CNY)); + assertEquals(175.0, buyerBalances.get(RUB)); - assertEquals(60.0, seller3Balances.get(RUB)); // Seller3 sells at 60 price - assertEquals(0.0, seller3Balances.get(CNY)); // Seller3's CNY is reduced to 0 + assertEquals(60.0, seller3Balances.get(RUB)); + assertEquals(0.0, seller3Balances.get(CNY)); - assertEquals(65.0, seller2Balances.get(RUB)); // Seller2 sells at 65 price - assertEquals(0.0, seller2Balances.get(CNY)); // Seller2's CNY is reduced to 0 + assertEquals(65.0, seller2Balances.get(RUB)); + assertEquals(0.0, seller2Balances.get(CNY)); - assertNull(seller1Balances.get(RUB)); // Seller1 remains untouched - assertEquals(0.0, seller1Balances.get(CNY)); // Seller1 still has their CNY reserved + assertNull(seller1Balances.get(RUB)); + assertEquals(0.0, seller1Balances.get(CNY)); } @Test @@ -379,8 +378,8 @@ class CurrencyExchangeTest { exchange.deposit(seller1.id(), CNY, 50.0).get(); exchange.deposit(seller2.id(), CNY, 50.0).get(); - exchange.placeOrder(seller1.id(), RUB_CNY, OrderType.SELL, 60, 50.0).get(); // Placed first - exchange.placeOrder(seller2.id(), RUB_CNY, OrderType.SELL, 60, 50.0).get(); // Placed second + exchange.placeOrder(seller1.id(), RUB_CNY, OrderType.SELL, 60, 50.0).get(); + exchange.placeOrder(seller2.id(), RUB_CNY, OrderType.SELL, 60, 50.0).get(); exchange.placeOrder(buyer.id(), RUB_CNY, OrderType.BUY, 60, 50.0).get(); @@ -388,13 +387,13 @@ class CurrencyExchangeTest { var seller1Balances = exchange.getBalances(seller1.id()).get(); var seller2Balances = exchange.getBalances(seller2.id()).get(); - assertEquals(50.0, buyerBalances.get(CNY)); // Buyer gets 50 CNY - assertEquals(140.0, buyerBalances.get(RUB)); // Buyer spends 60 RUB + assertEquals(50.0, buyerBalances.get(CNY)); + assertEquals(140.0, buyerBalances.get(RUB)); - assertEquals(60.0, seller1Balances.get(RUB)); // Seller1 sells first - assertEquals(0.0, seller1Balances.get(CNY)); // Seller1's CNY is reduced to 0 + assertEquals(60.0, seller1Balances.get(RUB)); + assertEquals(0.0, seller1Balances.get(CNY)); - assertNull(seller2Balances.get(RUB)); // Seller2 remains untouched + assertNull(seller2Balances.get(RUB)); } @Test @@ -416,13 +415,13 @@ class CurrencyExchangeTest { var buyer2Balances = exchange.getBalances(buyer2.id()).get(); var sellerBalances = exchange.getBalances(seller.id()).get(); - assertNull(sellerBalances.get(RUB)); // Seller did not sell anything - assertEquals(0.0, sellerBalances.get(CNY)); // Seller has no CNY left + assertNull(sellerBalances.get(RUB)); + assertEquals(0.0, sellerBalances.get(CNY)); - assertNull(buyer1Balances.get(CNY)); // Buyer1 did not buy anything + assertNull(buyer1Balances.get(CNY)); assertEquals(120.0, buyer1Balances.get(RUB)); - assertNull(buyer2Balances.get(CNY)); // Buyer2 did not buy anything + assertNull(buyer2Balances.get(CNY)); assertEquals(125.0, buyer2Balances.get(RUB)); }