Skip to content

Commit aee8088

Browse files
authored
Unit tests for accountant (#290)
1 parent b83f238 commit aee8088

File tree

47 files changed

+1594
-588
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

47 files changed

+1594
-588
lines changed

accountant/accountant-app/src/main/kotlin/co/nilin/opex/accountant/app/config/AppConfig.kt

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -104,31 +104,31 @@ class AppConfig {
104104

105105
@Autowired
106106
fun configureOrderListener(orderKafkaListener: OrderKafkaListener, orderListener: OrderListener) {
107-
orderKafkaListener.addOrderListener(orderListener)
107+
orderKafkaListener.addListener(orderListener)
108108
}
109109

110110
@Autowired
111111
fun configureTradeListener(
112112
tradeKafkaListener: TradeKafkaListener,
113113
accountantTradeListener: AccountantTradeListener
114114
) {
115-
tradeKafkaListener.addTradeListener(accountantTradeListener)
115+
tradeKafkaListener.addListener(accountantTradeListener)
116116
}
117117

118118
@Autowired
119119
fun configureEventListener(
120120
eventKafkaListener: EventKafkaListener,
121121
accountantEventListener: AccountantEventListener
122122
) {
123-
eventKafkaListener.addEventListener(accountantEventListener)
123+
eventKafkaListener.addListener(accountantEventListener)
124124
}
125125

126126
@Autowired
127127
fun configureTempEventListener(
128128
tempEventKafkaListener: TempEventKafkaListener,
129129
accountantTempEventListener: AccountantTempEventListener
130130
) {
131-
tempEventKafkaListener.addEventListener(accountantTempEventListener)
131+
tempEventKafkaListener.addListener(accountantTempEventListener)
132132
}
133133

134134
}

accountant/accountant-app/src/main/kotlin/co/nilin/opex/accountant/app/listener/AccountantEventListener.kt

Lines changed: 7 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -11,15 +11,15 @@ class AccountantEventListener(private val orderManager: OrderManager) : EventLis
1111
return "EventListener"
1212
}
1313

