Testing a workflow that awaits multiple signals in order

I want to write a testcase for my workflow method that relies on three other signal methods for completion.

public interface Workflow {

    public static final String QUEUE_NAME = "Food_Order";

    @WorkflowMethod
    String workflowMethod();

    @SignalMethod
    void signalMethod1();

    @SignalMethod
    void signalMethod2();

    @SignalMethod
    void signalMethod3();
}

WorkFlow implementation →

    @Override
    public String workflowMethod() {
        activity.startSomething();
        logger.info("***** waiting for first signal method to be called *****");
        Workflow.await(() -> firstSignalArrived);

        logger.info("***** waiting for second signal method to be called *****");
        Workflow.await(() -> secondSignalArrived);

        logger.info("*****waiting for third signal method to be called  *****");
        Workflow.await(() -> thirdSignalArrived);

        return "completed";

    }

  
  @Override
    public void signalMethod1() {
        activity.doSomething();
        this. firstSignalArrived =true;
    }

   // similar implementations for other signal methods

Now, I tried to write a test case something like this:

   @Rule
    public TestWorkflowRule testWorkflowRule = TestWorkflowRule.newBuilder()
            .setWorkflowTypes(WorkflowImpl.class)
            .build();
  
   @Test
    public void testWorkflowWithActivities(){

        Workflow workflow = testWorkflowRule
                .getWorkflowClient()
                .newWorkflowStub(WorkflowImpl.class,
                        WorkflowOptions.newBuilder().setTaskQueue(testWorkflowRule.getTaskQueue()).build());

        testWorkflowRule.getTestEnvironment().registerDelayedCallback(Duration.ofSeconds(2),() -> workflow. signalMethod1());
        testWorkflowRule.getTestEnvironment().registerDelayedCallback(Duration.ofSeconds(2),() -> workflow. signalMethod2());
        testWorkflowRule.getTestEnvironment().registerDelayedCallback(Duration.ofSeconds(2),() -> workflow. signalMethod3());
        testWorkflowRule.getTestEnvironment().start();

        // workflow.workflowMethod() should return "completed" and testcase should pass. 
        Assert.assertNotNull(workflow.workflowMethod()); 
    }

But it is indefinitely waiting on the workflowMethod(). I’m not sure if I have done registerDelayedCallback correctly. If not, how to register multiple callbacks to TestWorkflowRule so that it will get signalled in order with specified delay ?

In the posted code, I don’t see that activity implementation is registered. So I guess that it is retrying the activity.

Thank you! I modified the TestWorkflowRule to:

   @Rule
    public TestWorkflowRule testWorkflowRule = TestWorkflowRule.newBuilder()
            .setActivityImplementations(new ActivitiesImpl()) // added this line
            .setWorkflowTypes(WorkflowImpl.class)
            .build();

and the testcase is passed :slight_smile:

Now when I remove the registered callbacks (just for testing) , I see that test is failed with an exception:

Caused by: io.temporal.failure.TimeoutFailure: timeoutType=TIMEOUT_TYPE_START_TO_CLOSE

which is expected because the workflow is indefinitely waiting for the signal to come.

I assume the default timeout is 10 seconds for a workflow. Correct me If I’m wrong.

The default timeout for a workflow under unit test is very large (at least ten years). But due to time skipping, it is reached very fast under the unit test.

BTW. Do you know that you can write your test using testEnv.sleep?

   Workflow workflow = testWorkflowRule
            .getWorkflowClient()
            .newWorkflowStub(WorkflowImpl.class,
                    WorkflowOptions.newBuilder().setTaskQueue(testWorkflowRule.getTaskQueue()).build());

   TestWorkflowEnvironment testEnv = testWorkflowRule.getTestEnvironment();
   WorkflowExecution execution = WorkflowClient.start(workflow::workflowMethod); 
   testEnv.sleep(Duration.ofSeconds(2));
   workflow.signalMethod1();
   testEnv.sleep(Duration.ofSeconds(2));
   workflow.signalMethod2();
   testEnv.sleep(Duration.ofSeconds(2));
   workflow.signalMethod3();
   WorkflowStub untyped = WorkflowStub.fromTyped(workflow);
   untyped.getResult();

This is cool :slight_smile:
I wasn’t aware of the sleep() feature in test. Thanks for the alternate approach.