From 399bdba67142312d7d2d8d2629504b1827a43b3f Mon Sep 17 00:00:00 2001 From: Stephen Edwards Date: Mon, 12 Jun 2023 11:51:24 -0400 Subject: [PATCH] Add RuntimeConfig through to WorkflowSession in Interceptor --- workflow-runtime/api/workflow-runtime.api | 1 + .../squareup/workflow1/WorkflowInterceptor.kt | 3 ++ .../workflow1/internal/SubtreeManager.kt | 19 ++++---- .../workflow1/internal/WorkflowNode.kt | 5 ++ .../workflow1/internal/WorkflowRunner.kt | 1 + .../SimpleLoggingWorkflowInterceptorTest.kt | 1 + .../workflow1/WorkflowInterceptorTest.kt | 1 + .../ChainedWorkflowInterceptorTest.kt | 3 ++ .../workflow1/internal/SubtreeManagerTest.kt | 12 +++-- .../workflow1/internal/WorkflowNodeTest.kt | 48 +++++++++++++++++++ 10 files changed, 83 insertions(+), 11 deletions(-) diff --git a/workflow-runtime/api/workflow-runtime.api b/workflow-runtime/api/workflow-runtime.api index b321656f2..f4d0c92b2 100644 --- a/workflow-runtime/api/workflow-runtime.api +++ b/workflow-runtime/api/workflow-runtime.api @@ -101,6 +101,7 @@ public abstract interface class com/squareup/workflow1/WorkflowInterceptor$Workf public abstract fun getIdentifier ()Lcom/squareup/workflow1/WorkflowIdentifier; public abstract fun getParent ()Lcom/squareup/workflow1/WorkflowInterceptor$WorkflowSession; public abstract fun getRenderKey ()Ljava/lang/String; + public abstract fun getRuntimeConfig ()Ljava/util/Set; public abstract fun getSessionId ()J } diff --git a/workflow-runtime/src/commonMain/kotlin/com/squareup/workflow1/WorkflowInterceptor.kt b/workflow-runtime/src/commonMain/kotlin/com/squareup/workflow1/WorkflowInterceptor.kt index ed2427839..b8eb64039 100644 --- a/workflow-runtime/src/commonMain/kotlin/com/squareup/workflow1/WorkflowInterceptor.kt +++ b/workflow-runtime/src/commonMain/kotlin/com/squareup/workflow1/WorkflowInterceptor.kt @@ -150,6 +150,9 @@ public interface WorkflowInterceptor { /** The parent [WorkflowSession] of this workflow, or null if this is the root workflow. */ public val parent: WorkflowSession? + + /** The [RuntimeConfig] of the runtime this session is executing in. */ + public val runtimeConfig: RuntimeConfig } /** 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 2e77c3147..8311456bc 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 @@ -3,6 +3,7 @@ package com.squareup.workflow1.internal import com.squareup.workflow1.ActionApplied import com.squareup.workflow1.ActionProcessingResult import com.squareup.workflow1.NoopWorkflowInterceptor +import com.squareup.workflow1.RuntimeConfig import com.squareup.workflow1.TreeSnapshot import com.squareup.workflow1.Workflow import com.squareup.workflow1.WorkflowAction @@ -89,6 +90,7 @@ internal class SubtreeManager( action: WorkflowAction, childResult: ActionApplied<*> ) -> ActionProcessingResult, + private val runtimeConfig: RuntimeConfig, private val workflowSession: WorkflowSession? = null, private val interceptor: WorkflowInterceptor = NoopWorkflowInterceptor, private val idCounter: IdCounter? = null @@ -180,14 +182,15 @@ internal class SubtreeManager( val childTreeSnapshots = snapshotCache?.get(id) val workflowNode = WorkflowNode( - id, - child.asStatefulWorkflow(), - initialProps, - childTreeSnapshots, - contextForChildren, - ::acceptChildActionResult, - workflowSession, - interceptor, + id = id, + workflow = child.asStatefulWorkflow(), + initialProps = initialProps, + snapshot = childTreeSnapshots, + baseContext = contextForChildren, + runtimeConfig = runtimeConfig, + emitAppliedActionToParent = ::acceptChildActionResult, + parent = workflowSession, + interceptor = interceptor, idCounter = idCounter ) return WorkflowChildNode(child, handler, workflowNode) diff --git a/workflow-runtime/src/commonMain/kotlin/com/squareup/workflow1/internal/WorkflowNode.kt b/workflow-runtime/src/commonMain/kotlin/com/squareup/workflow1/internal/WorkflowNode.kt index 194ce7755..beb581f26 100644 --- a/workflow-runtime/src/commonMain/kotlin/com/squareup/workflow1/internal/WorkflowNode.kt +++ b/workflow-runtime/src/commonMain/kotlin/com/squareup/workflow1/internal/WorkflowNode.kt @@ -4,6 +4,8 @@ import com.squareup.workflow1.ActionApplied import com.squareup.workflow1.ActionProcessingResult import com.squareup.workflow1.NoopWorkflowInterceptor import com.squareup.workflow1.RenderContext +import com.squareup.workflow1.RuntimeConfig +import com.squareup.workflow1.RuntimeConfigOptions import com.squareup.workflow1.StatefulWorkflow import com.squareup.workflow1.TreeSnapshot import com.squareup.workflow1.Workflow @@ -44,6 +46,8 @@ internal class WorkflowNode( initialProps: PropsT, snapshot: TreeSnapshot?, baseContext: CoroutineContext, + // Providing default value so we don't need to specify in test. + override val runtimeConfig: RuntimeConfig = RuntimeConfigOptions.DEFAULT_CONFIG, private val emitAppliedActionToParent: (ActionApplied) -> ActionProcessingResult = { it }, override val parent: WorkflowSession? = null, @@ -66,6 +70,7 @@ internal class WorkflowNode( snapshotCache = snapshot?.childTreeSnapshots, contextForChildren = coroutineContext, emitActionToParent = ::applyAction, + runtimeConfig = runtimeConfig, workflowSession = this, interceptor = interceptor, idCounter = idCounter diff --git a/workflow-runtime/src/commonMain/kotlin/com/squareup/workflow1/internal/WorkflowRunner.kt b/workflow-runtime/src/commonMain/kotlin/com/squareup/workflow1/internal/WorkflowRunner.kt index 0d9a5201a..2794cd07a 100644 --- a/workflow-runtime/src/commonMain/kotlin/com/squareup/workflow1/internal/WorkflowRunner.kt +++ b/workflow-runtime/src/commonMain/kotlin/com/squareup/workflow1/internal/WorkflowRunner.kt @@ -54,6 +54,7 @@ internal class WorkflowRunner( initialProps = currentProps, snapshot = snapshot, baseContext = scope.coroutineContext, + runtimeConfig = runtimeConfig, interceptor = interceptor, idCounter = idCounter ) diff --git a/workflow-runtime/src/commonTest/kotlin/com/squareup/workflow1/SimpleLoggingWorkflowInterceptorTest.kt b/workflow-runtime/src/commonTest/kotlin/com/squareup/workflow1/SimpleLoggingWorkflowInterceptorTest.kt index 6fbd4b77b..589dcab1e 100644 --- a/workflow-runtime/src/commonTest/kotlin/com/squareup/workflow1/SimpleLoggingWorkflowInterceptorTest.kt +++ b/workflow-runtime/src/commonTest/kotlin/com/squareup/workflow1/SimpleLoggingWorkflowInterceptorTest.kt @@ -82,6 +82,7 @@ internal class SimpleLoggingWorkflowInterceptorTest { override val renderKey: String get() = "key" override val sessionId: Long get() = 42 override val parent: WorkflowSession? get() = null + override val runtimeConfig: RuntimeConfig = RuntimeConfigOptions.DEFAULT_CONFIG } private object FakeRenderContext : BaseRenderContext { diff --git a/workflow-runtime/src/commonTest/kotlin/com/squareup/workflow1/WorkflowInterceptorTest.kt b/workflow-runtime/src/commonTest/kotlin/com/squareup/workflow1/WorkflowInterceptorTest.kt index 0ab204617..b437dcc74 100644 --- a/workflow-runtime/src/commonTest/kotlin/com/squareup/workflow1/WorkflowInterceptorTest.kt +++ b/workflow-runtime/src/commonTest/kotlin/com/squareup/workflow1/WorkflowInterceptorTest.kt @@ -216,6 +216,7 @@ internal class WorkflowInterceptorTest { override val renderKey: String = "" override val sessionId: Long = 0 override val parent: WorkflowSession? = null + override val runtimeConfig: RuntimeConfig = RuntimeConfigOptions.DEFAULT_CONFIG } private object TestWorkflow : StatefulWorkflow() { diff --git a/workflow-runtime/src/commonTest/kotlin/com/squareup/workflow1/internal/ChainedWorkflowInterceptorTest.kt b/workflow-runtime/src/commonTest/kotlin/com/squareup/workflow1/internal/ChainedWorkflowInterceptorTest.kt index 441687de1..266ae5ca3 100644 --- a/workflow-runtime/src/commonTest/kotlin/com/squareup/workflow1/internal/ChainedWorkflowInterceptorTest.kt +++ b/workflow-runtime/src/commonTest/kotlin/com/squareup/workflow1/internal/ChainedWorkflowInterceptorTest.kt @@ -4,6 +4,8 @@ package com.squareup.workflow1.internal import com.squareup.workflow1.BaseRenderContext import com.squareup.workflow1.NoopWorkflowInterceptor +import com.squareup.workflow1.RuntimeConfig +import com.squareup.workflow1.RuntimeConfigOptions import com.squareup.workflow1.Sink import com.squareup.workflow1.Snapshot import com.squareup.workflow1.Workflow @@ -331,5 +333,6 @@ internal class ChainedWorkflowInterceptorTest { override val renderKey: String = "" override val sessionId: Long = 0 override val parent: WorkflowSession? = null + override val runtimeConfig: RuntimeConfig = RuntimeConfigOptions.DEFAULT_CONFIG } } diff --git a/workflow-runtime/src/commonTest/kotlin/com/squareup/workflow1/internal/SubtreeManagerTest.kt b/workflow-runtime/src/commonTest/kotlin/com/squareup/workflow1/internal/SubtreeManagerTest.kt index 8eb13cff0..c8e375a2a 100644 --- a/workflow-runtime/src/commonTest/kotlin/com/squareup/workflow1/internal/SubtreeManagerTest.kt +++ b/workflow-runtime/src/commonTest/kotlin/com/squareup/workflow1/internal/SubtreeManagerTest.kt @@ -4,6 +4,7 @@ package com.squareup.workflow1.internal import com.squareup.workflow1.ActionApplied import com.squareup.workflow1.ActionProcessingResult +import com.squareup.workflow1.RuntimeConfigOptions import com.squareup.workflow1.Snapshot import com.squareup.workflow1.StatefulWorkflow import com.squareup.workflow1.TreeSnapshot @@ -307,7 +308,12 @@ internal class SubtreeManagerTest { private fun subtreeManagerForTest( snapshotCache: Map? = null - ) = SubtreeManager(snapshotCache, context, emitActionToParent = { action, childResult -> - ActionApplied(WorkflowOutput(action), childResult.stateChanged) - }) + ) = SubtreeManager( + snapshotCache = snapshotCache, + contextForChildren = context, + runtimeConfig = RuntimeConfigOptions.DEFAULT_CONFIG, + emitActionToParent = { action, childResult -> + ActionApplied(WorkflowOutput(action), childResult.stateChanged) + } + ) } diff --git a/workflow-runtime/src/commonTest/kotlin/com/squareup/workflow1/internal/WorkflowNodeTest.kt b/workflow-runtime/src/commonTest/kotlin/com/squareup/workflow1/internal/WorkflowNodeTest.kt index 8afede8ac..025ec7bea 100644 --- a/workflow-runtime/src/commonTest/kotlin/com/squareup/workflow1/internal/WorkflowNodeTest.kt +++ b/workflow-runtime/src/commonTest/kotlin/com/squareup/workflow1/internal/WorkflowNodeTest.kt @@ -5,12 +5,16 @@ package com.squareup.workflow1.internal import com.squareup.workflow1.ActionApplied import com.squareup.workflow1.BaseRenderContext +import com.squareup.workflow1.RuntimeConfig +import com.squareup.workflow1.RuntimeConfigOptions +import com.squareup.workflow1.RuntimeConfigOptions.RENDER_ONLY_WHEN_STATE_CHANGES import com.squareup.workflow1.Sink import com.squareup.workflow1.Snapshot import com.squareup.workflow1.StatefulWorkflow import com.squareup.workflow1.TreeSnapshot import com.squareup.workflow1.Workflow import com.squareup.workflow1.WorkflowAction +import com.squareup.workflow1.WorkflowExperimentalRuntime import com.squareup.workflow1.WorkflowIdentifier import com.squareup.workflow1.WorkflowInterceptor import com.squareup.workflow1.WorkflowInterceptor.RenderContextInterceptor @@ -818,6 +822,49 @@ internal class WorkflowNodeTest { assertEquals(0, interceptedSession.sessionId) assertEquals("foo", interceptedSession.renderKey) assertEquals(42, interceptedSession.parent!!.sessionId) + assertEquals(RuntimeConfigOptions.DEFAULT_CONFIG, interceptedSession.runtimeConfig) + + val cause = CancellationException("stop") + node.cancel(cause) + assertSame(cause, cancellationException) + } + + @OptIn(WorkflowExperimentalRuntime::class) + @Test + fun interceptor_handles_scope_start_and_cancellation_with_config() { + lateinit var interceptedScope: CoroutineScope + lateinit var interceptedSession: WorkflowSession + lateinit var cancellationException: Throwable + val interceptor = object : WorkflowInterceptor { + override fun onSessionStarted( + workflowScope: CoroutineScope, + session: WorkflowSession + ) { + interceptedScope = workflowScope + interceptedSession = session + workflowScope.coroutineContext[Job]!!.invokeOnCompletion { + cancellationException = it!! + } + } + } + val workflow = Workflow.rendering(Unit) + val node = WorkflowNode( + id = workflow.id(key = "foo"), + workflow = workflow.asStatefulWorkflow(), + initialProps = Unit, + snapshot = null, + interceptor = interceptor, + baseContext = Unconfined, + runtimeConfig = setOf(RENDER_ONLY_WHEN_STATE_CHANGES), + parent = TestSession(42) + ) + + assertSame(node.coroutineContext, interceptedScope.coroutineContext) + assertEquals(workflow.identifier, interceptedSession.identifier) + assertEquals(0, interceptedSession.sessionId) + assertEquals("foo", interceptedSession.renderKey) + assertEquals(42, interceptedSession.parent!!.sessionId) + assertEquals(setOf(RENDER_ONLY_WHEN_STATE_CHANGES), interceptedSession.runtimeConfig) val cause = CancellationException("stop") node.cancel(cause) @@ -1292,5 +1339,6 @@ internal class WorkflowNodeTest { override val identifier: WorkflowIdentifier = Workflow.rendering(Unit).identifier override val renderKey: String = "" override val parent: WorkflowSession? = null + override val runtimeConfig: RuntimeConfig = RuntimeConfigOptions.DEFAULT_CONFIG } }