blob: dc14a122b75dbdfbe0128aa92efccd313779d73a [file] [log] [blame]
package kotlinx.coroutines.sync
import kotlinx.coroutines.TestBase
import kotlinx.coroutines.cancelAndJoin
import kotlinx.coroutines.launch
import kotlinx.coroutines.yield
import kotlin.test.Test
import kotlin.test.assertEquals
import kotlin.test.assertFalse
import kotlin.test.assertTrue
class SemaphoreTest : TestBase() {
@Test
fun testSimple() = runTest {
val semaphore = Semaphore(2)
launch {
expect(3)
semaphore.release()
expect(4)
}
expect(1)
semaphore.acquire()
semaphore.acquire()
expect(2)
semaphore.acquire()
finish(5)
}
@Test
fun testSimpleAsMutex() = runTest {
val semaphore = Semaphore(1)
expect(1)
launch {
expect(4)
semaphore.acquire() // suspends
expect(7) // now got lock
semaphore.release()
expect(8)
}
expect(2)
semaphore.acquire() // locked
expect(3)
yield() // yield to child
expect(5)
semaphore.release()
expect(6)
yield() // now child has lock
finish(9)
}
@Test
fun tryAcquireTest() = runTest {
val semaphore = Semaphore(2)
assertTrue(semaphore.tryAcquire())
assertTrue(semaphore.tryAcquire())
assertFalse(semaphore.tryAcquire())
assertEquals(0, semaphore.availablePermits)
semaphore.release()
assertEquals(1, semaphore.availablePermits)
assertTrue(semaphore.tryAcquire())
assertEquals(0, semaphore.availablePermits)
}
@Test
fun withSemaphoreTest() = runTest {
val semaphore = Semaphore(1)
assertEquals(1, semaphore.availablePermits)
semaphore.withPermit {
assertEquals(0, semaphore.availablePermits)
}
assertEquals(1, semaphore.availablePermits)
}
@Test
fun fairnessTest() = runTest {
val semaphore = Semaphore(1)
semaphore.acquire()
launch(coroutineContext) {
// first to acquire
expect(2)
semaphore.acquire() // suspend
expect(6)
}
launch(coroutineContext) {
// second to acquire
expect(3)
semaphore.acquire() // suspend
expect(9)
}
expect(1)
yield()
expect(4)
semaphore.release()
expect(5)
yield()
expect(7)
semaphore.release()
expect(8)
yield()
finish(10)
}
@Test
fun testCancellationReturnsPermitBack() = runTest {
val semaphore = Semaphore(1)
semaphore.acquire()
assertEquals(0, semaphore.availablePermits)
val job = launch {
assertFalse(semaphore.tryAcquire())
semaphore.acquire()
}
yield()
job.cancelAndJoin()
assertEquals(0, semaphore.availablePermits)
semaphore.release()
assertEquals(1, semaphore.availablePermits)
}
@Test
fun testCancellationDoesNotResumeWaitingAcquirers() = runTest {
val semaphore = Semaphore(1)
semaphore.acquire()
val job1 = launch { // 1st job in the waiting queue
expect(2)
semaphore.acquire()
expectUnreached()
}
val job2 = launch { // 2nd job in the waiting queue
expect(3)
semaphore.acquire()
expectUnreached()
}
expect(1)
yield()
expect(4)
job2.cancel()
yield()
expect(5)
job1.cancel()
finish(6)
}
}