Best way to test a never-ending workflow?

Typically, workflows that have a finite time-span can be tested with the following asserts:

require.True(t, env.IsWorkflowCompleted())
require.NoError(t, env.GetWorkflowError())

If the workflow is instead an infinitely long workflow (never-ending), we see the following error when testing:

2020/10/06 16:40:02 DEBUG Auto fire timer TimerID 0 TimerDuration 87600h0m0s TimeSkipped 87600h0m0s
    Test_ForeverWorkflow: forever_test.go:35: 
        	Error Trace:	forever_test.go:35
        	Error:      	Received unexpected error:
        	            	workflow execution error (workflowID: default-test-workflow-id, runID: default-test-run-id, workflowType: ForeverWorkflow): TimeoutType: ScheduleToClose, Cause: <nil>
        	Test:       	Test_ForeverWorkflow
--- FAIL: Test_ForeverWorkflow (0.00s)

The test should essentially verify the signal has been processed. I see two options:

  1. Only test that the signal was processed successfully.
  2. Test that the signal was processed successfully, and also test to make sure the workflow never completed by checking if the ScheduleToClose error fired after 87600h0m0s time skipped.

Any options I’m not considering?

Upon further consideration: I think it’s a valid test case to make sure the workflow never completes.

I think any infinite workflow has to call continue as new periodically to ensure that history doesn’t grow indefinitely.

Hi all

I have the same issue @pauldemarco mentioned.

Consider a workflow like

func Workflow(ctx workflow.Context, initial *negotiation.Negotiation) error {
	state := New(initial)

	if err := workflow.SetQueryHandler(ctx, QueryGetState, state.GetState); err != nil {
		return err
	}

	channel := workflow.GetSignalChannel(ctx, NegotiationSignalName)
	for {
		if state.IsDone() {
			break
		}

		var signal *negotiation.SignalRequest
		channel.Receive(ctx, &signal)
		state.Handle(signal)
	}
	return nil
}

When executing the workflow in the test I would expect s.env.IsWorkflowCompleted() to be false because I haven’t sent the right signal yet, nevertheless, the value always return true

func (s *UnitTestSuite) Test_ThatStayWaitingForSignal() {
	initial := &negotiation.Negotiation{}
	s.env.ExecuteWorkflow(Workflow, initial)
	s.Require().False(s.env.IsWorkflowCompleted())
	
}

Am I missing something?

The unit testing framework automatically forwards time if the workflow is blocked. So my guess is that if you check for the failure you’ll see the workflow timeout as an error.

You have to use delayed callbacks to send signals at a specific time during unit tests.