From 18312f191a97a516e27decf1379025a6246515ca Mon Sep 17 00:00:00 2001 From: Stephen Edwards Date: Fri, 6 Dec 2024 10:51:00 -0500 Subject: [PATCH] Add Tests for WorkflowTracer --- .../com/squareup/workflow1/WorkerWorkflow.kt | 2 +- .../workflow1/internal/SubtreeManager.kt | 4 +- .../workflow1/internal/WorkflowChildNode.kt | 7 +- .../workflow1/RenderWorkflowInTest.kt | 233 +++++++++++++----- 4 files changed, 177 insertions(+), 69 deletions(-) diff --git a/workflow-core/src/commonMain/kotlin/com/squareup/workflow1/WorkerWorkflow.kt b/workflow-core/src/commonMain/kotlin/com/squareup/workflow1/WorkerWorkflow.kt index 64c6a33e3..dedfa5902 100644 --- a/workflow-core/src/commonMain/kotlin/com/squareup/workflow1/WorkerWorkflow.kt +++ b/workflow-core/src/commonMain/kotlin/com/squareup/workflow1/WorkerWorkflow.kt @@ -36,7 +36,7 @@ internal class WorkerWorkflow( ImpostorWorkflow { override val realIdentifier: WorkflowIdentifier = - workflowTracer.trace("ComputeRealIdentifier" ) { + workflowTracer.trace("ComputeRealIdentifier") { unsnapshottableIdentifier(workerType) } diff --git a/workflow-runtime/src/commonMain/kotlin/com/squareup/workflow1/internal/SubtreeManager.kt b/workflow-runtime/src/commonMain/kotlin/com/squareup/workflow1/internal/SubtreeManager.kt index f5e6fe45f..7ec3bd6ec 100644 --- a/workflow-runtime/src/commonMain/kotlin/com/squareup/workflow1/internal/SubtreeManager.kt +++ b/workflow-runtime/src/commonMain/kotlin/com/squareup/workflow1/internal/SubtreeManager.kt @@ -126,7 +126,7 @@ internal class SubtreeManager( // Prevent duplicate workflows with the same key. workflowTracer.trace("CheckingUniqueMatches") { children.forEachStaging { - require(!(it.matches(child, key))) { + require(!(it.matches(child, key, workflowTracer))) { "Expected keys to be unique for ${child.identifier}: key=\"$key\"" } } @@ -136,7 +136,7 @@ internal class SubtreeManager( val stagedChild = workflowTracer.trace("RetainingChildren") { children.retainOrCreate( - predicate = { it.matches(child, key) }, + predicate = { it.matches(child, key, workflowTracer) }, create = { createChildNode(child, props, key, handler) } ) } diff --git a/workflow-runtime/src/commonMain/kotlin/com/squareup/workflow1/internal/WorkflowChildNode.kt b/workflow-runtime/src/commonMain/kotlin/com/squareup/workflow1/internal/WorkflowChildNode.kt index b6a833a95..4f5d357fe 100644 --- a/workflow-runtime/src/commonMain/kotlin/com/squareup/workflow1/internal/WorkflowChildNode.kt +++ b/workflow-runtime/src/commonMain/kotlin/com/squareup/workflow1/internal/WorkflowChildNode.kt @@ -3,7 +3,9 @@ package com.squareup.workflow1.internal import com.squareup.workflow1.StatefulWorkflow import com.squareup.workflow1.Workflow import com.squareup.workflow1.WorkflowAction +import com.squareup.workflow1.WorkflowTracer import com.squareup.workflow1.internal.InlineLinkedList.InlineListNode +import com.squareup.workflow1.trace /** * Representation of a child workflow that has been rendered by another workflow. @@ -32,8 +34,9 @@ internal class WorkflowChildNode< */ fun matches( otherWorkflow: Workflow<*, *, *>, - key: String - ): Boolean = id.matches(otherWorkflow, key) + key: String, + workflowTracer: WorkflowTracer? + ): Boolean = workflowTracer.trace("matches") { id.matches(otherWorkflow, key) } /** * Updates the handler function that will be invoked by [acceptChildOutput]. diff --git a/workflow-runtime/src/commonTest/kotlin/com/squareup/workflow1/RenderWorkflowInTest.kt b/workflow-runtime/src/commonTest/kotlin/com/squareup/workflow1/RenderWorkflowInTest.kt index 73fdf7116..5d770e6a3 100644 --- a/workflow-runtime/src/commonTest/kotlin/com/squareup/workflow1/RenderWorkflowInTest.kt +++ b/workflow-runtime/src/commonTest/kotlin/com/squareup/workflow1/RenderWorkflowInTest.kt @@ -28,6 +28,8 @@ import kotlinx.coroutines.test.advanceUntilIdle import kotlinx.coroutines.test.runCurrent import okio.ByteString import kotlin.test.Test +import kotlin.test.assertEquals +import kotlin.test.assertTrue @OptIn(ExperimentalCoroutinesApi::class, FlowPreview::class, WorkflowExperimentalRuntime::class) class RenderWorkflowInTest { @@ -42,16 +44,35 @@ class RenderWorkflowInTest { */ private lateinit var testScope: TestScope - private val runtimeOptions: Sequence = arrayOf( - RuntimeConfigOptions.RENDER_PER_ACTION, - setOf(RENDER_ONLY_WHEN_STATE_CHANGES), - setOf(CONFLATE_STALE_RENDERINGS), - setOf(CONFLATE_STALE_RENDERINGS, RENDER_ONLY_WHEN_STATE_CHANGES) + private val traces: StringBuilder = StringBuilder() + private val testTracer: WorkflowTracer = object : WorkflowTracer { + var prefix: String = "" + override fun beginSection(label: String) { + traces.appendLine("${prefix}Starting$label") + prefix += " " + } + + override fun endSection() { + prefix = prefix.substring(0, prefix.length - 2) + traces.appendLine("${prefix}Ending") + } + } + + private val runtimeOptions: Sequence> = arrayOf( + RuntimeConfigOptions.RENDER_PER_ACTION to null, + RuntimeConfigOptions.RENDER_PER_ACTION to testTracer, + setOf(RENDER_ONLY_WHEN_STATE_CHANGES) to null, + setOf(RENDER_ONLY_WHEN_STATE_CHANGES) to testTracer, + setOf(CONFLATE_STALE_RENDERINGS) to null, + setOf(CONFLATE_STALE_RENDERINGS) to testTracer, + setOf(CONFLATE_STALE_RENDERINGS, RENDER_ONLY_WHEN_STATE_CHANGES) to null, + setOf(CONFLATE_STALE_RENDERINGS, RENDER_ONLY_WHEN_STATE_CHANGES) to testTracer, ).asSequence() - private val runtimeTestRunner = ParameterizedTestRunner() + private val runtimeTestRunner = ParameterizedTestRunner>() private fun setup() { + traces.clear() pausedTestScope = TestScope() testScope = TestScope(UnconfinedTestDispatcher()) } @@ -60,7 +81,7 @@ class RenderWorkflowInTest { runtimeTestRunner.runParametrizedTest( paramSource = runtimeOptions, before = ::setup, - ) { runtimeConfig: RuntimeConfig -> + ) { (runtimeConfig: RuntimeConfig, workflowTracer: WorkflowTracer?) -> val props = MutableStateFlow("foo") val workflow = Workflow.stateless { "props: $it" } // Don't allow the workflow runtime to actually start. @@ -70,7 +91,7 @@ class RenderWorkflowInTest { scope = pausedTestScope, props = props, runtimeConfig = runtimeConfig, - workflowTracer = null, + workflowTracer = workflowTracer, ) {} assertEquals("props: foo", renderings.value.rendering) } @@ -80,7 +101,7 @@ class RenderWorkflowInTest { runtimeTestRunner.runParametrizedTest( paramSource = runtimeOptions, before = ::setup, - ) { runtimeConfig: RuntimeConfig -> + ) { (runtimeConfig: RuntimeConfig, workflowTracer: WorkflowTracer?) -> val props = MutableStateFlow("foo") val workflow = Workflow.stateless { "props: $it" } @@ -90,7 +111,7 @@ class RenderWorkflowInTest { scope = pausedTestScope, props = props, runtimeConfig = runtimeConfig, - workflowTracer = null, + workflowTracer = workflowTracer, ) {} assertEquals("props: foo", renderings.value.rendering) } @@ -101,7 +122,7 @@ class RenderWorkflowInTest { runtimeTestRunner.runParametrizedTest( paramSource = runtimeOptions, before = ::setup, - ) { runtimeConfig: RuntimeConfig -> + ) { (runtimeConfig: RuntimeConfig, workflowTracer: WorkflowTracer?) -> var sideEffectWasRan = false val workflow = Workflow.stateless { runningSideEffect("test") { @@ -115,7 +136,7 @@ class RenderWorkflowInTest { testScope, MutableStateFlow(Unit), runtimeConfig = runtimeConfig, - workflowTracer = null, + workflowTracer = workflowTracer, ) {} testScope.advanceUntilIdle() @@ -128,7 +149,7 @@ class RenderWorkflowInTest { runtimeTestRunner.runParametrizedTest( paramSource = runtimeOptions, before = ::setup, - ) { runtimeConfig: RuntimeConfig -> + ) { (runtimeConfig: RuntimeConfig, workflowTracer: WorkflowTracer?) -> var sideEffectWasRan = false val childWorkflow = Workflow.stateless { runningSideEffect("test") { @@ -145,7 +166,7 @@ class RenderWorkflowInTest { scope = testScope, props = MutableStateFlow(Unit), runtimeConfig = runtimeConfig, - workflowTracer = null, + workflowTracer = workflowTracer, ) {} testScope.advanceUntilIdle() @@ -157,7 +178,7 @@ class RenderWorkflowInTest { runtimeTestRunner.runParametrizedTest( paramSource = runtimeOptions, before = ::setup, - ) { runtimeConfig: RuntimeConfig -> + ) { (runtimeConfig: RuntimeConfig, workflowTracer: WorkflowTracer?) -> val props = MutableStateFlow("foo") val workflow = Workflow.stateless { "props: $it" } val renderings = renderWorkflowIn( @@ -165,7 +186,7 @@ class RenderWorkflowInTest { scope = testScope, props = props, runtimeConfig = runtimeConfig, - workflowTracer = null, + workflowTracer = workflowTracer, ) {} assertEquals("props: foo", renderings.value.rendering) @@ -287,7 +308,7 @@ class RenderWorkflowInTest { runtimeTestRunner.runParametrizedTest( paramSource = runtimeOptions, before = ::setup, - ) { runtimeConfig: RuntimeConfig -> + ) { (runtimeConfig: RuntimeConfig, workflowTracer: WorkflowTracer?) -> lateinit var sink: Sink var snapped = false @@ -310,7 +331,7 @@ class RenderWorkflowInTest { scope = testScope, props = props, runtimeConfig = runtimeConfig, - workflowTracer = null, + workflowTracer = workflowTracer, ) {} val emitted = mutableListOf>() @@ -355,7 +376,7 @@ class RenderWorkflowInTest { runtimeTestRunner.runParametrizedTest( paramSource = runtimeOptions, before = ::setup, - ) { runtimeConfig: RuntimeConfig -> + ) { (runtimeConfig: RuntimeConfig, workflowTracer: WorkflowTracer?) -> val trigger = Channel() val workflow = Workflow.stateless { runningWorker( @@ -369,7 +390,7 @@ class RenderWorkflowInTest { scope = testScope, props = MutableStateFlow(Unit), runtimeConfig = runtimeConfig, - workflowTracer = null, + workflowTracer = workflowTracer, ) { receivedOutputs += it } @@ -387,7 +408,7 @@ class RenderWorkflowInTest { runtimeTestRunner.runParametrizedTest( paramSource = runtimeOptions, before = ::setup, - ) { runtimeConfig: RuntimeConfig -> + ) { (runtimeConfig: RuntimeConfig, workflowTracer: WorkflowTracer?) -> val trigger = Channel() val workflow = Workflow.stateful( initialState = "initial", @@ -412,7 +433,7 @@ class RenderWorkflowInTest { scope = testScope, props = MutableStateFlow(Unit), runtimeConfig = runtimeConfig, - workflowTracer = null, + workflowTracer = workflowTracer, ) { it: String -> receivedOutputs += it assertTrue(emittedRenderings.contains(it)) @@ -434,11 +455,62 @@ class RenderWorkflowInTest { } } + @Test fun tracer_includes_expected_sections() { + val runtimeConfig = RuntimeConfigOptions.DEFAULT_CONFIG + val workflowTracer = testTracer + setup() + val trigger = Channel() + val workflow = Workflow.stateful( + initialState = "initial", + render = { renderState -> + runningWorker( + trigger.consumeAsFlow() + .asWorker() + ) { + action("") { + state = it + setOutput(it) + } + } + renderState + } + ) + + val emittedRenderings = mutableListOf() + val receivedOutputs = mutableListOf() + val renderings = renderWorkflowIn( + workflow = workflow, + scope = testScope, + props = MutableStateFlow(Unit), + runtimeConfig = runtimeConfig, + workflowTracer = workflowTracer, + ) { it: String -> + receivedOutputs += it + assertTrue(emittedRenderings.contains(it)) + } + assertTrue(receivedOutputs.isEmpty()) + + val scope = CoroutineScope(Unconfined) + scope.launch { + renderings.collect { rendering: RenderingAndSnapshot -> + emittedRenderings += rendering.rendering + } + } + + trigger.trySend("foo").isSuccess + + trigger.trySend("bar").isSuccess + + scope.cancel() + + assertEquals(EXPECTED_TRACE, traces.toString().trim()) + } + @Test fun onOutput_is_not_called_when_no_output_emitted() { runtimeTestRunner.runParametrizedTest( paramSource = runtimeOptions, before = ::setup, - ) { runtimeConfig: RuntimeConfig -> + ) { (runtimeConfig: RuntimeConfig, workflowTracer: WorkflowTracer?) -> val workflow = Workflow.stateless { props -> props } var onOutputCalls = 0 val props = MutableStateFlow(0) @@ -447,7 +519,7 @@ class RenderWorkflowInTest { scope = testScope, props = props, runtimeConfig = runtimeConfig, - workflowTracer = null, + workflowTracer = workflowTracer, ) { onOutputCalls++ } assertEquals(0, renderings.value.rendering) assertEquals(0, onOutputCalls) @@ -475,7 +547,7 @@ class RenderWorkflowInTest { runtimeTestRunner.runParametrizedTest( paramSource = runtimeOptions, before = ::setup, - ) { runtimeConfig: RuntimeConfig -> + ) { (runtimeConfig: RuntimeConfig, workflowTracer: WorkflowTracer?) -> val workflow = Workflow.stateless { throw ExpectedException() } @@ -485,7 +557,7 @@ class RenderWorkflowInTest { scope = testScope, props = MutableStateFlow(Unit), runtimeConfig = runtimeConfig, - workflowTracer = null, + workflowTracer = workflowTracer, ) {} } assertTrue(testScope.isActive) @@ -497,7 +569,7 @@ class RenderWorkflowInTest { runtimeTestRunner.runParametrizedTest( paramSource = runtimeOptions, before = ::setup, - ) { runtimeConfig: RuntimeConfig -> + ) { (runtimeConfig: RuntimeConfig, workflowTracer: WorkflowTracer?) -> var sideEffectWasRan = false val workflow = Workflow.stateless { runningSideEffect("test") { @@ -512,7 +584,7 @@ class RenderWorkflowInTest { scope = testScope, props = MutableStateFlow(Unit), runtimeConfig = runtimeConfig, - workflowTracer = null, + workflowTracer = workflowTracer, ) {} } assertFalse(sideEffectWasRan) @@ -524,7 +596,7 @@ class RenderWorkflowInTest { runtimeTestRunner.runParametrizedTest( paramSource = runtimeOptions, before = ::setup, - ) { runtimeConfig: RuntimeConfig -> + ) { (runtimeConfig: RuntimeConfig, workflowTracer: WorkflowTracer?) -> var sideEffectWasRan = false var cancellationException: Throwable? = null val childWorkflow = Workflow.stateless { @@ -546,7 +618,7 @@ class RenderWorkflowInTest { scope = testScope, props = MutableStateFlow(Unit), runtimeConfig = runtimeConfig, - workflowTracer = null, + workflowTracer = workflowTracer, ) {} } assertTrue(sideEffectWasRan) @@ -562,7 +634,7 @@ class RenderWorkflowInTest { runtimeTestRunner.runParametrizedTest( paramSource = runtimeOptions, before = ::setup, - ) { runtimeConfig: RuntimeConfig -> + ) { (runtimeConfig: RuntimeConfig, workflowTracer: WorkflowTracer?) -> var sideEffectWasRan = false val childWorkflow = Workflow.stateless { runningSideEffect("test") { @@ -580,7 +652,7 @@ class RenderWorkflowInTest { scope = testScope, props = MutableStateFlow(Unit), runtimeConfig = runtimeConfig, - workflowTracer = null, + workflowTracer = workflowTracer, ) {} } assertFalse(sideEffectWasRan) @@ -591,7 +663,7 @@ class RenderWorkflowInTest { runtimeTestRunner.runParametrizedTest( paramSource = runtimeOptions, before = ::setup, - ) { runtimeConfig: RuntimeConfig -> + ) { (runtimeConfig: RuntimeConfig, workflowTracer: WorkflowTracer?) -> val trigger = CompletableDeferred() // Throws an exception when trigger is completed. val workflow = Workflow.stateful( @@ -608,7 +680,7 @@ class RenderWorkflowInTest { scope = testScope, props = MutableStateFlow(Unit), runtimeConfig = runtimeConfig, - workflowTracer = null, + workflowTracer = workflowTracer, ) {} assertTrue(testScope.isActive) @@ -624,7 +696,7 @@ class RenderWorkflowInTest { runtimeTestRunner.runParametrizedTest( paramSource = runtimeOptions, before = ::setup, - ) { runtimeConfig: RuntimeConfig -> + ) { (runtimeConfig: RuntimeConfig, workflowTracer: WorkflowTracer?) -> val trigger = CompletableDeferred() // Throws an exception when trigger is completed. val workflow = Workflow.stateless { @@ -639,7 +711,7 @@ class RenderWorkflowInTest { scope = testScope, props = MutableStateFlow(Unit), runtimeConfig = runtimeConfig, - workflowTracer = null, + workflowTracer = workflowTracer, ) {} assertTrue(testScope.isActive) @@ -655,7 +727,7 @@ class RenderWorkflowInTest { runtimeTestRunner.runParametrizedTest( paramSource = runtimeOptions, before = ::setup, - ) { runtimeConfig: RuntimeConfig -> + ) { (runtimeConfig: RuntimeConfig, workflowTracer: WorkflowTracer?) -> var cancellationException: Throwable? = null val workflow = Workflow.stateless { runningSideEffect(key = "test1") { @@ -669,7 +741,7 @@ class RenderWorkflowInTest { scope = testScope, props = MutableStateFlow(Unit), runtimeConfig = runtimeConfig, - workflowTracer = null, + workflowTracer = workflowTracer, ) {} assertNull(cancellationException) assertTrue(testScope.isActive) @@ -684,7 +756,7 @@ class RenderWorkflowInTest { runtimeTestRunner.runParametrizedTest( paramSource = runtimeOptions, before = ::setup, - ) { runtimeConfig: RuntimeConfig -> + ) { (runtimeConfig: RuntimeConfig, workflowTracer: WorkflowTracer?) -> val trigger = CompletableDeferred() var renderCount = 0 val workflow = Workflow.stateless { @@ -700,7 +772,7 @@ class RenderWorkflowInTest { scope = testScope, props = MutableStateFlow(Unit), runtimeConfig = runtimeConfig, - workflowTracer = null, + workflowTracer = workflowTracer, ) {} assertTrue(testScope.isActive) assertTrue(renderCount == 1) @@ -720,7 +792,7 @@ class RenderWorkflowInTest { runtimeTestRunner.runParametrizedTest( paramSource = runtimeOptions, before = ::setup, - ) { runtimeConfig: RuntimeConfig -> + ) { (runtimeConfig: RuntimeConfig, workflowTracer: WorkflowTracer?) -> var cancellationException: Throwable? = null val workflow = Workflow.stateless { runningSideEffect(key = "failing") { @@ -734,7 +806,7 @@ class RenderWorkflowInTest { scope = testScope, props = MutableStateFlow(Unit), runtimeConfig = runtimeConfig, - workflowTracer = null, + workflowTracer = workflowTracer, ) {} assertNull(cancellationException) assertTrue(testScope.isActive) @@ -749,14 +821,14 @@ class RenderWorkflowInTest { runtimeTestRunner.runParametrizedTest( paramSource = runtimeOptions, before = ::setup, - ) { runtimeConfig: RuntimeConfig -> + ) { (runtimeConfig: RuntimeConfig, workflowTracer: WorkflowTracer?) -> val workflow = Workflow.stateless {} val renderings = renderWorkflowIn( workflow = workflow, scope = testScope, props = MutableStateFlow(Unit), runtimeConfig = runtimeConfig, - workflowTracer = null, + workflowTracer = workflowTracer, ) {} // Collect in separate scope so we actually test that the parent scope is failed when it's @@ -774,7 +846,7 @@ class RenderWorkflowInTest { runtimeTestRunner.runParametrizedTest( paramSource = runtimeOptions, before = ::setup, - ) { runtimeConfig: RuntimeConfig -> + ) { (runtimeConfig: RuntimeConfig, workflowTracer: WorkflowTracer?) -> var cancellationException: Throwable? = null val workflow = Workflow.stateless { runningSideEffect(key = "test") { @@ -790,7 +862,7 @@ class RenderWorkflowInTest { scope = pausedTestScope, props = MutableStateFlow(Unit), runtimeConfig = runtimeConfig, - workflowTracer = null, + workflowTracer = workflowTracer, ) {} pausedTestScope.launch { @@ -808,7 +880,7 @@ class RenderWorkflowInTest { runtimeTestRunner.runParametrizedTest( paramSource = runtimeOptions, before = ::setup, - ) { runtimeConfig: RuntimeConfig -> + ) { (runtimeConfig: RuntimeConfig, workflowTracer: WorkflowTracer?) -> val trigger = CompletableDeferred() // Emits a Unit when trigger is completed. val workflow = Workflow.stateless { @@ -819,7 +891,7 @@ class RenderWorkflowInTest { scope = pausedTestScope, props = MutableStateFlow(Unit), runtimeConfig = runtimeConfig, - workflowTracer = null, + workflowTracer = workflowTracer, ) { throw ExpectedException() } @@ -838,7 +910,7 @@ class RenderWorkflowInTest { runtimeTestRunner.runParametrizedTest( paramSource = runtimeOptions, before = ::setup, - ) { runtimeConfig: RuntimeConfig -> + ) { (runtimeConfig: RuntimeConfig, workflowTracer: WorkflowTracer?) -> val outputTrigger = CompletableDeferred() // A workflow whose state and rendering is the last output that it emitted. val workflow = Workflow.stateful( @@ -860,7 +932,7 @@ class RenderWorkflowInTest { scope = pausedTestScope, props = MutableStateFlow(Unit), runtimeConfig = runtimeConfig, - workflowTracer = null, + workflowTracer = workflowTracer, onOutput = { events += "output($it)" } ) .onEach { events += "rendering(${it.rendering})" } @@ -888,7 +960,7 @@ class RenderWorkflowInTest { runtimeTestRunner.runParametrizedTest( paramSource = runtimeOptions, before = ::setup, - ) { runtimeConfig: RuntimeConfig -> + ) { (runtimeConfig: RuntimeConfig, workflowTracer: WorkflowTracer?) -> val workflow = Workflow.stateful( snapshot = { Snapshot.of { @@ -908,7 +980,7 @@ class RenderWorkflowInTest { scope = testScope + exceptionHandler, props = props, runtimeConfig = runtimeConfig, - workflowTracer = null, + workflowTracer = workflowTracer, ) {} .value .snapshot @@ -926,7 +998,7 @@ class RenderWorkflowInTest { runtimeTestRunner.runParametrizedTest( paramSource = runtimeOptions, before = ::setup, - ) { runtimeConfig: RuntimeConfig -> + ) { (runtimeConfig: RuntimeConfig, workflowTracer: WorkflowTracer?) -> @Suppress("EqualsOrHashCode", "unused") class FailRendering(val value: Int) { override fun equals(other: Any?): Boolean { @@ -947,7 +1019,7 @@ class RenderWorkflowInTest { scope = testScope + exceptionHandler, props = props, runtimeConfig = runtimeConfig, - workflowTracer = null, + workflowTracer = workflowTracer, ) {} val renderings = ras.map { it.rendering } .produceIn(testScope) @@ -975,7 +1047,7 @@ class RenderWorkflowInTest { runtimeTestRunner.runParametrizedTest( paramSource = runtimeOptions, before = ::setup, - ) { runtimeConfig: RuntimeConfig -> + ) { (runtimeConfig: RuntimeConfig, workflowTracer: WorkflowTracer?) -> @Suppress("EqualsOrHashCode") data class FailRendering(val value: Int) { override fun hashCode(): Int { @@ -996,7 +1068,7 @@ class RenderWorkflowInTest { scope = testScope + exceptionHandler, props = props, runtimeConfig = runtimeConfig, - workflowTracer = null, + workflowTracer = workflowTracer, ) {} val renderings = ras.map { it.rendering } .produceIn(testScope) @@ -1023,11 +1095,13 @@ class RenderWorkflowInTest { @Test fun for_render_on_state_change_only_we_do_not_render_if_state_not_changed() { runtimeTestRunner.runParametrizedTest( paramSource = arrayOf( - setOf(RENDER_ONLY_WHEN_STATE_CHANGES), - setOf(RENDER_ONLY_WHEN_STATE_CHANGES, CONFLATE_STALE_RENDERINGS) + setOf(RENDER_ONLY_WHEN_STATE_CHANGES) to null, + setOf(RENDER_ONLY_WHEN_STATE_CHANGES) to testTracer, + setOf(RENDER_ONLY_WHEN_STATE_CHANGES, CONFLATE_STALE_RENDERINGS) to null, + setOf(RENDER_ONLY_WHEN_STATE_CHANGES, CONFLATE_STALE_RENDERINGS) to testTracer, ).asSequence(), before = ::setup, - ) { runtimeConfig: RuntimeConfig -> + ) { (runtimeConfig: RuntimeConfig, workflowTracer: WorkflowTracer?) -> check(runtimeConfig.contains(RENDER_ONLY_WHEN_STATE_CHANGES)) lateinit var sink: Sink @@ -1044,7 +1118,7 @@ class RenderWorkflowInTest { scope = testScope, props = props, runtimeConfig = runtimeConfig, - workflowTracer = null, + workflowTracer = workflowTracer, ) {} val emitted = mutableListOf>() @@ -1065,11 +1139,13 @@ class RenderWorkflowInTest { @Test fun for_render_on_state_change_only_we_render_if_state_changed() { runtimeTestRunner.runParametrizedTest( paramSource = arrayOf( - setOf(RENDER_ONLY_WHEN_STATE_CHANGES), - setOf(RENDER_ONLY_WHEN_STATE_CHANGES, CONFLATE_STALE_RENDERINGS) + setOf(RENDER_ONLY_WHEN_STATE_CHANGES) to null, + setOf(RENDER_ONLY_WHEN_STATE_CHANGES) to testTracer, + setOf(RENDER_ONLY_WHEN_STATE_CHANGES, CONFLATE_STALE_RENDERINGS) to null, + setOf(RENDER_ONLY_WHEN_STATE_CHANGES, CONFLATE_STALE_RENDERINGS) to testTracer, ).asSequence(), before = ::setup, - ) { runtimeConfig: RuntimeConfig -> + ) { (runtimeConfig: RuntimeConfig, workflowTracer: WorkflowTracer?) -> check(runtimeConfig.contains(RENDER_ONLY_WHEN_STATE_CHANGES)) lateinit var sink: Sink @@ -1086,7 +1162,7 @@ class RenderWorkflowInTest { scope = testScope, props = props, runtimeConfig = runtimeConfig, - workflowTracer = null, + workflowTracer = workflowTracer, ) {} val emitted = mutableListOf>() @@ -1105,4 +1181,33 @@ class RenderWorkflowInTest { } private class ExpectedException : RuntimeException() + + companion object { + internal val EXPECTED_TRACE: String = """ +StartingCreateWorkerWorkflow +Ending +StartingCheckingUniqueMatches +Ending +StartingRetainingChildren +Ending +StartingCreateSideEffectNode +Ending +StartingUpdateRuntimeTree +Ending +StartingUpdateRuntimeTree +Ending +StartingCreateWorkerWorkflow +Ending +StartingCheckingUniqueMatches +Ending +StartingRetainingChildren + Startingmatches + Ending +Ending +StartingUpdateRuntimeTree +Ending +StartingUpdateRuntimeTree +Ending + """.trim() + } }