Interface TestWorkflowEnvironment

  • All Known Implementing Classes:
    TestWorkflowEnvironmentInternal

    public interface TestWorkflowEnvironment
    TestWorkflowEnvironment provides workflow unit testing capabilities.

    Testing the workflow code is hard as it might be potentially very long running. The included in-memory implementation of the Cadence service supports an automatic time skipping. Anytime a workflow under the test as well as the unit test code are waiting on a timer (or sleep) the internal service time is automatically advanced to the nearest time that unblocks one of the waiting threads. This way a workflow that runs in production for months is unit tested in milliseconds. Here is an example of a test that executes in a few milliseconds instead of over two hours that are needed for the workflow to complete:

    
       public class SignaledWorkflowImpl implements SignaledWorkflow {
         private String signalInput;
    
        @Override
         public String workflow1(String input) {
           Workflow.sleep(Duration.ofHours(1));
           Workflow.await(() -> signalInput != null);
           Workflow.sleep(Duration.ofHours(1));
           return signalInput + "-" + input;
         }
    
        @Override
         public void processSignal(String input) {
           signalInput = input;
        }
      }
    
     @Test
      public void testSignal() throws ExecutionException, InterruptedException {
        TestWorkflowEnvironment testEnvironment = TestWorkflowEnvironment.newInstance();
    
        // Creates a worker that polls tasks from the service owned by the testEnvironment.
        Worker worker = testEnvironment.newWorker(TASK_LIST);
        worker.registerWorkflowImplementationTypes(SignaledWorkflowImpl.class);
        worker.start();
    
        // Creates a WorkflowClient that interacts with the server owned by the testEnvironment.
        WorkflowClient client = testEnvironment.newWorkflowClient();
        SignaledWorkflow workflow = client.newWorkflowStub(SignaledWorkflow.class);
    
        // Starts a workflow execution
        CompletableFuture result = WorkflowClient.execute(workflow::workflow1, "input1");
    
        // The sleep forwards the service clock for 65 minutes without blocking.
        // This ensures that the signal is sent after the one hour sleep in the workflow code.
        testEnvironment.sleep(Duration.ofMinutes(65));
        workflow.processSignal("signalInput");
    
        // Blocks until workflow is complete. Workflow sleep forwards clock for one hour and
        // this call returns almost immediately.
        assertEquals("signalInput-input1", result.get());
    
        // Closes workers and releases in-memory service.
        testEnvironment.close();
      }
    
     
    • Method Detail

      • newWorker

        Worker newWorker​(java.lang.String taskList)
        Creates a new Worker instance that is connected to the in-memory test Cadence service.
        Parameters:
        taskList - task list to poll.
      • newWorker

        Worker newWorker​(java.lang.String taskList,
                         java.util.function.Function<WorkerOptions.Builder,​WorkerOptions.Builder> overrideOptions)
        Creates a new Worker instance that is connected to the in-memory test Cadence service.
        Parameters:
        taskList - task list to poll.
        overrideOptions - is used to override the default worker options.
      • newWorkflowClient

        WorkflowClient newWorkflowClient()
        Creates a WorkflowClient that is connected to the in-memory test Cadence service.
      • newWorkflowClient

        WorkflowClient newWorkflowClient​(WorkflowClientOptions clientOptions)
        Creates a WorkflowClient that is connected to the in-memory test Cadence service.
        Parameters:
        clientOptions - options used to configure the client.
      • currentTimeMillis

        long currentTimeMillis()
        Returns the current in-memory test Cadence service time in milliseconds. This time might not be equal to System.currentTimeMillis() due to time skipping.
      • sleep

        void sleep​(java.time.Duration duration)
        Wait until internal test Cadence service time passes the specified duration. This call also indicates that workflow time might jump forward (if none of the activities are running) up to the specified duration.
      • registerDelayedCallback

        void registerDelayedCallback​(java.time.Duration delay,
                                     java.lang.Runnable r)
        Registers a callback to run after the specified delay according to the test Cadence service internal clock.
      • getWorkflowService

        IWorkflowService getWorkflowService()
        Returns the in-memory test Cadence service that is owned by this.
      • getDomain

        java.lang.String getDomain()
      • getDiagnostics

        java.lang.String getDiagnostics()
        Returns the diagnostic data about the internal service state. Currently prints histories of all workflow instances stored in the service. This is useful information to print in the case of a unit test failure. A convenient way to achieve this is to add the following Rule to a unit test:
        
          @Rule
           public TestWatcher watchman =
               new TestWatcher() {
                @Override
                 protected void failed(Throwable e, Description description) {
                   System.err.println(testEnvironment.getDiagnostics());
                   testEnvironment.close();
                 }
               };
         
      • start

        void start()
        Start all workers created by this factory.
      • isStarted

        boolean isStarted()
        Was start() called?
      • shutdownNow

        void shutdownNow()
        Initiates an orderly shutdown in which polls are stopped and already received decision and activity tasks are attempted to be stopped. This implementation cancels tasks via Thread.interrupt(), so any task that fails to respond to interrupts may never terminate. Also after the shutdownNow calls to Activity.heartbeat(Object) start throwing ActivityWorkerShutdownException. Invocation has no additional effect if already shut down. This method does not wait for previously received tasks to complete execution. Use awaitTermination(long, TimeUnit) to do that.
      • awaitTermination

        void awaitTermination​(long timeout,
                              java.util.concurrent.TimeUnit unit)
        Blocks until all tasks have completed execution after a shutdown request, or the timeout occurs, or the current thread is interrupted, whichever happens first.