go.uber.org/cadence@v1.2.9/internal/workflow_shadower_worker_test.go (about) 1 // Copyright (c) 2017-2021 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 internal 22 23 import ( 24 "context" 25 "testing" 26 27 "github.com/golang/mock/gomock" 28 "github.com/stretchr/testify/require" 29 "github.com/stretchr/testify/suite" 30 "go.uber.org/yarpc" 31 "go.uber.org/zap/zaptest" 32 33 "go.uber.org/cadence/.gen/go/cadence/workflowserviceclient" 34 "go.uber.org/cadence/.gen/go/cadence/workflowservicetest" 35 "go.uber.org/cadence/.gen/go/shadower" 36 "go.uber.org/cadence/.gen/go/shared" 37 "go.uber.org/cadence/internal/common" 38 ) 39 40 type shadowWorkerSuite struct { 41 *require.Assertions 42 suite.Suite 43 44 controller *gomock.Controller 45 mockService *workflowservicetest.MockClient 46 } 47 48 func TestShadowWorkerSuite(t *testing.T) { 49 s := new(shadowWorkerSuite) 50 suite.Run(t, s) 51 } 52 53 func (s *shadowWorkerSuite) SetupTest() { 54 s.Assertions = require.New(s.T()) 55 56 s.controller = gomock.NewController(s.T()) 57 s.mockService = workflowservicetest.NewMockClient(s.controller) 58 } 59 60 func (s *shadowWorkerSuite) TearDownTest() { 61 s.controller.Finish() 62 } 63 64 func (s *shadowWorkerSuite) TestNewShadowWorker() { 65 registry := newRegistry() 66 shadowWorker := newShadowWorker( 67 s.mockService, 68 testDomain, 69 ShadowOptions{}, 70 workerExecutionParameters{ 71 TaskList: testTaskList, 72 WorkerOptions: WorkerOptions{ 73 Logger: zaptest.NewLogger(s.T())}, 74 }, 75 registry, 76 ) 77 78 // check if scan and replay activities are registered 79 _, ok := registry.GetActivity(shadower.ScanWorkflowActivityName) 80 s.True(ok) 81 _, ok = registry.GetActivity(shadower.ReplayWorkflowActivityName) 82 s.True(ok) 83 84 // check if background context is updated with necessary components 85 userContext := shadowWorker.activityWorker.executionParameters.UserContext 86 _, ok = userContext.Value(serviceClientContextKey).(workflowserviceclient.Interface) 87 s.True(ok) 88 _, ok = userContext.Value(workflowReplayerContextKey).(*WorkflowReplayer) 89 s.True(ok) 90 91 taskList := shadowWorker.activityWorker.executionParameters.TaskList 92 s.Contains(taskList, testDomain) 93 } 94 95 func (s *shadowWorkerSuite) TestStartShadowWorker_Failed_InvalidShadowOption() { 96 shadowWorker := newShadowWorker( 97 s.mockService, 98 testDomain, 99 ShadowOptions{ 100 Mode: ShadowModeContinuous, // exit condition is not specified 101 }, 102 workerExecutionParameters{ 103 TaskList: testTaskList, 104 WorkerOptions: WorkerOptions{ 105 Logger: zaptest.NewLogger(s.T())}, 106 }, 107 newRegistry(), 108 ) 109 110 s.Error(shadowWorker.Start()) 111 } 112 113 func (s *shadowWorkerSuite) TestStartShadowWorker_Failed_DomainNotExist() { 114 s.mockService.EXPECT().DescribeDomain(gomock.Any(), &shared.DescribeDomainRequest{ 115 Name: common.StringPtr(testDomain), 116 }, callOptions()...).Return(nil, &shared.EntityNotExistsError{}).Times(1) 117 118 shadowWorker := newShadowWorker( 119 s.mockService, 120 testDomain, 121 ShadowOptions{}, 122 workerExecutionParameters{ 123 TaskList: testTaskList, 124 WorkerOptions: WorkerOptions{ 125 Logger: zaptest.NewLogger(s.T())}, 126 }, 127 newRegistry(), 128 ) 129 130 s.Error(shadowWorker.Start()) 131 } 132 133 func (s *shadowWorkerSuite) TestStartShadowWorker_Failed_TaskListNotSpecified() { 134 s.mockService.EXPECT().DescribeDomain(gomock.Any(), &shared.DescribeDomainRequest{ 135 Name: common.StringPtr(testDomain), 136 }, callOptions()...).Return(&shared.DescribeDomainResponse{}, nil).Times(1) 137 138 shadowWorker := newShadowWorker( 139 s.mockService, 140 testDomain, 141 ShadowOptions{}, 142 workerExecutionParameters{ 143 WorkerOptions: WorkerOptions{ 144 Logger: zaptest.NewLogger(s.T())}, 145 }, 146 newRegistry(), 147 ) 148 149 s.Equal(errTaskListNotSet, shadowWorker.Start()) 150 } 151 152 func (s *shadowWorkerSuite) TestStartShadowWorker_Failed_StartWorkflowError() { 153 s.mockService.EXPECT().DescribeDomain(gomock.Any(), &shared.DescribeDomainRequest{ 154 Name: common.StringPtr(testDomain), 155 }, callOptions()...).Return(&shared.DescribeDomainResponse{}, nil).Times(1) 156 // first return a retryable error to check if retry policy is configured 157 s.mockService.EXPECT().StartWorkflowExecution(gomock.Any(), gomock.Any(), callOptions()...).Return(nil, &shared.InternalServiceError{}).Times(1) 158 // then return a non-retryable error 159 s.mockService.EXPECT().StartWorkflowExecution(gomock.Any(), gomock.Any(), callOptions()...).Return(nil, &shared.BadRequestError{}).Times(1) 160 161 shadowWorker := newShadowWorker( 162 s.mockService, 163 testDomain, 164 ShadowOptions{}, 165 workerExecutionParameters{ 166 TaskList: testTaskList, 167 WorkerOptions: WorkerOptions{ 168 Logger: zaptest.NewLogger(s.T())}, 169 }, 170 newRegistry(), 171 ) 172 173 s.Error(shadowWorker.Start()) 174 } 175 176 func (s *shadowWorkerSuite) TestStartShadowWorker_Succeed() { 177 workflowQuery := "workflow query string" 178 samplingRate := 0.5 179 concurrency := 10 180 shadowMode := ShadowModeContinuous 181 exitCondition := ShadowExitCondition{ 182 ShadowCount: 100, 183 } 184 185 var startRequest *shared.StartWorkflowExecutionRequest 186 s.mockService.EXPECT().DescribeDomain(gomock.Any(), &shared.DescribeDomainRequest{ 187 Name: common.StringPtr(testDomain), 188 }, callOptions()...).Return(&shared.DescribeDomainResponse{}, nil).Times(1) 189 s.mockService.EXPECT().DescribeDomain(gomock.Any(), &shared.DescribeDomainRequest{ 190 Name: common.StringPtr(shadower.LocalDomainName), 191 }, callOptions()...).Return(&shared.DescribeDomainResponse{}, nil).Times(1) 192 s.mockService.EXPECT().StartWorkflowExecution(gomock.Any(), gomock.Any(), callOptions()...).DoAndReturn( 193 func(_ context.Context, request *shared.StartWorkflowExecutionRequest, _ ...yarpc.CallOption) (*shared.StartWorkflowExecutionResponse, error) { 194 startRequest = request 195 return nil, &shared.WorkflowExecutionAlreadyStartedError{} 196 }, 197 ).Times(1) 198 199 shadowWorker := newShadowWorker( 200 s.mockService, 201 testDomain, 202 ShadowOptions{ 203 WorkflowQuery: workflowQuery, 204 SamplingRate: samplingRate, 205 Mode: shadowMode, 206 ExitCondition: exitCondition, 207 Concurrency: concurrency, 208 }, 209 workerExecutionParameters{ 210 TaskList: testTaskList, 211 WorkerOptions: WorkerOptions{ 212 Logger: zaptest.NewLogger(s.T())}, 213 }, 214 newRegistry(), 215 ) 216 217 s.NoError(shadowWorker.Start()) 218 shadowWorker.Stop() 219 220 s.Equal(shadower.LocalDomainName, startRequest.GetDomain()) 221 s.Equal(testDomain+shadower.WorkflowIDSuffix, startRequest.GetWorkflowId()) 222 s.Equal(shadower.WorkflowName, startRequest.WorkflowType.GetName()) 223 s.Equal(shadower.TaskList, startRequest.TaskList.GetName()) 224 s.NotZero(startRequest.GetExecutionStartToCloseTimeoutSeconds()) 225 s.Equal(shared.WorkflowIdReusePolicyAllowDuplicate, startRequest.GetWorkflowIdReusePolicy()) 226 227 var workflowParams shadower.WorkflowParams 228 getDefaultDataConverter().FromData(startRequest.Input, &workflowParams) 229 s.Equal(testDomain, workflowParams.GetDomain()) 230 s.Equal(generateShadowTaskList(testDomain, testTaskList), workflowParams.GetTaskList()) 231 s.Equal(workflowQuery, workflowParams.GetWorkflowQuery()) 232 s.Equal(samplingRate, workflowParams.GetSamplingRate()) 233 s.Equal(shadowMode.toThriftPtr(), workflowParams.ShadowMode) 234 s.Equal(exitCondition.toThriftPtr(), workflowParams.ExitCondition) 235 s.Equal(int32(concurrency), workflowParams.GetConcurrency()) 236 }