@@ -8,11 +8,13 @@ import com.getcode.opencode.model.accounts.AccountType
88import com.getcode.opencode.model.financial.Fiat
99import com.getcode.solana.keys.Mint
1010import com.getcode.solana.keys.PublicKey
11+ import com.flipcash.app.core.dispatchers.TestDispatchers
1112import io.mockk.coEvery
1213import io.mockk.coVerify
1314import io.mockk.every
1415import io.mockk.mockk
1516import kotlinx.coroutines.ExperimentalCoroutinesApi
17+ import kotlinx.coroutines.test.TestCoroutineScheduler
1618import kotlinx.coroutines.test.advanceUntilIdle
1719import kotlinx.coroutines.test.runTest
1820import org.junit.After
@@ -30,6 +32,8 @@ class UsdcDepositSweepTest {
3032
3133 private val owner: AccountCluster = mockk(relaxed = true )
3234
35+ private val testDispatchers = TestDispatchers (TestCoroutineScheduler ())
36+
3337 private lateinit var sweep: UsdcDepositSweep
3438
3539 @Before
@@ -43,6 +47,7 @@ class UsdcDepositSweepTest {
4347 accountController = accountController,
4448 tokenCoordinator = tokenCoordinator,
4549 balancePoller = balancePoller,
50+ dispatchers = testDispatchers,
4651 maxRetries = 3 ,
4752 initialDelay = 10 .milliseconds,
4853 backoffFactor = 1.0 ,
@@ -74,46 +79,43 @@ class UsdcDepositSweepTest {
7479 }
7580
7681 @Test
77- fun `gives up after max retries when USDC account is not found` () = runTest {
82+ fun `gives up after max retries when USDC account is not found` () = runTest(testDispatchers.dispatcher) {
7883 stubNoUsdcAccount()
7984
8085 sweep.execute(owner)
8186 advanceUntilIdle()
82- Thread .sleep(200 )
8387
8488 coVerify(exactly = 0 ) {
8589 transactionOperations.swapUsdc(any(), any())
8690 }
8791 }
8892
8993 @Test
90- fun `gives up after max retries when account type is not AssociatedToken` () = runTest {
94+ fun `gives up after max retries when account type is not AssociatedToken` () = runTest(testDispatchers.dispatcher) {
9195 stubUsdcAccount(balance = 1_000_000L , type = AccountType .Primary )
9296
9397 sweep.execute(owner)
9498 advanceUntilIdle()
95- Thread .sleep(200 )
9699
97100 coVerify(exactly = 0 ) {
98101 transactionOperations.swapUsdc(any(), any())
99102 }
100103 }
101104
102105 @Test
103- fun `gives up after max retries when USDC balance stays zero` () = runTest {
106+ fun `gives up after max retries when USDC balance stays zero` () = runTest(testDispatchers.dispatcher) {
104107 stubUsdcAccount(balance = 0L )
105108
106109 sweep.execute(owner)
107110 advanceUntilIdle()
108- Thread .sleep(200 )
109111
110112 coVerify(exactly = 0 ) {
111113 transactionOperations.swapUsdc(any(), any())
112114 }
113115 }
114116
115117 @Test
116- fun `retries until balance appears then sweeps` () = runTest {
118+ fun `retries until balance appears then sweeps` () = runTest(testDispatchers.dispatcher) {
117119 var callCount = 0
118120 coEvery {
119121 accountController.getAccount(any(), any(), any())
@@ -131,36 +133,33 @@ class UsdcDepositSweepTest {
131133
132134 sweep.execute(owner)
133135 advanceUntilIdle()
134- Thread .sleep(300 )
135136
136137 coVerify {
137138 transactionOperations.swapUsdc(owner, 2_000_000L )
138139 }
139140 }
140141
141142 @Test
142- fun `calls swapUsdc with correct amount when balance is positive` () = runTest {
143+ fun `calls swapUsdc with correct amount when balance is positive` () = runTest(testDispatchers.dispatcher) {
143144 val amount = 5_000_000L
144145 stubUsdcAccount(balance = amount)
145146 coEvery { transactionOperations.swapUsdc(any(), any()) } returns Result .success(Unit )
146147
147148 sweep.execute(owner)
148149 advanceUntilIdle()
149- Thread .sleep(200 )
150150
151151 coVerify {
152152 transactionOperations.swapUsdc(owner, amount)
153153 }
154154 }
155155
156156 @Test
157- fun `polls for USDF balance on successful swap` () = runTest {
157+ fun `polls for USDF balance on successful swap` () = runTest(testDispatchers.dispatcher) {
158158 stubUsdcAccount(balance = 1_000_000L )
159159 coEvery { transactionOperations.swapUsdc(any(), any()) } returns Result .success(Unit )
160160
161161 sweep.execute(owner)
162162 advanceUntilIdle()
163- Thread .sleep(200 )
164163
165164 coVerify {
166165 balancePoller.awaitBalanceChange(
@@ -174,23 +173,22 @@ class UsdcDepositSweepTest {
174173 }
175174
176175 @Test
177- fun `does not poll for USDF balance when swap fails` () = runTest {
176+ fun `does not poll for USDF balance when swap fails` () = runTest(testDispatchers.dispatcher) {
178177 stubUsdcAccount(balance = 1_000_000L )
179178 coEvery {
180179 transactionOperations.swapUsdc(any(), any())
181180 } returns Result .failure(RuntimeException (" swap failed" ))
182181
183182 sweep.execute(owner)
184183 advanceUntilIdle()
185- Thread .sleep(200 )
186184
187185 coVerify(exactly = 0 ) {
188186 balancePoller.awaitBalanceChange(any(), any(), any(), any(), any())
189187 }
190188 }
191189
192190 @Test
193- fun `completes gracefully when USDF balance poll times out` () = runTest {
191+ fun `completes gracefully when USDF balance poll times out` () = runTest(testDispatchers.dispatcher) {
194192 stubUsdcAccount(balance = 1_000_000L )
195193 coEvery { transactionOperations.swapUsdc(any(), any()) } returns Result .success(Unit )
196194 coEvery {
@@ -199,15 +197,14 @@ class UsdcDepositSweepTest {
199197
200198 sweep.execute(owner)
201199 advanceUntilIdle()
202- Thread .sleep(200 )
203200
204201 coVerify {
205202 balancePoller.awaitBalanceChange(any(), any(), any(), any(), any())
206203 }
207204 }
208205
209206 @Test
210- fun `does not execute concurrently when job is active` () = runTest {
207+ fun `does not execute concurrently when job is active` () = runTest(testDispatchers.dispatcher) {
211208 stubUsdcAccount(balance = 1_000_000L )
212209 coEvery { transactionOperations.swapUsdc(any(), any()) } coAnswers {
213210 kotlinx.coroutines.delay(500 )
@@ -216,16 +213,15 @@ class UsdcDepositSweepTest {
216213
217214 sweep.execute(owner)
218215 sweep.execute(owner)
219-
220- Thread .sleep(700 )
216+ advanceUntilIdle()
221217
222218 coVerify(exactly = 1 ) {
223219 transactionOperations.swapUsdc(any(), any())
224220 }
225221 }
226222
227223 @Test
228- fun `cancel stops active job` () = runTest {
224+ fun `cancel stops active job` () = runTest(testDispatchers.dispatcher) {
229225 coEvery {
230226 accountController.getAccount(any(), any(), any())
231227 } coAnswers {
@@ -240,9 +236,8 @@ class UsdcDepositSweepTest {
240236 coEvery { transactionOperations.swapUsdc(any(), any()) } returns Result .success(Unit )
241237
242238 sweep.execute(owner)
243- Thread .sleep(50 )
244239 sweep.cancel()
245- Thread .sleep( 100 )
240+ advanceUntilIdle( )
246241
247242 coVerify(exactly = 0 ) {
248243 transactionOperations.swapUsdc(any(), any())
0 commit comments