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 }