go.uber.org/cadence@v1.2.9/test/replaytests/replay_test.go (about)

     1  // Copyright (c) 2017 Uber Technologies, Inc.
     2  //
     3  // Permission is hereby granted, free of charge, to any person obtaining a copy
     4  // of this software and associated documentation files (the "Software"), to deal
     5  // in the Software without restriction, including without limitation the rights
     6  // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
     7  // copies of the Software, and to permit persons to whom the Software is
     8  // furnished to do so, subject to the following conditions:
     9  //
    10  // The above copyright notice and this permission notice shall be included in
    11  // all copies or substantial portions of the Software.
    12  //
    13  // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
    14  // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
    15  // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
    16  // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
    17  // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
    18  // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
    19  // THE SOFTWARE.
    20  
    21  package replaytests
    22  
    23  import (
    24  	"strings"
    25  	"testing"
    26  
    27  	"go.uber.org/cadence/activity"
    28  
    29  	"github.com/stretchr/testify/assert"
    30  
    31  	"github.com/stretchr/testify/require"
    32  	"go.uber.org/zap/zaptest"
    33  
    34  	"go.uber.org/cadence/worker"
    35  	"go.uber.org/cadence/workflow"
    36  )
    37  
    38  func TestReplayWorkflowHistoryFromFile(t *testing.T) {
    39  	for _, testFile := range []string{"basic.json", "basic_new.json", "version.json", "version_new.json"} {
    40  		t.Run("replay_"+strings.Split(testFile, ".")[0], func(t *testing.T) {
    41  			replayer := worker.NewWorkflowReplayer()
    42  			replayer.RegisterWorkflow(Workflow)
    43  			replayer.RegisterWorkflow(Workflow2)
    44  
    45  			err := replayer.ReplayWorkflowHistoryFromJSONFile(zaptest.NewLogger(t), testFile)
    46  			require.NoError(t, err)
    47  		})
    48  	}
    49  }
    50  
    51  func TestReplayChildWorkflowBugBackport(t *testing.T) {
    52  	replayer := worker.NewWorkflowReplayer()
    53  	replayer.RegisterWorkflowWithOptions(childWorkflow, workflow.RegisterOptions{Name: "child"})
    54  	replayer.RegisterWorkflowWithOptions(childWorkflowBug, workflow.RegisterOptions{Name: "parent"})
    55  
    56  	err := replayer.ReplayWorkflowHistoryFromJSONFile(zaptest.NewLogger(t), "child_bug.json")
    57  	require.NoError(t, err)
    58  }
    59  
    60  // Gives a non-deterministic-error because the getGreetingActivitytest was not registered on the replayer.
    61  func TestGreetingsWorkflowforActivity(t *testing.T) {
    62  	replayer := worker.NewWorkflowReplayer()
    63  	replayer.RegisterWorkflowWithOptions(greetingsWorkflowActivity, workflow.RegisterOptions{Name: "greetings"})
    64  	err := replayer.ReplayWorkflowHistoryFromJSONFile(zaptest.NewLogger(t), "greetings.json")
    65  	require.Error(t, err)
    66  }
    67  
    68  func TestGreetingsWorkflow(t *testing.T) {
    69  	replayer := worker.NewWorkflowReplayer()
    70  	replayer.RegisterWorkflowWithOptions(greetingsWorkflow, workflow.RegisterOptions{Name: "greetings"})
    71  	err := replayer.ReplayWorkflowHistoryFromJSONFile(zaptest.NewLogger(t), "greetings.json")
    72  	require.NoError(t, err)
    73  }
    74  
    75  // Should have failed but passed. Maybe, because the result recorded in history still matches the return type of the workflow.
    76  func TestGreetingsWorkflow3(t *testing.T) {
    77  	replayer := worker.NewWorkflowReplayer()
    78  	replayer.RegisterActivityWithOptions(getNameActivity3, activity.RegisterOptions{Name: "main.getNameActivity", DisableAlreadyRegisteredCheck: true})
    79  	replayer.RegisterWorkflowWithOptions(greetingsWorkflow3, workflow.RegisterOptions{Name: "greetings"})
    80  	err := replayer.ReplayWorkflowHistoryFromJSONFile(zaptest.NewLogger(t), "greetings.json")
    81  	require.NoError(t, err)
    82  }
    83  
    84  // Fails because the expected signature was different from history.
    85  func TestGreetingsWorkflow4(t *testing.T) {
    86  	replayer := worker.NewWorkflowReplayer()
    87  	replayer.RegisterActivityWithOptions(getNameActivity4, activity.RegisterOptions{Name: "main.getNameActivity", DisableAlreadyRegisteredCheck: true})
    88  	replayer.RegisterWorkflowWithOptions(greetingsWorkflow4, workflow.RegisterOptions{Name: "greetings"})
    89  	err := replayer.ReplayWorkflowHistoryFromJSONFile(zaptest.NewLogger(t), "greetings.json")
    90  	require.Error(t, err)
    91  }
    92  
    93  // Panic with failed to register activity. This passes in cadence_samples because it's registered in Helper.
    94  // To test it on cadence_samples change the https://github.com/uber-common/cadence-samples/blob/master/cmd/samples/recipes/greetings/greetings_workflow.go
    95  // to include the extra return types in getNameActivity.
    96  func TestGreetingsWorkflow2(t *testing.T) {
    97  
    98  	t.Skip("Panic with failed to register activity. Here the activity returns incompatible arguments so the test should fail")
    99  	replayer := worker.NewWorkflowReplayer()
   100  	replayer.RegisterActivityWithOptions(getNameActivity2, activity.RegisterOptions{Name: "main.getNameActivity", DisableAlreadyRegisteredCheck: true})
   101  	replayer.RegisterWorkflowWithOptions(greetingsWorkflow2, workflow.RegisterOptions{Name: "greetings"})
   102  	err := replayer.ReplayWorkflowHistoryFromJSONFile(zaptest.NewLogger(t), "greetings.json")
   103  	require.Error(t, err)
   104  }
   105  
   106  // Ideally replayer doesn't concern itself with the change in the activity content until it matches the expected output type.
   107  // History has recorded the output of banana activity instead. The replayer should have failed because we have not registered any
   108  // activity here in the test.
   109  // The replayer still runs whatever it found in the history and passes.
   110  func TestExclusiveChoiceWorkflowWithUnregisteredActivity(t *testing.T) {
   111  	replayer := worker.NewWorkflowReplayer()
   112  
   113  	replayer.RegisterWorkflowWithOptions(exclusiveChoiceWorkflow, workflow.RegisterOptions{Name: "choice"})
   114  	err := replayer.ReplayWorkflowHistoryFromJSONFile(zaptest.NewLogger(t), "choice.json")
   115  	require.NoError(t, err)
   116  }
   117  
   118  // This test registers Cherry Activity as the activity but calls Apple activity in the workflow code. Infact, Cherry and Banana
   119  // activities are not even a part of the workflow code in question.
   120  // History has recorded the output of banana activity. Here, The workflow is not waiting for the activity so it doesn't notice
   121  // that registered activity is different from executed activity.
   122  // The replayer relies on whatever is recorded in the History so as long as the main activity name in the options matched partially
   123  // it doesn't raise errors.
   124  func TestExclusiveChoiceWorkflowWithDifferentActvityCombo(t *testing.T) {
   125  	replayer := worker.NewWorkflowReplayer()
   126  
   127  	replayer.RegisterWorkflowWithOptions(exclusiveChoiceWorkflow2, workflow.RegisterOptions{Name: "choice"})
   128  	replayer.RegisterActivityWithOptions(getAppleOrderActivity, activity.RegisterOptions{Name: "main.getOrderActivity"})
   129  	replayer.RegisterActivityWithOptions(orderAppleActivity, activity.RegisterOptions{Name: "testactivity"})
   130  	err := replayer.ReplayWorkflowHistoryFromJSONFile(zaptest.NewLogger(t), "choice.json")
   131  	require.NoError(t, err)
   132  }
   133  
   134  func TestBranchWorkflow(t *testing.T) {
   135  	replayer := worker.NewWorkflowReplayer()
   136  
   137  	replayer.RegisterWorkflowWithOptions(sampleBranchWorkflow, workflow.RegisterOptions{Name: "branch"})
   138  
   139  	err := replayer.ReplayWorkflowHistoryFromJSONFile(zaptest.NewLogger(t), "branch.json")
   140  	require.NoError(t, err)
   141  }
   142  
   143  // Fails with a non deterministic error because there was an additional unexpected branch. Decreasing the number of branches will
   144  // also fail the test because the history expects the same number of branches executing the activity.
   145  func TestBranchWorkflowWithExtraBranch(t *testing.T) {
   146  	replayer := worker.NewWorkflowReplayer()
   147  
   148  	replayer.RegisterWorkflowWithOptions(sampleBranchWorkflow2, workflow.RegisterOptions{Name: "branch"})
   149  
   150  	err := replayer.ReplayWorkflowHistoryFromJSONFile(zaptest.NewLogger(t), "branch.json")
   151  	assert.ErrorContains(t, err, "nondeterministic workflow")
   152  }
   153  
   154  // TestSequentialStepsWorkflow replays a history with 2 sequential activity calls and runs it against new version of the workflow code which only calls 1 activity.
   155  // This should be considered as non-determinism error.
   156  func TestSequentialStepsWorkflow(t *testing.T) {
   157  	replayer := worker.NewWorkflowReplayer()
   158  
   159  	replayer.RegisterWorkflowWithOptions(replayerHelloWorldWorkflow, workflow.RegisterOptions{Name: "fx.ReplayerHelloWorldWorkflow"})
   160  	replayer.RegisterActivityWithOptions(replayerHelloWorldActivity, activity.RegisterOptions{Name: "replayerhello"})
   161  	err := replayer.ReplayWorkflowHistoryFromJSONFile(zaptest.NewLogger(t), "sequential.json")
   162  	assert.NoError(t, err)
   163  }
   164  
   165  func TestParallel(t *testing.T) {
   166  	replayer := worker.NewWorkflowReplayer()
   167  
   168  	replayer.RegisterWorkflowWithOptions(sampleParallelWorkflow, workflow.RegisterOptions{Name: "branch2"})
   169  
   170  	err := replayer.ReplayWorkflowHistoryFromJSONFile(zaptest.NewLogger(t), "branch2.json")
   171  	require.NoError(t, err)
   172  }
   173  
   174  // Should have failed since the first go routine has only one branch whereas the history has two branches.
   175  // The replayer totally misses this change.
   176  func TestParallel2(t *testing.T) {
   177  	replayer := worker.NewWorkflowReplayer()
   178  
   179  	replayer.RegisterWorkflowWithOptions(sampleParallelWorkflow2, workflow.RegisterOptions{Name: "branch2"})
   180  
   181  	err := replayer.ReplayWorkflowHistoryFromJSONFile(zaptest.NewLogger(t), "branch2.json")
   182  	require.NoError(t, err)
   183  }
   184  
   185  // Runs a history which ends with WorkflowExecutionContinuedAsNew. Replay fails because of the additional checks done
   186  // for continue as new case by replayWorkflowHistory().
   187  // This should not have any error because it's a valid continue as new case.
   188  func TestContinueAsNew(t *testing.T) {
   189  	replayer := worker.NewWorkflowReplayer()
   190  	replayer.RegisterWorkflowWithOptions(ContinueAsNewWorkflow, workflow.RegisterOptions{Name: "fx.SimpleSignalWorkflow"})
   191  	err := replayer.ReplayWorkflowHistoryFromJSONFile(zaptest.NewLogger(t), "continue_as_new.json")
   192  	assert.ErrorContains(t, err, "missing replay decision for WorkflowExecutionContinuedAsNew")
   193  }