diff --git a/internal/internal_workflow_testsuite.go b/internal/internal_workflow_testsuite.go index f239186e2..3e473899f 100644 --- a/internal/internal_workflow_testsuite.go +++ b/internal/internal_workflow_testsuite.go @@ -2281,9 +2281,16 @@ func (env *testWorkflowEnvironmentImpl) RequestCancelChildWorkflow(_, workflowID func (env *testWorkflowEnvironmentImpl) RequestCancelExternalWorkflow(namespace, workflowID, runID string, callback ResultHandler) { if env.workflowInfo.WorkflowExecution.ID == workflowID { - // cancel current workflow - env.workflowCancelHandler() - // check if current workflow is a child workflow + // The way testWorkflowEnvironment is setup today, we close the child workflow dispatcher before calling + // the workflowCancelHandler. A larger refactor would be needed to handle this similar to non-test code. + // Maybe worth doing when https://github.com/temporalio/go-sdk/issues/50 is tackled. + if sd, ok := env.workflowDef.(*syncWorkflowDefinition); ok && env.isChildWorkflow() { + sd.dispatcher.NewCoroutine(sd.rootCtx, "cancel-self", true, func(ctx Context) { + env.workflowCancelHandler() + }) + } else { + env.workflowCancelHandler() + } if env.isChildWorkflow() && env.onChildWorkflowCanceledListener != nil { env.postCallback(func() { env.onChildWorkflowCanceledListener(env.workflowInfo) diff --git a/internal/workflow_testsuite_test.go b/internal/workflow_testsuite_test.go index 2326e7c55..9b9220f83 100644 --- a/internal/workflow_testsuite_test.go +++ b/internal/workflow_testsuite_test.go @@ -1232,3 +1232,37 @@ func TestDynamicWorkflows(t *testing.T) { require.NoError(t, err) require.Equal(t, "dynamic-activity - grape - cherry", result) } + +func SleepHour(ctx Context) error { + return Sleep(ctx, time.Hour) +} + +func SleepThenCancel(ctx Context) error { + cwf := ExecuteChildWorkflow( + ctx, + SleepHour, + ) + var res WorkflowExecution + if err := cwf.GetChildWorkflowExecution().Get(ctx, &res); err != nil { + return err + } + + // Canceling an external workflow that causes a timer to cancel used to fail due to + // "illegal access from outside of workflow context" + err := RequestCancelExternalWorkflow(ctx, res.ID, res.RunID).Get(ctx, nil) + if err != nil { + return err + } + + // Give the workflow time to finish canceling the child workflow + return Sleep(ctx, 1*time.Second) +} + +func TestRequestCancelExternalWorkflowInSelector(t *testing.T) { + testSuite := &WorkflowTestSuite{} + env := testSuite.NewTestWorkflowEnvironment() + env.RegisterWorkflow(SleepHour) + env.ExecuteWorkflow(SleepThenCancel) + require.NoError(t, env.GetWorkflowError()) + env.IsWorkflowCompleted() +}