resolve flaky jvm multi threaded coroutine tests
By switching to using the jvm only (hopefully by 1.6 in common) coroutine test lib we can swap to using a fake dispatcher instead of defining threads which should resolve any odd timing issues.
This commit is contained in:
parent
08cf52bfd4
commit
07b4d61d3f
@ -3,6 +3,7 @@ object Versions {
|
|||||||
const val kotlin = "1.5.10"
|
const val kotlin = "1.5.10"
|
||||||
const val kotlinBenchmark = "0.2.0-dev-20"
|
const val kotlinBenchmark = "0.2.0-dev-20"
|
||||||
const val kotlinCoroutines = "1.5.0"
|
const val kotlinCoroutines = "1.5.0"
|
||||||
|
const val kotlinCoroutinesTest = "1.5.0"
|
||||||
const val ktor = "1.5.4"
|
const val ktor = "1.5.4"
|
||||||
const val logback = "1.2.3"
|
const val logback = "1.2.3"
|
||||||
const val versionsPlugin = "0.38.0"
|
const val versionsPlugin = "0.38.0"
|
||||||
|
@ -31,6 +31,7 @@ kotlin {
|
|||||||
dependencies {
|
dependencies {
|
||||||
implementation(kotlin("test-junit"))
|
implementation(kotlin("test-junit"))
|
||||||
implementation(kotlin("test"))
|
implementation(kotlin("test"))
|
||||||
|
implementation("org.jetbrains.kotlinx:kotlinx-coroutines-test:${Versions.kotlinCoroutinesTest}")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -3,19 +3,19 @@ package com.github.michaelbull.result.coroutines.binding
|
|||||||
import com.github.michaelbull.result.Err
|
import com.github.michaelbull.result.Err
|
||||||
import com.github.michaelbull.result.Ok
|
import com.github.michaelbull.result.Ok
|
||||||
import com.github.michaelbull.result.Result
|
import com.github.michaelbull.result.Result
|
||||||
import kotlinx.coroutines.CoroutineName
|
import kotlinx.coroutines.ExperimentalCoroutinesApi
|
||||||
import kotlinx.coroutines.asCoroutineDispatcher
|
|
||||||
import kotlinx.coroutines.async
|
import kotlinx.coroutines.async
|
||||||
import kotlinx.coroutines.delay
|
|
||||||
import kotlinx.coroutines.launch
|
import kotlinx.coroutines.launch
|
||||||
|
import kotlinx.coroutines.delay
|
||||||
import kotlinx.coroutines.runBlocking
|
import kotlinx.coroutines.runBlocking
|
||||||
import java.util.concurrent.Executors
|
import kotlinx.coroutines.test.TestCoroutineDispatcher
|
||||||
import kotlin.coroutines.CoroutineContext
|
import kotlinx.coroutines.test.runBlockingTest
|
||||||
import kotlin.test.Test
|
import kotlin.test.Test
|
||||||
import kotlin.test.assertEquals
|
import kotlin.test.assertEquals
|
||||||
import kotlin.test.assertFalse
|
import kotlin.test.assertFalse
|
||||||
import kotlin.test.assertTrue
|
import kotlin.test.assertTrue
|
||||||
|
|
||||||
|
@ExperimentalCoroutinesApi
|
||||||
class AsyncSuspendableBindingTest {
|
class AsyncSuspendableBindingTest {
|
||||||
|
|
||||||
private sealed class BindingError {
|
private sealed class BindingError {
|
||||||
@ -35,7 +35,7 @@ class AsyncSuspendableBindingTest {
|
|||||||
return Ok(2)
|
return Ok(2)
|
||||||
}
|
}
|
||||||
|
|
||||||
runBlocking {
|
runBlockingTest {
|
||||||
val result = binding<Int, BindingError> {
|
val result = binding<Int, BindingError> {
|
||||||
val x = async { provideX().bind() }
|
val x = async { provideX().bind() }
|
||||||
val y = async { provideY().bind() }
|
val y = async { provideY().bind() }
|
||||||
@ -67,7 +67,7 @@ class AsyncSuspendableBindingTest {
|
|||||||
return Err(BindingError.BindingErrorB)
|
return Err(BindingError.BindingErrorB)
|
||||||
}
|
}
|
||||||
|
|
||||||
runBlocking {
|
runBlockingTest {
|
||||||
val result = binding<Int, BindingError> {
|
val result = binding<Int, BindingError> {
|
||||||
val x = async { provideX().bind() }
|
val x = async { provideX().bind() }
|
||||||
val y = async { provideY().bind() }
|
val y = async { provideY().bind() }
|
||||||
@ -95,18 +95,19 @@ class AsyncSuspendableBindingTest {
|
|||||||
}
|
}
|
||||||
|
|
||||||
suspend fun provideY(): Result<Int, BindingError.BindingErrorB> {
|
suspend fun provideY(): Result<Int, BindingError.BindingErrorB> {
|
||||||
// as this test uses a new thread for each coroutine, we want to set this delay to a high enough number that
|
delay(3)
|
||||||
// there isn't any chance of a jvm run actually completing this suspending function in this thread first
|
|
||||||
// otherwise the assertions might fail.
|
|
||||||
delay(100)
|
|
||||||
yStateChange = true
|
yStateChange = true
|
||||||
return Err(BindingError.BindingErrorB)
|
return Err(BindingError.BindingErrorB)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
val dispatcherA = TestCoroutineDispatcher()
|
||||||
|
val dispatcherB = TestCoroutineDispatcher()
|
||||||
|
|
||||||
runBlocking {
|
runBlocking {
|
||||||
val result = binding<Int, BindingError> {
|
val result = binding<Int, BindingError> {
|
||||||
val x = async(newThread("ThreadA")) { provideX().bind() }
|
val x = async(dispatcherA) { provideX().bind() }
|
||||||
val y = async(newThread("ThreadB")) { provideY().bind() }
|
val y = async(dispatcherB) { provideY().bind() }
|
||||||
|
dispatcherA.advanceTimeBy(2)
|
||||||
x.await() + y.await()
|
x.await() + y.await()
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -144,11 +145,17 @@ class AsyncSuspendableBindingTest {
|
|||||||
return Err(BindingError.BindingErrorB)
|
return Err(BindingError.BindingErrorB)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
val dispatcherA = TestCoroutineDispatcher()
|
||||||
|
val dispatcherB = TestCoroutineDispatcher()
|
||||||
|
val dispatcherC = TestCoroutineDispatcher()
|
||||||
|
|
||||||
runBlocking {
|
runBlocking {
|
||||||
val result = binding<Unit, BindingError> {
|
val result = binding<Unit, BindingError> {
|
||||||
launch(newThread("Thread A")) { provideX().bind() }
|
launch(dispatcherA) { provideX().bind() }
|
||||||
launch(newThread("Thread B")) { provideY().bind() }
|
dispatcherA.advanceTimeBy(20)
|
||||||
launch(newThread("Thread C")) { provideZ().bind() }
|
launch(dispatcherB) { provideY().bind() }
|
||||||
|
dispatcherB.advanceTimeBy(20)
|
||||||
|
launch(dispatcherC) { provideZ().bind() }
|
||||||
}
|
}
|
||||||
|
|
||||||
assertTrue(result is Err)
|
assertTrue(result is Err)
|
||||||
@ -161,8 +168,4 @@ class AsyncSuspendableBindingTest {
|
|||||||
assertFalse(zStateChange)
|
assertFalse(zStateChange)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun newThread(name: String): CoroutineContext {
|
|
||||||
return Executors.newSingleThreadExecutor().asCoroutineDispatcher() + CoroutineName(name)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user