14-
override fun onEvent(coreEvent: CoreEvent, partition: Int, offset: Long, timestamp: Long) {
14+
override fun onEvent(event: CoreEvent, partition: Int, offset: Long, timestamp: Long) {
1515
runBlocking {
16-
when (coreEvent) {
17-
is CreateOrderEvent -> orderManager.handleNewOrder(coreEvent)
18-
is RejectOrderEvent -> orderManager.handleRejectOrder(coreEvent)
19-
is UpdatedOrderEvent -> orderManager.handleUpdateOrder(coreEvent)
20-
is CancelOrderEvent -> orderManager.handleCancelOrder(coreEvent)
16+
when (event) {
17+
is CreateOrderEvent -> orderManager.handleNewOrder(event)
18+
is RejectOrderEvent -> orderManager.handleRejectOrder(event)
19+
is UpdatedOrderEvent -> orderManager.handleUpdateOrder(event)
20+
is CancelOrderEvent -> orderManager.handleCancelOrder(event)
2121
else -> {
22-
println("Event is not accepted ${coreEvent::class.java}")
22+
println("Event is not accepted ${event::class.java}")
2323
}
2424
}
2525
}

accountant/accountant-app/src/main/kotlin/co/nilin/opex/accountant/app/listener/AccountantTempEventListener.kt

Lines changed: 9 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -15,17 +15,17 @@ class AccountantTempEventListener(
1515
return "TempEventListener"
1616
}
1717

18-
override fun onEvent(coreEvent: CoreEvent, partition: Int, offset: Long, timestamp: Long) {
19-
println("TempEvent $coreEvent")
18+
override fun onEvent(event: CoreEvent, partition: Int, offset: Long, timestamp: Long) {
19+
println("TempEvent $event")
2020
runBlocking {
21-
when (coreEvent) {
22-
is CreateOrderEvent -> orderManager.handleNewOrder(coreEvent)
23-
is RejectOrderEvent -> orderManager.handleRejectOrder(coreEvent)
24-
is UpdatedOrderEvent -> orderManager.handleUpdateOrder(coreEvent)
25-
is CancelOrderEvent -> orderManager.handleCancelOrder(coreEvent)
26-
is TradeEvent -> tradeManager.handleTrade(coreEvent)
21+
when (event) {
22+
is CreateOrderEvent -> orderManager.handleNewOrder(event)
23+
is RejectOrderEvent -> orderManager.handleRejectOrder(event)
24+
is UpdatedOrderEvent -> orderManager.handleUpdateOrder(event)
25+
is CancelOrderEvent -> orderManager.handleCancelOrder(event)
26+
is TradeEvent -> tradeManager.handleTrade(event)
2727
else -> {
28-
throw IllegalArgumentException("Event is not accepted ${coreEvent::class.java}")
28+
throw IllegalArgumentException("Event is not accepted ${event::class.java}")
2929
}
3030
}
3131
}

accountant/accountant-app/src/main/kotlin/co/nilin/opex/accountant/app/listener/AccountantTradeListener.kt

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
package co.nilin.opex.accountant.app.listener
22

33
import co.nilin.opex.accountant.core.api.TradeManager
4+
import co.nilin.opex.accountant.ports.kafka.listener.spi.Listener
45
import co.nilin.opex.accountant.ports.kafka.listener.spi.TradeListener
56
import co.nilin.opex.matching.engine.core.eventh.events.TradeEvent
67
import kotlinx.coroutines.runBlocking
@@ -11,9 +12,9 @@ class AccountantTradeListener(private val tradeManager: TradeManager) : TradeLis
1112
return "TradeListener"
1213
}
1314

14-
override fun onTrade(tradeEvent: TradeEvent, partition: Int, offset: Long, timestamp: Long) {
15+
override fun onEvent(event: TradeEvent, partition: Int, offset: Long, timestamp: Long) {
1516
runBlocking {
16-
tradeManager.handleTrade(tradeEvent)
17+
tradeManager.handleTrade(event)
1718
}
1819
}
1920
}

accountant/accountant-app/src/main/kotlin/co/nilin/opex/accountant/app/listener/OrderListener.kt

Lines changed: 12 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -15,22 +15,22 @@ class OrderListener(private val orderManager: OrderManager) : OrderSubmitRequest
1515
return "OrderListener"
1616
}
1717

18-
override fun onOrder(order: OrderSubmitRequest, partition: Int, offset: Long, timestamp: Long) {
18+
override fun onEvent(event: OrderSubmitRequest, partition: Int, offset: Long, timestamp: Long) {
1919
runBlocking {
20-
logger.info("Order submit event received ${order.ouid}")
20+
logger.info("Order submit event received ${event.ouid}")
2121

2222
orderManager.handleRequestOrder(
2323
SubmitOrderEvent(
24-
order.ouid,
25-
order.uuid,
26-
order.orderId,
27-
order.pair,
28-
order.price,
29-
order.quantity,
30-
order.quantity,
31-
order.direction,
32-
order.matchConstraint,
33-
order.orderType
24+
event.ouid,
25+
event.uuid,
26+
event.orderId,
27+
event.pair,
28+
event.price,
29+
event.quantity,
30+
event.quantity,
31+
event.direction,
32+
event.matchConstraint,
33+
event.orderType
3434
)
3535
)
3636
}

accountant/accountant-core/pom.xml

Lines changed: 11 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -50,8 +50,17 @@
5050
<scope>provided</scope>
5151
</dependency>
5252
<dependency>
53-
<groupId>org.mockito</groupId>
54-
<artifactId>mockito-core</artifactId>
53+
<groupId>org.mockito.kotlin</groupId>
54+
<artifactId>mockito-kotlin</artifactId>
55+
</dependency>
56+
<dependency>
57+
<groupId>io.mockk</groupId>
58+
<artifactId>mockk</artifactId>
59+
</dependency>
60+
<dependency>
61+
<groupId>org.jetbrains.kotlinx</groupId>
62+
<artifactId>kotlinx-coroutines-core</artifactId>
63+
<scope>test</scope>
5564
</dependency>
5665
</dependencies>
5766
</project>
Lines changed: 112 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,112 @@
1+
package co.nilin.opex.accountant.core.service
2+
3+
import co.nilin.opex.accountant.core.model.FinancialActionStatus
4+
import co.nilin.opex.accountant.core.spi.FinancialActionLoader
5+
import co.nilin.opex.accountant.core.spi.FinancialActionPersister
6+
import co.nilin.opex.accountant.core.spi.WalletProxy
7+
import io.mockk.coEvery
8+
import io.mockk.coVerify
9+
import io.mockk.mockk
10+
import kotlinx.coroutines.runBlocking
11+
import org.junit.jupiter.api.Test
12+
13+
class FAJobManagerImplTest {
14+
15+
private val financialActionLoader = mockk<FinancialActionLoader>()
16+
private val financialActionPersister = mockk<FinancialActionPersister>()
17+
private val walletProxy = mockk<WalletProxy>()
18+
19+
private val sut = FinancialActionJobManagerImpl(financialActionLoader, financialActionPersister, walletProxy)
20+
21+
init {
22+
coEvery { financialActionLoader.loadUnprocessed(any(), any()) } returns listOf(Valid.fa, Valid.fa)
23+
coEvery { financialActionPersister.updateStatus(any(), any()) } returns Unit
24+
}
25+
26+
@Test
27+
fun given2FALoaded_whenProcessing_thenVerifyThatTransferProxyCalled2Times() = runBlocking {
28+
coEvery { walletProxy.transfer(any(), any(), any(), any(), any(), any(), any(), any()) } returns Unit
29+
sut.processFinancialActions(0, 2)
30+
with(Valid.fa) {
31+
coVerify(exactly = 2) {
32+
walletProxy.transfer(
33+
eq(symbol),
34+
eq(senderWalletType),
35+
eq(sender),
36+
eq(receiverWalletType),
37+
eq(receiver),
38+
eq(amount),
39+
eq(eventType + pointer),
40+
any()
41+
)
42+
}
43+
coVerify(exactly = 2) {
44+
financialActionPersister.updateStatus(
45+
eq(this@with),
46+
eq(FinancialActionStatus.PROCESSED)
47+
)
48+
}
49+
}
50+
}
51+
52+
@Test
53+
fun given2FALoaded_whenProcessingFailed_thenUpdateStatusCalledRegardless() = runBlocking {
54+
coEvery {
55+
walletProxy.transfer(any(), any(), any(), any(), any(), any(), any(), any())
56+
} throws IllegalStateException()
57+
58+
sut.processFinancialActions(0, 2)
59+
with(Valid.fa) {
60+
coVerify(exactly = 2) {
61+
walletProxy.transfer(
62+
eq(symbol),
63+
eq(senderWalletType),
64+
eq(sender),
65+
eq(receiverWalletType),
66+
eq(receiver),
67+
eq(amount),
68+
eq(eventType + pointer),
69+
any()
70+
)
71+
}
72+
coVerify(exactly = 2) {
73+
financialActionPersister.updateStatus(
74+
eq(this@with),
75+
eq(FinancialActionStatus.CREATED)
76+
)
77+
}
78+
}
79+
}
80+
81+
@Test
82+
fun given2FALoaded_whenProcessingFailedAndRetryCountExceeded_thenUpdateStatusCalledRegardless() = runBlocking {
83+
coEvery {
84+
walletProxy.transfer(any(), any(), any(), any(), any(), any(), any(), any())
85+
} throws IllegalStateException()
86+
87+
coEvery { financialActionLoader.loadUnprocessed(any(), any()) } returns listOf(Valid.faHighRetry)
88+
89+
sut.processFinancialActions(0, 1)
90+
with(Valid.faHighRetry) {
91+
coVerify(exactly = 1) {
92+
walletProxy.transfer(
93+
eq(symbol),
94+
eq(senderWalletType),
95+
eq(sender),
96+
eq(receiverWalletType),
97+
eq(receiver),
98+
eq(amount),
99+
eq(eventType + pointer),
100+
any()
101+
)
102+
}
103+
coVerify(exactly = 1) {
104+
financialActionPersister.updateStatus(
105+
eq(this@with),
106+
eq(FinancialActionStatus.ERROR)
107+
)
108+
}
109+
}
110+
}
111+
112+
}
Lines changed: 72 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,72 @@
1+
package co.nilin.opex.accountant.core.service
2+
3+
import co.nilin.opex.accountant.core.model.FinancialAction
4+
import co.nilin.opex.matching.engine.core.eventh.events.TradeEvent
5+
import kotlinx.coroutines.runBlocking
6+
import org.assertj.core.api.Assertions.assertThat
7+
import org.junit.jupiter.api.Test
8+
import java.time.LocalDateTime
9+
10+
internal class FeeCalculatorImplTest {
11+
12+
private val receiverAddress = "0x0"
13+
private val feeCalculator = FeeCalculatorImpl(receiverAddress)
14+
15+
@Test
16+
fun givenTradeEventsAndOrders_whenFeeCalculated_feeActionsNotNull(): Unit = runBlocking {
17+
val actions =
18+
feeCalculator.createFeeActions(Valid.tradeEvent, Valid.makerOrder, Valid.takerOrder, null, null)
19+
assertThat(actions.makerFeeAction).isNotNull
20+
assertThat(actions.takerFeeAction).isNotNull
21+
}
22+
23+
@Test
24+
fun givenTradeEventsAndOrders_whenFeeCalculated_returnCorrectFees(): Unit = runBlocking {
25+
val actions =
26+
feeCalculator.createFeeActions(Valid.tradeEvent, Valid.makerOrder, Valid.takerOrder, null, null)
27+
with(actions.makerFeeAction) {
28+
assertThat(amount.toDouble()).isEqualTo(0.01) // 1% of 1 BTC
29+
assertThat(symbol).isEqualTo("BTC")
30+
assertThat(sender).isEqualTo("user_1")
31+
assertThat(pointer).isEqualTo("order_2")
32+
assertThat(receiver).isEqualTo(receiverAddress)
33+
assertThat(receiverWalletType).isEqualTo("exchange")
34+
}
35+
36+
with(actions.takerFeeAction) {
37+
assertThat(amount.toDouble()).isEqualTo(500.0) // 1% of 50,000 USDT
38+
assertThat(symbol).isEqualTo("USDT")
39+
assertThat(sender).isEqualTo("user_2")
40+
assertThat(pointer).isEqualTo("order_1")
41+
assertThat(receiver).isEqualTo(receiverAddress)
42+
assertThat(receiverWalletType).isEqualTo("exchange")
43+
}
44+
}
45+
46+
@Test
47+
fun givenTradeEventsAndOrders_whenFAParentNotNull_thenFeeActionParentNotNull(): Unit = runBlocking {
48+
val parentFA = FinancialAction(
49+
null,
50+
TradeEvent::class.java.name,
51+
"trade_id",
52+
"BTC_USDT",
53+
10000.0.toBigDecimal(),
54+
"user_parent",
55+
"main",
56+
"system",
57+
"main",
58+
Valid.currentTime
59+
)
60+
61+
val actions = feeCalculator.createFeeActions(
62+
Valid.tradeEvent,
63+
Valid.makerOrder,
64+
Valid.takerOrder,
65+
parentFA,
66+
parentFA
67+
)
68+
assertThat(actions.makerFeeAction.parent).isNotNull
69+
assertThat(actions.takerFeeAction.parent).isNotNull
70+
}
71+
72+
}

accountant/accountant-core/src/test/kotlin/co/nilin/opex/accountant/core/service/MockitoHelper.kt

Lines changed: 0 additions & 13 deletions
This file was deleted.

0 commit comments

Comments
 (0)