@@ -7,11 +7,14 @@ import io.mockk.mockk
7
7
import io.mockk.mockkObject
8
8
import io.mockk.unmockkAll
9
9
import kotlinx.coroutines.Dispatchers
10
+ import kotlinx.coroutines.Job
10
11
import kotlinx.coroutines.delay
11
12
import kotlinx.coroutines.launch
12
13
import kotlinx.coroutines.runBlocking
13
14
import org.junit.After
14
- import org.junit.Assert.*
15
+ import org.junit.Assert.assertEquals
16
+ import org.junit.Assert.assertFalse
17
+ import org.junit.Assert.assertTrue
15
18
import org.junit.Before
16
19
import org.junit.Test
17
20
import java.security.cert.X509Certificate
@@ -53,6 +56,40 @@ class UserDecisionRegistryTest {
53
56
})
54
57
}
55
58
59
+ @Test
60
+ fun testCheck_MultipleDecisionsForSameCert_allCancelled () {
61
+ val canSendFeedback = Semaphore (0 )
62
+ val getUserDecision: suspend (X509Certificate ) -> Boolean = mockk {
63
+ coEvery { this @mockk(testCert) } coAnswers {
64
+ canSendFeedback.acquire() // block call until released
65
+ true
66
+ }
67
+ }
68
+ val results = Collections .synchronizedList(mutableListOf<Boolean >())
69
+ val jobs = mutableListOf<Job >()
70
+ runBlocking(Dispatchers .Default ) {
71
+ // launch 5 getUserDecision calls (each will be blocked by the semaphore)
72
+ repeat(5 ) {
73
+ jobs + = launch {
74
+ results + = registry.check(testCert, this , getUserDecision)
75
+ }
76
+ }
77
+ delay(1000 ) // wait a bit for all getUserDecision calls to be launched and blocked
78
+
79
+ // Cancel all jobs
80
+ jobs.forEach { it.cancel() }
81
+
82
+ canSendFeedback.release() // now unblock
83
+ }
84
+
85
+ // pendingDecisions should be empty
86
+ synchronized(registry.pendingDecisions) {
87
+ assertFalse(registry.pendingDecisions.containsKey(testCert))
88
+ }
89
+ assertEquals(0 , results.size) // should be 0 results
90
+ coVerify(exactly = 1 ) { getUserDecision(testCert) } // getUserDecision should be called only once
91
+ }
92
+
56
93
@Test
57
94
fun testCheck_MultipleDecisionsForSameCert_Negative () {
58
95
val canSendFeedback = Semaphore (0 )
0 commit comments