Skip to content

Commit

Permalink
Fix test coroutines
Browse files Browse the repository at this point in the history
  • Loading branch information
hujim committed Nov 9, 2022
1 parent 6a7d5b1 commit 2e2eec0
Show file tree
Hide file tree
Showing 6 changed files with 63 additions and 64 deletions.
Original file line number Diff line number Diff line change
@@ -1,19 +1,21 @@
package com.squareup.workflow1

import kotlinx.coroutines.ExperimentalCoroutinesApi
import kotlinx.coroutines.flow.Flow
import kotlinx.coroutines.flow.buffer
import kotlinx.coroutines.flow.conflate
import kotlinx.coroutines.flow.emptyFlow
import kotlinx.coroutines.flow.flowOf
import kotlinx.coroutines.flow.map
import kotlinx.coroutines.flow.toList
import kotlinx.coroutines.runBlocking
import kotlinx.coroutines.test.runTest
import kotlin.test.Test
import kotlin.test.assertEquals
import kotlin.test.assertFalse
import kotlin.test.assertNotSame
import kotlin.test.assertTrue

@ExperimentalCoroutinesApi
@OptIn(ExperimentalStdlibApi::class)
class WorkerTest {

Expand Down Expand Up @@ -62,14 +64,11 @@ class WorkerTest {
assertFalse(transformed1.doesSameWorkAs(transformed2))
}

@Test fun transformed_workers_transform_flows() {
@Test fun transformed_workers_transform_flows() = runTest {
val source = flowOf(1, 2, 3).asWorker()
val transformed = source.transform { flow -> flow.map { it.toString() } }

val transformedValues = runBlocking {
transformed.run()
.toList()
}
val transformedValues = transformed.run().toList()

assertEquals(listOf("1", "2", "3"), transformedValues)
}
Expand Down
Original file line number Diff line number Diff line change
@@ -1,29 +1,29 @@
package com.squareup.workflow1

import kotlinx.coroutines.CoroutineName
import kotlinx.coroutines.ExperimentalCoroutinesApi
import kotlinx.coroutines.flow.Flow
import kotlinx.coroutines.flow.flow
import kotlinx.coroutines.runBlocking
import kotlinx.coroutines.test.runTest
import kotlin.coroutines.coroutineContext
import kotlin.test.Test
import kotlin.test.assertEquals

@ExperimentalCoroutinesApi
class WorkerWorkflowTest {

@Test fun runWorker_coroutine_is_named_without_key() {
@Test fun runWorker_coroutine_is_named_without_key() = runTest {
val worker = CoroutineNameWorker()
runBlocking {
runWorker(worker, renderKey = "", actionSink = NoopSink)
}

runWorker(worker, renderKey = "", actionSink = NoopSink)

assertEquals("CoroutineNameWorker.toString", worker.recordedName)
}

@Test fun runWorker_coroutine_is_named_with_key() {
@Test fun runWorker_coroutine_is_named_with_key() = runTest {
val worker = CoroutineNameWorker()
runBlocking {
runWorker(worker, renderKey = "foo", actionSink = NoopSink)
}

runWorker(worker, renderKey = "foo", actionSink = NoopSink)

assertEquals("CoroutineNameWorker.toString:foo", worker.recordedName)
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,8 +7,9 @@ import com.squareup.workflow1.WorkflowInterceptor.WorkflowSession
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.ExperimentalCoroutinesApi
import kotlinx.coroutines.launch
import kotlinx.coroutines.runBlocking
import kotlinx.coroutines.test.TestScope
import kotlinx.coroutines.test.advanceUntilIdle
import kotlinx.coroutines.test.runTest
import kotlin.coroutines.CoroutineContext
import kotlin.coroutines.CoroutineContext.Key
import kotlin.test.Test
Expand Down Expand Up @@ -122,7 +123,7 @@ internal class WorkflowInterceptorTest {
)
}

@Test fun intercept_intercepts_side_effects() {
@Test fun intercept_intercepts_side_effects() = runTest {
val recorder = RecordingWorkflowInterceptor()
val workflow = TestSideEffectWorkflow()
val intercepted = recorder.intercept(workflow, workflow.session)
Expand All @@ -140,7 +141,8 @@ internal class WorkflowInterceptorTest {
key: String,
sideEffect: suspend CoroutineScope.() -> Unit
) {
runBlocking { sideEffect() }
launch { sideEffect() }
advanceUntilIdle()
}
}

Expand All @@ -157,7 +159,7 @@ internal class WorkflowInterceptorTest {
)
}

@Test fun intercept_uses_interceptors_context_for_side_effect() {
@Test fun intercept_uses_interceptors_context_for_side_effect() = runTest {
val recorder = object : RecordingWorkflowInterceptor() {
override fun <P, S, O, R> onRender(
renderProps: P,
Expand Down Expand Up @@ -200,7 +202,8 @@ internal class WorkflowInterceptorTest {
key: String,
sideEffect: suspend CoroutineScope.() -> Unit
) {
runBlocking { sideEffect() }
launch { sideEffect() }
advanceUntilIdle()
}
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,8 @@ import com.squareup.workflow1.rendering
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.ExperimentalCoroutinesApi
import kotlinx.coroutines.Job
import kotlinx.coroutines.launch
import kotlinx.coroutines.test.advanceUntilIdle
import kotlinx.coroutines.test.runTest
import kotlin.test.Test
import kotlin.test.assertEquals
Expand Down Expand Up @@ -55,7 +57,7 @@ internal class ChainedWorkflowInterceptorTest {

@OptIn(ExperimentalCoroutinesApi::class)
@Test
fun chains_calls_to_onInstanceStarted_in_left_to_right_order() {
fun chains_calls_to_onInstanceStarted_in_left_to_right_order() = runTest {
val events = mutableListOf<String>()
val interceptor1 = object : WorkflowInterceptor {
override fun onSessionStarted(
Expand All @@ -81,9 +83,10 @@ internal class ChainedWorkflowInterceptorTest {
}
val chained = listOf(interceptor1, interceptor2).chained()

runTest {
launch {
chained.onSessionStarted(this, TestSession)
}
advanceUntilIdle()

assertEquals(listOf("started1", "started2", "cancelled1", "cancelled2"), events)
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -13,9 +13,10 @@ import com.squareup.workflow1.applyTo
import com.squareup.workflow1.identifier
import com.squareup.workflow1.internal.SubtreeManagerTest.TestWorkflow.Rendering
import kotlinx.coroutines.Dispatchers.Unconfined
import kotlinx.coroutines.ExperimentalCoroutinesApi
import kotlinx.coroutines.async
import kotlinx.coroutines.runBlocking
import kotlinx.coroutines.selects.select
import kotlinx.coroutines.test.runTest
import kotlin.test.Test
import kotlin.test.assertEquals
import kotlin.test.assertFailsWith
Expand All @@ -24,6 +25,7 @@ import kotlin.test.fail

private typealias StringHandler = (String) -> WorkflowAction<String, String, String>

@ExperimentalCoroutinesApi
internal class SubtreeManagerTest {

private class TestWorkflow : StatefulWorkflow<String, String, String, Rendering>() {
Expand Down Expand Up @@ -154,7 +156,7 @@ internal class SubtreeManagerTest {
assertEquals("initialState:props", composeState)
}

@Test fun tick_children_handles_child_output() {
@Test fun tick_children_handles_child_output() = runTest {
val manager = subtreeManagerForTest<String, String, String>()
val workflow = TestWorkflow()
val handler: StringHandler = { output ->
Expand All @@ -166,44 +168,40 @@ internal class SubtreeManagerTest {
val (_, _, eventHandler) = manager.render(workflow, "props", key = "", handler = handler)
manager.commitRenderedChildren()

runBlocking {
val tickOutput = async { manager.tickAction() }
assertFalse(tickOutput.isCompleted)
val tickOutput = async { manager.tickAction() }
assertFalse(tickOutput.isCompleted)

eventHandler("event!")
val update = tickOutput.await().value!!
eventHandler("event!")
val update = tickOutput.await().value!!

val (_, output) = update.applyTo("props", "state")
assertEquals("case output:workflow output:event!", output?.value)
}
val (_, output) = update.applyTo("props", "state")
assertEquals("case output:workflow output:event!", output?.value)
}

@Test fun render_updates_childs_output_handler() {
@Test fun render_updates_childs_output_handler() = runTest {
val manager = subtreeManagerForTest<String, String, String>()
val workflow = TestWorkflow()
fun render(handler: StringHandler) =
manager.render(workflow, "props", key = "", handler = handler)
.also { manager.commitRenderedChildren() }

runBlocking {
// First render + tick pass – uninteresting.
render { action { setOutput("initial handler: $it") } }
.let { rendering ->
rendering.eventHandler("initial output")
val initialAction = manager.tickAction().value
val (_, initialOutput) = initialAction!!.applyTo("", "")
assertEquals("initial handler: workflow output:initial output", initialOutput?.value)
}

// Do a second render + tick, but with a different handler function.
render { action { setOutput("second handler: $it") } }
.let { rendering ->
rendering.eventHandler("second output")
val secondAction = manager.tickAction().value
val (_, secondOutput) = secondAction!!.applyTo("", "")
assertEquals("second handler: workflow output:second output", secondOutput?.value)
}
}
// First render + tick pass – uninteresting.
render { action { setOutput("initial handler: $it") } }
.let { rendering ->
rendering.eventHandler("initial output")
val initialAction = manager.tickAction().value
val (_, initialOutput) = initialAction!!.applyTo("", "")
assertEquals("initial handler: workflow output:initial output", initialOutput?.value)
}

// Do a second render + tick, but with a different handler function.
render { action { setOutput("second handler: $it") } }
.let { rendering ->
rendering.eventHandler("second output")
val secondAction = manager.tickAction().value
val (_, secondOutput) = secondAction!!.applyTo("", "")
assertEquals("second handler: workflow output:second output", secondOutput?.value)
}
}

// See https://github.com/square/workflow/issues/404
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -1118,7 +1118,7 @@ internal class WorkflowNodeTest {
)
}

@Test fun actionSink_action_changes_state() {
@Test fun actionSink_action_changes_state() = runTest {
val workflow = Workflow.stateful<Unit, String, Nothing, Pair<String, Sink<String>>>(
initialState = { "initial" },
render = { _, renderState ->
Expand All @@ -1138,11 +1138,9 @@ internal class WorkflowNodeTest {

sink.send("hello")

runTest {
select<ActionProcessingResult?> {
node.tick(this)
} as WorkflowOutput<String>?
}
select<ActionProcessingResult?> {
node.tick(this)
} as WorkflowOutput<String>?

val (state, _) = node.render(workflow.asStatefulWorkflow(), Unit)
assertEquals("initial->hello", state)
Expand Down Expand Up @@ -1196,7 +1194,7 @@ internal class WorkflowNodeTest {
}
}

@Test fun child_action_changes_state() {
@Test fun child_action_changes_state() = runTest {
val workflow = Workflow.stateful<Unit, String, Nothing, String>(
initialState = { "initial" },
render = { _, renderState ->
Expand All @@ -1215,11 +1213,9 @@ internal class WorkflowNodeTest {
)
node.render(workflow.asStatefulWorkflow(), Unit)

runTest {
select<ActionProcessingResult?> {
node.tick(this)
} as WorkflowOutput<String>?
}
select<ActionProcessingResult?> {
node.tick(this)
} as WorkflowOutput<String>?

val state = node.render(workflow.asStatefulWorkflow(), Unit)
assertEquals("initial->hello", state)
Expand Down

0 comments on commit 2e2eec0

Please sign in to comment.