go.uber.org/cadence@v1.2.9/internal/internal_worker_test.go (about) 1 // Copyright (c) 2017-2020 Uber Technologies Inc. 2 // Portions of the Software are attributed to Copyright (c) 2020 Temporal Technologies Inc. 3 // 4 // Permission is hereby granted, free of charge, to any person obtaining a copy 5 // of this software and associated documentation files (the "Software"), to deal 6 // in the Software without restriction, including without limitation the rights 7 // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 8 // copies of the Software, and to permit persons to whom the Software is 9 // furnished to do so, subject to the following conditions: 10 // 11 // The above copyright notice and this permission notice shall be included in 12 // all copies or substantial portions of the Software. 13 // 14 // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 15 // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 16 // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 17 // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 18 // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 19 // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 20 // THE SOFTWARE. 21 22 package internal 23 24 import ( 25 "context" 26 "errors" 27 "os" 28 "reflect" 29 "sync" 30 "testing" 31 "time" 32 33 "github.com/golang/mock/gomock" 34 "github.com/opentracing/opentracing-go" 35 "github.com/stretchr/testify/assert" 36 "github.com/stretchr/testify/require" 37 "github.com/stretchr/testify/suite" 38 "github.com/uber-go/tally" 39 "go.uber.org/yarpc" 40 "go.uber.org/zap" 41 "go.uber.org/zap/zaptest" 42 43 "go.uber.org/cadence/.gen/go/cadence/workflowservicetest" 44 "go.uber.org/cadence/.gen/go/shared" 45 "go.uber.org/cadence/internal/common" 46 ) 47 48 func testInternalWorkerRegister(r *registry) { 49 r.RegisterWorkflowWithOptions( 50 sampleWorkflowExecute, 51 RegisterWorkflowOptions{Name: "sampleWorkflowExecute"}, 52 ) 53 r.RegisterActivity(testActivityByteArgs) 54 r.RegisterActivityWithOptions( 55 testActivityMultipleArgs, 56 RegisterActivityOptions{Name: "testActivityMultipleArgs"}, 57 ) 58 r.RegisterActivity(testActivityMultipleArgsWithStruct) 59 r.RegisterActivity(testActivityReturnString) 60 r.RegisterActivity(testActivityReturnEmptyString) 61 r.RegisterActivity(testActivityReturnEmptyStruct) 62 63 r.RegisterActivity(testActivityNoResult) 64 r.RegisterActivity(testActivityNoContextArg) 65 r.RegisterActivity(testActivityReturnByteArray) 66 r.RegisterActivity(testActivityReturnInt) 67 r.RegisterActivity(testActivityReturnNilStructPtr) 68 r.RegisterActivity(testActivityReturnStructPtr) 69 r.RegisterActivity(testActivityReturnNilStructPtrPtr) 70 r.RegisterActivity(testActivityReturnStructPtrPtr) 71 } 72 73 func testInternalWorkerRegisterWithTestEnv(env *TestWorkflowEnvironment) { 74 env.RegisterWorkflowWithOptions( 75 sampleWorkflowExecute, 76 RegisterWorkflowOptions{Name: "sampleWorkflowExecute"}, 77 ) 78 env.RegisterActivity(testActivityByteArgs) 79 env.RegisterActivityWithOptions( 80 testActivityMultipleArgs, 81 RegisterActivityOptions{Name: "testActivityMultipleArgs"}, 82 ) 83 env.RegisterActivity(testActivityMultipleArgsWithStruct) 84 env.RegisterActivity(testActivityReturnString) 85 env.RegisterActivity(testActivityReturnEmptyString) 86 env.RegisterActivity(testActivityReturnEmptyStruct) 87 88 env.RegisterActivity(testActivityNoResult) 89 env.RegisterActivity(testActivityNoContextArg) 90 env.RegisterActivity(testActivityReturnByteArray) 91 env.RegisterActivity(testActivityReturnInt) 92 env.RegisterActivity(testActivityReturnNilStructPtr) 93 env.RegisterActivity(testActivityReturnStructPtr) 94 env.RegisterActivity(testActivityReturnNilStructPtrPtr) 95 env.RegisterActivity(testActivityReturnStructPtrPtr) 96 } 97 98 type internalWorkerTestSuite struct { 99 suite.Suite 100 mockCtrl *gomock.Controller 101 service *workflowservicetest.MockClient 102 registry *registry 103 } 104 105 func TestInternalWorkerTestSuite(t *testing.T) { 106 s := &internalWorkerTestSuite{ 107 registry: newRegistry(), 108 } 109 testInternalWorkerRegister(s.registry) 110 suite.Run(t, s) 111 } 112 113 func (s *internalWorkerTestSuite) SetupTest() { 114 s.mockCtrl = gomock.NewController(s.T()) 115 s.service = workflowservicetest.NewMockClient(s.mockCtrl) 116 } 117 118 func (s *internalWorkerTestSuite) TearDownTest() { 119 s.mockCtrl.Finish() // assert mock’s expectations 120 } 121 122 func getTestLogger(t *testing.T) *zap.Logger { 123 return zaptest.NewLogger(t) 124 } 125 126 func (s *internalWorkerTestSuite) testDecisionTaskHandlerHelper(params workerExecutionParameters) { 127 taskList := "taskList1" 128 testEvents := []*shared.HistoryEvent{ 129 createTestEventWorkflowExecutionStarted(1, &shared.WorkflowExecutionStartedEventAttributes{ 130 TaskList: &shared.TaskList{Name: common.StringPtr(taskList)}, 131 Input: testEncodeFunctionArgs(s.T(), params.DataConverter), 132 }), 133 createTestEventDecisionTaskScheduled(2, &shared.DecisionTaskScheduledEventAttributes{}), 134 createTestEventDecisionTaskStarted(3), 135 } 136 137 workflowType := "sampleWorkflowExecute" 138 workflowID := "testID" 139 runID := "testRunID" 140 141 task := &shared.PollForDecisionTaskResponse{ 142 WorkflowExecution: &shared.WorkflowExecution{WorkflowId: &workflowID, RunId: &runID}, 143 WorkflowType: &shared.WorkflowType{Name: &workflowType}, 144 History: &shared.History{Events: testEvents}, 145 PreviousStartedEventId: common.Int64Ptr(0), 146 } 147 148 r := newWorkflowTaskHandler(testDomain, params, nil, s.registry) 149 _, err := r.ProcessWorkflowTask(&workflowTask{task: task}, nil) 150 s.NoError(err) 151 } 152 153 func (s *internalWorkerTestSuite) TestDecisionTaskHandler() { 154 params := workerExecutionParameters{ 155 WorkerOptions: WorkerOptions{ 156 Identity: "identity", 157 Logger: getTestLogger(s.T())}, 158 } 159 s.testDecisionTaskHandlerHelper(params) 160 } 161 162 func (s *internalWorkerTestSuite) TestDecisionTaskHandler_WithDataConverter() { 163 params := workerExecutionParameters{ 164 WorkerOptions: WorkerOptions{ 165 Identity: "identity", 166 Logger: getTestLogger(s.T()), 167 DataConverter: newTestDataConverter()}, 168 } 169 s.testDecisionTaskHandlerHelper(params) 170 } 171 172 // testSampleWorkflow 173 func sampleWorkflowExecute(ctx Context, input []byte) (result []byte, err error) { 174 ExecuteActivity(ctx, testActivityByteArgs, input) 175 ExecuteActivity(ctx, testActivityMultipleArgs, 2, []string{"test"}, true) 176 ExecuteActivity(ctx, testActivityMultipleArgsWithStruct, -8, newTestActivityArg()) 177 return []byte("Done"), nil 178 } 179 180 // test activity1 181 func testActivityByteArgs(ctx context.Context, input []byte) ([]byte, error) { 182 GetActivityLogger(ctx).Info("Executing Activity1") 183 return nil, nil 184 } 185 186 // test testActivityMultipleArgs 187 func testActivityMultipleArgs(ctx context.Context, _ int, _ []string, _ bool) ([]byte, error) { 188 GetActivityLogger(ctx).Info("Executing Activity2") 189 return nil, nil 190 } 191 192 // test testActivityMultipleArgsWithStruct 193 func testActivityMultipleArgsWithStruct(ctx context.Context, i int, s testActivityArg) ([]byte, error) { 194 GetActivityLogger(ctx).Sugar().Infof("Executing testActivityMultipleArgsWithStruct: %d, %v\n", i, s) 195 return nil, nil 196 } 197 198 func (s *internalWorkerTestSuite) TestCreateWorker() { 199 worker := createWorkerWithThrottle(s.T(), s.service, 500, WorkerOptions{}) 200 err := worker.Start() 201 require.NoError(s.T(), err) 202 time.Sleep(time.Millisecond * 200) 203 worker.Stop() 204 } 205 206 func (s *internalWorkerTestSuite) TestCreateWorker_WithDataConverter() { 207 worker := createWorkerWithDataConverter(s.T(), s.service) 208 err := worker.Start() 209 require.NoError(s.T(), err) 210 time.Sleep(time.Millisecond * 200) 211 worker.Stop() 212 } 213 214 func (s *internalWorkerTestSuite) TestCreateShadowWorker() { 215 worker := createShadowWorker(s.T(), s.service, &ShadowOptions{}) 216 s.Nil(worker.workflowWorker) 217 s.Nil(worker.activityWorker) 218 s.Nil(worker.locallyDispatchedActivityWorker) 219 s.Nil(worker.sessionWorker) 220 } 221 222 func (s *internalWorkerTestSuite) TestCreateWorker_WithAutoScaler() { 223 worker := createWorkerWithAutoscaler(s.T(), s.service) 224 err := worker.Start() 225 require.NoError(s.T(), err) 226 time.Sleep(time.Millisecond * 200) 227 worker.Stop() 228 } 229 230 func (s *internalWorkerTestSuite) TestCreateWorker_WithStrictNonDeterminism() { 231 worker := createWorkerWithStrictNonDeterminismDisabled(s.T(), s.service) 232 err := worker.Start() 233 require.NoError(s.T(), err) 234 time.Sleep(time.Millisecond * 200) 235 worker.Stop() 236 } 237 238 func (s *internalWorkerTestSuite) TestCreateWorker_WithHost() { 239 worker := createWorkerWithHost(s.T(), s.service) 240 err := worker.Start() 241 require.NoError(s.T(), err) 242 time.Sleep(time.Millisecond * 200) 243 assert.Equal(s.T(), "test_host", worker.activityWorker.worker.options.host) 244 assert.Equal(s.T(), "test_host", worker.workflowWorker.worker.options.host) 245 worker.Stop() 246 } 247 248 func (s *internalWorkerTestSuite) TestCreateWorkerRun() { 249 // Create service endpoint 250 mockCtrl := gomock.NewController(s.T()) 251 service := workflowservicetest.NewMockClient(mockCtrl) 252 253 worker := createWorker(s.T(), service) 254 var wg sync.WaitGroup 255 wg.Add(1) 256 go func() { 257 defer wg.Done() 258 worker.Run() 259 }() 260 time.Sleep(time.Millisecond * 200) 261 p, err := os.FindProcess(os.Getpid()) 262 assert.NoError(s.T(), err) 263 assert.NoError(s.T(), p.Signal(os.Interrupt)) 264 wg.Wait() 265 } 266 267 func (s *internalWorkerTestSuite) TestNoActivitiesOrWorkflows() { 268 t := s.T() 269 w := createWorker(s.T(), s.service) 270 w.registry = newRegistry() 271 assert.Empty(t, w.registry.getRegisteredActivities()) 272 assert.Empty(t, w.registry.GetRegisteredWorkflowTypes()) 273 assert.NoError(t, w.Start()) 274 } 275 276 func (s *internalWorkerTestSuite) TestWorkerStartFailsWithInvalidDomain() { 277 t := s.T() 278 testCases := []struct { 279 domainErr error 280 isErrFatal bool 281 }{ 282 {&shared.EntityNotExistsError{}, true}, 283 {&shared.BadRequestError{}, true}, 284 {&shared.InternalServiceError{}, false}, 285 {errors.New("unknown"), false}, 286 } 287 288 mockCtrl := gomock.NewController(t) 289 290 for _, tc := range testCases { 291 service := workflowservicetest.NewMockClient(mockCtrl) 292 service.EXPECT().DescribeDomain(gomock.Any(), gomock.Any(), callOptions()...).Return(nil, tc.domainErr).Do( 293 func(ctx context.Context, request *shared.DescribeDomainRequest, opts ...yarpc.CallOption) { 294 // log 295 }).Times(2) 296 297 worker := createWorker(s.T(), service) 298 if tc.isErrFatal { 299 err := worker.Start() 300 assert.Error(t, err, "worker.start() MUST fail when domain is invalid") 301 errC := make(chan error) 302 go func() { errC <- worker.Run() }() 303 select { 304 case e := <-errC: 305 assert.Error(t, e, "worker.Run() MUST fail when domain is invalid") 306 case <-time.After(time.Second): 307 assert.Fail(t, "worker.Run() MUST fail when domain is invalid") 308 } 309 continue 310 } 311 err := worker.Start() 312 assert.NoError(t, err, "worker.Start() failed unexpectedly") 313 worker.Stop() 314 } 315 } 316 317 func (s *internalWorkerTestSuite) TestStartShadowWorkerFailWithInvalidOptions() { 318 invalidOptions := []*ShadowOptions{ 319 { 320 Mode: ShadowModeContinuous, 321 }, 322 { 323 WorkflowQuery: "workflow query", 324 WorkflowTypes: []string{"workflowTypeName"}, 325 }, 326 } 327 328 for _, opt := range invalidOptions { 329 worker := createShadowWorker(s.T(), s.service, opt) 330 err := worker.Start() 331 assert.Error(s.T(), err, "worker.Start() should fail given invalid shadow options") 332 } 333 } 334 335 func ofPollForActivityTaskRequest(tps float64) gomock.Matcher { 336 return &mockPollForActivityTaskRequest{tps: tps} 337 } 338 339 type mockPollForActivityTaskRequest struct { 340 tps float64 341 } 342 343 func (m *mockPollForActivityTaskRequest) Matches(x interface{}) bool { 344 v, ok := x.(*shared.PollForActivityTaskRequest) 345 if !ok { 346 return false 347 } 348 return *(v.TaskListMetadata.MaxTasksPerSecond) == m.tps 349 } 350 351 func (m *mockPollForActivityTaskRequest) String() string { 352 return "PollForActivityTaskRequest" 353 } 354 355 func createWorker( 356 t *testing.T, 357 service *workflowservicetest.MockClient, 358 ) *aggregatedWorker { 359 return createWorkerWithThrottle(t, service, 0, WorkerOptions{}) 360 } 361 362 func createShadowWorker( 363 t *testing.T, 364 service *workflowservicetest.MockClient, 365 shadowOptions *ShadowOptions, 366 ) *aggregatedWorker { 367 return createWorkerWithThrottle(t, service, 0, WorkerOptions{ 368 EnableShadowWorker: true, 369 ShadowOptions: *shadowOptions, 370 }) 371 } 372 373 func createWorkerWithThrottle( 374 t *testing.T, 375 service *workflowservicetest.MockClient, 376 activitiesPerSecond float64, 377 workerOptions WorkerOptions, 378 ) *aggregatedWorker { 379 domain := "testDomain" 380 domainStatus := shared.DomainStatusRegistered 381 domainDesc := &shared.DescribeDomainResponse{ 382 DomainInfo: &shared.DomainInfo{ 383 Name: &domain, 384 Status: &domainStatus, 385 }, 386 } 387 // mocks 388 service.EXPECT().DescribeDomain(gomock.Any(), gomock.Any(), callOptions()...).Return(domainDesc, nil).Do( 389 func(ctx context.Context, request *shared.DescribeDomainRequest, opts ...yarpc.CallOption) { 390 // log 391 }).AnyTimes() 392 393 activityTask := &shared.PollForActivityTaskResponse{} 394 expectedActivitiesPerSecond := activitiesPerSecond 395 if expectedActivitiesPerSecond == 0.0 { 396 expectedActivitiesPerSecond = defaultTaskListActivitiesPerSecond 397 } 398 service.EXPECT().PollForActivityTask( 399 gomock.Any(), ofPollForActivityTaskRequest(expectedActivitiesPerSecond), callOptions()..., 400 ).Return(activityTask, nil).AnyTimes() 401 service.EXPECT().RespondActivityTaskCompleted(gomock.Any(), gomock.Any(), callOptions()...).Return(nil).AnyTimes() 402 403 decisionTask := &shared.PollForDecisionTaskResponse{} 404 service.EXPECT().PollForDecisionTask(gomock.Any(), gomock.Any(), callOptions()...).Return(decisionTask, nil).AnyTimes() 405 service.EXPECT().RespondDecisionTaskCompleted(gomock.Any(), gomock.Any(), callOptions()...).Return(nil, nil).AnyTimes() 406 407 // Configure worker options. 408 workerOptions.WorkerActivitiesPerSecond = 20 409 workerOptions.TaskListActivitiesPerSecond = activitiesPerSecond 410 workerOptions.Logger = zaptest.NewLogger(t) 411 workerOptions.EnableSessionWorker = true 412 413 // Start Worker. 414 worker := NewWorker( 415 service, 416 domain, 417 "testGroupName2", 418 workerOptions) 419 return worker 420 } 421 422 func createWorkerWithDataConverter( 423 t *testing.T, 424 service *workflowservicetest.MockClient, 425 ) *aggregatedWorker { 426 return createWorkerWithThrottle(t, service, 0, WorkerOptions{DataConverter: newTestDataConverter()}) 427 } 428 429 func createWorkerWithAutoscaler( 430 t *testing.T, 431 service *workflowservicetest.MockClient, 432 ) *aggregatedWorker { 433 return createWorkerWithThrottle(t, service, 0, WorkerOptions{FeatureFlags: FeatureFlags{PollerAutoScalerEnabled: true}}) 434 } 435 436 func createWorkerWithStrictNonDeterminismDisabled( 437 t *testing.T, 438 service *workflowservicetest.MockClient, 439 ) *aggregatedWorker { 440 return createWorkerWithThrottle(t, service, 0, WorkerOptions{WorkerBugPorts: WorkerBugPorts{DisableStrictNonDeterminismCheck: true}}) 441 } 442 443 func createWorkerWithHost( 444 t *testing.T, 445 service *workflowservicetest.MockClient, 446 ) *aggregatedWorker { 447 return createWorkerWithThrottle(t, service, 0, WorkerOptions{Host: "test_host"}) 448 } 449 450 func (s *internalWorkerTestSuite) testCompleteActivityHelper(opt *ClientOptions) { 451 t := s.T() 452 mockService := s.service 453 domain := "testDomain" 454 wfClient := NewClient(mockService, domain, opt) 455 var completedRequest, canceledRequest, failedRequest interface{} 456 mockService.EXPECT().RespondActivityTaskCompleted(gomock.Any(), gomock.Any(), callOptions()...).Return(nil).Do( 457 func(ctx context.Context, request *shared.RespondActivityTaskCompletedRequest, opts ...yarpc.CallOption) { 458 completedRequest = request 459 }) 460 mockService.EXPECT().RespondActivityTaskCanceled(gomock.Any(), gomock.Any(), callOptions()...).Return(nil).Do( 461 func(ctx context.Context, request *shared.RespondActivityTaskCanceledRequest, opts ...yarpc.CallOption) { 462 canceledRequest = request 463 }) 464 mockService.EXPECT().RespondActivityTaskFailed(gomock.Any(), gomock.Any(), callOptions()...).Return(nil).Do( 465 func(ctx context.Context, request *shared.RespondActivityTaskFailedRequest, opts ...yarpc.CallOption) { 466 failedRequest = request 467 }) 468 469 wfClient.CompleteActivity(context.Background(), []byte("task-token"), nil, nil) 470 require.NotNil(t, completedRequest) 471 472 wfClient.CompleteActivity(context.Background(), []byte("task-token"), nil, NewCanceledError()) 473 require.NotNil(t, canceledRequest) 474 475 wfClient.CompleteActivity(context.Background(), []byte("task-token"), nil, errors.New("")) 476 require.NotNil(t, failedRequest) 477 } 478 479 func (s *internalWorkerTestSuite) TestCompleteActivity() { 480 s.testCompleteActivityHelper(nil) 481 } 482 483 func (s *internalWorkerTestSuite) TestCompleteActivity_WithDataConverter() { 484 opt := &ClientOptions{DataConverter: newTestDataConverter()} 485 s.testCompleteActivityHelper(opt) 486 } 487 488 func (s *internalWorkerTestSuite) TestCompleteActivityById() { 489 t := s.T() 490 mockService := s.service 491 domain := "testDomain" 492 wfClient := NewClient(mockService, domain, nil) 493 var completedRequest, canceledRequest, failedRequest interface{} 494 mockService.EXPECT().RespondActivityTaskCompletedByID(gomock.Any(), gomock.Any(), callOptions()...).Return(nil).Do( 495 func(ctx context.Context, request *shared.RespondActivityTaskCompletedByIDRequest, opts ...yarpc.CallOption) { 496 completedRequest = request 497 }) 498 mockService.EXPECT().RespondActivityTaskCanceledByID(gomock.Any(), gomock.Any(), callOptions()...).Return(nil).Do( 499 func(ctx context.Context, request *shared.RespondActivityTaskCanceledByIDRequest, opts ...yarpc.CallOption) { 500 canceledRequest = request 501 }) 502 mockService.EXPECT().RespondActivityTaskFailedByID(gomock.Any(), gomock.Any(), callOptions()...).Return(nil).Do( 503 func(ctx context.Context, request *shared.RespondActivityTaskFailedByIDRequest, opts ...yarpc.CallOption) { 504 failedRequest = request 505 }) 506 507 workflowID := "wid" 508 runID := "" 509 activityID := "aid" 510 511 wfClient.CompleteActivityByID(context.Background(), domain, workflowID, runID, activityID, nil, nil) 512 require.NotNil(t, completedRequest) 513 514 wfClient.CompleteActivityByID(context.Background(), domain, workflowID, runID, activityID, nil, NewCanceledError()) 515 require.NotNil(t, canceledRequest) 516 517 wfClient.CompleteActivityByID(context.Background(), domain, workflowID, runID, activityID, nil, errors.New("")) 518 require.NotNil(t, failedRequest) 519 } 520 521 func (s *internalWorkerTestSuite) TestRecordActivityHeartbeat() { 522 domain := "testDomain" 523 wfClient := NewClient(s.service, domain, nil) 524 var heartbeatRequest *shared.RecordActivityTaskHeartbeatRequest 525 cancelRequested := false 526 heartbeatResponse := shared.RecordActivityTaskHeartbeatResponse{CancelRequested: &cancelRequested} 527 s.service.EXPECT().RecordActivityTaskHeartbeat(gomock.Any(), gomock.Any(), callOptions()...).Return(&heartbeatResponse, nil). 528 Do(func(ctx context.Context, request *shared.RecordActivityTaskHeartbeatRequest, opts ...yarpc.CallOption) { 529 heartbeatRequest = request 530 }).Times(2) 531 532 wfClient.RecordActivityHeartbeat(context.Background(), nil) 533 wfClient.RecordActivityHeartbeat(context.Background(), nil, "testStack", "customerObjects", 4) 534 require.NotNil(s.T(), heartbeatRequest) 535 } 536 537 func (s *internalWorkerTestSuite) TestRecordActivityHeartbeat_WithDataConverter() { 538 t := s.T() 539 domain := "testDomain" 540 dc := newTestDataConverter() 541 opt := &ClientOptions{DataConverter: dc} 542 wfClient := NewClient(s.service, domain, opt) 543 var heartbeatRequest *shared.RecordActivityTaskHeartbeatRequest 544 cancelRequested := false 545 heartbeatResponse := shared.RecordActivityTaskHeartbeatResponse{CancelRequested: &cancelRequested} 546 detail1 := "testStack" 547 detail2 := testStruct{"abc", 123} 548 detail3 := 4 549 encodedDetail, err := dc.ToData(detail1, detail2, detail3) 550 require.Nil(t, err) 551 s.service.EXPECT().RecordActivityTaskHeartbeat(gomock.Any(), gomock.Any(), callOptions()...).Return(&heartbeatResponse, nil). 552 Do(func(ctx context.Context, request *shared.RecordActivityTaskHeartbeatRequest, opts ...yarpc.CallOption) { 553 heartbeatRequest = request 554 require.Equal(t, encodedDetail, request.Details) 555 }).Times(1) 556 557 wfClient.RecordActivityHeartbeat(context.Background(), nil, detail1, detail2, detail3) 558 require.NotNil(t, heartbeatRequest) 559 } 560 561 func (s *internalWorkerTestSuite) TestRecordActivityHeartbeatByID() { 562 domain := "testDomain" 563 wfClient := NewClient(s.service, domain, nil) 564 var heartbeatRequest *shared.RecordActivityTaskHeartbeatByIDRequest 565 cancelRequested := false 566 heartbeatResponse := shared.RecordActivityTaskHeartbeatResponse{CancelRequested: &cancelRequested} 567 s.service.EXPECT().RecordActivityTaskHeartbeatByID(gomock.Any(), gomock.Any(), callOptions()...).Return(&heartbeatResponse, nil). 568 Do(func(ctx context.Context, request *shared.RecordActivityTaskHeartbeatByIDRequest, opts ...yarpc.CallOption) { 569 heartbeatRequest = request 570 }).Times(2) 571 572 wfClient.RecordActivityHeartbeatByID(context.Background(), domain, "wid", "rid", "aid") 573 wfClient.RecordActivityHeartbeatByID(context.Background(), domain, "wid", "rid", "aid", 574 "testStack", "customerObjects", 4) 575 require.NotNil(s.T(), heartbeatRequest) 576 } 577 578 type activitiesCallingOptionsWorkflow struct { 579 t *testing.T 580 } 581 582 func (w activitiesCallingOptionsWorkflow) Execute(ctx Context, input []byte) (result []byte, err error) { 583 ao := ActivityOptions{ 584 ScheduleToStartTimeout: 10 * time.Second, 585 StartToCloseTimeout: 5 * time.Second, 586 } 587 ctx = WithActivityOptions(ctx, ao) 588 589 // By functions. 590 err = ExecuteActivity(ctx, testActivityByteArgs, input).Get(ctx, nil) 591 require.NoError(w.t, err, err) 592 593 err = ExecuteActivity(ctx, testActivityMultipleArgs, 2, []string{"test"}, true).Get(ctx, nil) 594 require.NoError(w.t, err, err) 595 596 err = ExecuteActivity(ctx, testActivityMultipleArgsWithStruct, -8, newTestActivityArg()).Get(ctx, nil) 597 require.NoError(w.t, err, err) 598 599 err = ExecuteActivity(ctx, testActivityNoResult, 2, "test").Get(ctx, nil) 600 require.NoError(w.t, err, err) 601 602 err = ExecuteActivity(ctx, testActivityNoContextArg, 2, "test").Get(ctx, nil) 603 require.NoError(w.t, err, err) 604 605 f := ExecuteActivity(ctx, testActivityReturnByteArray) 606 var r []byte 607 err = f.Get(ctx, &r) 608 require.NoError(w.t, err, err) 609 require.Equal(w.t, []byte("testActivity"), r) 610 611 f = ExecuteActivity(ctx, testActivityReturnInt) 612 var rInt int 613 err = f.Get(ctx, &rInt) 614 require.NoError(w.t, err, err) 615 require.Equal(w.t, 5, rInt) 616 617 f = ExecuteActivity(ctx, testActivityReturnString) 618 var rString string 619 err = f.Get(ctx, &rString) 620 621 require.NoError(w.t, err, err) 622 require.Equal(w.t, "testActivity", rString) 623 624 f = ExecuteActivity(ctx, testActivityReturnEmptyString) 625 var r2String string 626 err = f.Get(ctx, &r2String) 627 require.NoError(w.t, err, err) 628 require.Equal(w.t, "", r2String) 629 630 f = ExecuteActivity(ctx, testActivityReturnEmptyStruct) 631 var r2Struct testActivityResult 632 err = f.Get(ctx, &r2Struct) 633 require.NoError(w.t, err, err) 634 require.Equal(w.t, testActivityResult{}, r2Struct) 635 636 f = ExecuteActivity(ctx, testActivityReturnNilStructPtr) 637 var rStructPtr *testActivityResult 638 err = f.Get(ctx, &rStructPtr) 639 require.NoError(w.t, err, err) 640 require.True(w.t, rStructPtr == nil) 641 642 f = ExecuteActivity(ctx, testActivityReturnStructPtr) 643 err = f.Get(ctx, &rStructPtr) 644 require.NoError(w.t, err, err) 645 require.Equal(w.t, *rStructPtr, testActivityResult{Index: 10}) 646 647 f = ExecuteActivity(ctx, testActivityReturnNilStructPtrPtr) 648 var rStruct2Ptr **testActivityResult 649 err = f.Get(ctx, &rStruct2Ptr) 650 require.NoError(w.t, err, err) 651 require.True(w.t, rStruct2Ptr == nil) 652 653 f = ExecuteActivity(ctx, testActivityReturnStructPtrPtr) 654 err = f.Get(ctx, &rStruct2Ptr) 655 require.NoError(w.t, err, err) 656 require.True(w.t, **rStruct2Ptr == testActivityResult{Index: 10}) 657 658 // By names. 659 err = ExecuteActivity(ctx, "go.uber.org/cadence/internal.testActivityByteArgs", input).Get(ctx, nil) 660 require.NoError(w.t, err, err) 661 662 err = ExecuteActivity(ctx, "testActivityMultipleArgs", 2, []string{"test"}, true).Get(ctx, nil) 663 require.NoError(w.t, err, err) 664 665 err = ExecuteActivity(ctx, "go.uber.org/cadence/internal.testActivityNoResult", 2, "test").Get(ctx, nil) 666 require.NoError(w.t, err, err) 667 668 err = ExecuteActivity(ctx, "go.uber.org/cadence/internal.testActivityNoContextArg", 2, "test").Get(ctx, nil) 669 require.NoError(w.t, err, err) 670 671 f = ExecuteActivity(ctx, "go.uber.org/cadence/internal.testActivityReturnString") 672 err = f.Get(ctx, &rString) 673 require.NoError(w.t, err, err) 674 require.Equal(w.t, "testActivity", rString, rString) 675 676 f = ExecuteActivity(ctx, "go.uber.org/cadence/internal.testActivityReturnEmptyString") 677 var r2sString string 678 err = f.Get(ctx, &r2String) 679 require.NoError(w.t, err, err) 680 require.Equal(w.t, "", r2sString) 681 682 f = ExecuteActivity(ctx, "go.uber.org/cadence/internal.testActivityReturnEmptyStruct") 683 err = f.Get(ctx, &r2Struct) 684 require.NoError(w.t, err, err) 685 require.Equal(w.t, testActivityResult{}, r2Struct) 686 687 return []byte("Done"), nil 688 } 689 690 // test testActivityNoResult 691 func testActivityNoResult(ctx context.Context, arg1 int, arg2 string) error { 692 return nil 693 } 694 695 // test testActivityNoContextArg 696 func testActivityNoContextArg(arg1 int, arg2 string) error { 697 return nil 698 } 699 700 // test testActivityReturnByteArray 701 func testActivityReturnByteArray() ([]byte, error) { 702 return []byte("testActivity"), nil 703 } 704 705 // testActivityReturnInt 706 func testActivityReturnInt() (int, error) { 707 return 5, nil 708 } 709 710 // testActivityReturnString 711 func testActivityReturnString() (string, error) { 712 return "testActivity", nil 713 } 714 715 // testActivityReturnEmptyString 716 func testActivityReturnEmptyString() (string, error) { 717 // Return is mocked to retrun nil from server. 718 // expect to convert it to appropriate default value. 719 return "", nil 720 } 721 722 type testActivityArg struct { 723 Index int 724 Name string 725 Data []byte 726 IndexPtr *int 727 NamePtr *string 728 DataPtr *[]byte 729 } 730 731 type testActivityResult struct { 732 Index int 733 } 734 735 func newTestActivityArg() *testActivityArg { 736 name := "JohnSmith" 737 index := 22 738 data := []byte{22, 8, 78} 739 740 return &testActivityArg{ 741 Name: name, 742 Index: index, 743 Data: data, 744 NamePtr: &name, 745 IndexPtr: &index, 746 DataPtr: &data, 747 } 748 } 749 750 // testActivityReturnEmptyStruct 751 func testActivityReturnEmptyStruct() (testActivityResult, error) { 752 // Return is mocked to retrun nil from server. 753 // expect to convert it to appropriate default value. 754 return testActivityResult{}, nil 755 } 756 func testActivityReturnNilStructPtr() (*testActivityResult, error) { 757 return nil, nil 758 } 759 func testActivityReturnStructPtr() (*testActivityResult, error) { 760 return &testActivityResult{Index: 10}, nil 761 } 762 func testActivityReturnNilStructPtrPtr() (**testActivityResult, error) { 763 return nil, nil 764 } 765 func testActivityReturnStructPtrPtr() (**testActivityResult, error) { 766 r := &testActivityResult{Index: 10} 767 return &r, nil 768 } 769 770 func TestVariousActivitySchedulingOption(t *testing.T) { 771 w := &activitiesCallingOptionsWorkflow{t: t} 772 773 testVariousActivitySchedulingOption(t, w.Execute) 774 testVariousActivitySchedulingOptionWithDataConverter(t, w.Execute) 775 } 776 777 func testVariousActivitySchedulingOption(t *testing.T, wf interface{}) { 778 env := newTestWorkflowEnv(t) 779 env.RegisterWorkflow(wf) 780 testInternalWorkerRegisterWithTestEnv(env) 781 env.ExecuteWorkflow(wf, []byte{1, 2}) 782 require.True(t, env.IsWorkflowCompleted()) 783 require.NoError(t, env.GetWorkflowError()) 784 } 785 786 func testVariousActivitySchedulingOptionWithDataConverter(t *testing.T, wf interface{}) { 787 env := newTestWorkflowEnv(t) 788 env.SetWorkerOptions(WorkerOptions{DataConverter: newTestDataConverter()}) 789 env.RegisterWorkflow(wf) 790 testInternalWorkerRegisterWithTestEnv(env) 791 env.ExecuteWorkflow(wf, []byte{1, 2}) 792 require.True(t, env.IsWorkflowCompleted()) 793 require.NoError(t, env.GetWorkflowError()) 794 } 795 796 func testWorkflowSample(ctx Context, input []byte) (result []byte, err error) { 797 return nil, nil 798 } 799 800 func testWorkflowMultipleArgs(ctx Context, arg1 int, arg2 string, arg3 bool) (result []byte, err error) { 801 return nil, nil 802 } 803 804 func testWorkflowNoArgs(ctx Context) (result []byte, err error) { 805 return nil, nil 806 } 807 808 func testWorkflowReturnInt(ctx Context) (result int, err error) { 809 return 5, nil 810 } 811 812 func testWorkflowReturnString(ctx Context, arg1 int) (result string, err error) { 813 return "Done", nil 814 } 815 816 type testWorkflowResult struct { 817 V int 818 } 819 820 func testWorkflowReturnStruct(ctx Context, arg1 int) (result testWorkflowResult, err error) { 821 return testWorkflowResult{}, nil 822 } 823 824 func testWorkflowReturnStructPtr(ctx Context, arg1 int) (result *testWorkflowResult, err error) { 825 return &testWorkflowResult{}, nil 826 } 827 828 func testWorkflowReturnStructPtrPtr(ctx Context, arg1 int) (result **testWorkflowResult, err error) { 829 return nil, nil 830 } 831 832 func TestRegisterVariousWorkflowTypes(t *testing.T) { 833 r := newRegistry() 834 r.RegisterWorkflow(testWorkflowSample) 835 r.RegisterWorkflow(testWorkflowMultipleArgs) 836 r.RegisterWorkflow(testWorkflowNoArgs) 837 r.RegisterWorkflow(testWorkflowReturnInt) 838 r.RegisterWorkflow(testWorkflowReturnString) 839 r.RegisterWorkflow(testWorkflowReturnStruct) 840 r.RegisterWorkflow(testWorkflowReturnStructPtr) 841 r.RegisterWorkflow(testWorkflowReturnStructPtrPtr) 842 } 843 844 type testErrorDetails struct { 845 T string 846 } 847 848 func testActivityErrorWithDetailsHelper(ctx context.Context, t *testing.T, dataConverter DataConverter) { 849 a1 := activityExecutor{ 850 name: "test", 851 fn: func(arg1 int) (err error) { 852 return NewCustomError("testReason", "testStringDetails") 853 }} 854 _, e := a1.Execute(ctx, testEncodeFunctionArgs(t, dataConverter, 1)) 855 require.Error(t, e) 856 errWD := e.(*CustomError) 857 require.Equal(t, "testReason", errWD.Reason()) 858 var strDetails string 859 errWD.Details(&strDetails) 860 require.Equal(t, "testStringDetails", strDetails) 861 862 a2 := activityExecutor{ 863 name: "test", 864 fn: func(arg1 int) (err error) { 865 return NewCustomError("testReason", testErrorDetails{T: "testErrorStack"}) 866 }} 867 _, e = a2.Execute(ctx, testEncodeFunctionArgs(t, dataConverter, 1)) 868 require.Error(t, e) 869 errWD = e.(*CustomError) 870 require.Equal(t, "testReason", errWD.Reason()) 871 var td testErrorDetails 872 errWD.Details(&td) 873 require.Equal(t, testErrorDetails{T: "testErrorStack"}, td) 874 875 a3 := activityExecutor{ 876 name: "test", 877 fn: func(arg1 int) (result string, err error) { 878 return "testResult", NewCustomError("testReason", testErrorDetails{T: "testErrorStack3"}) 879 }} 880 encResult, e := a3.Execute(ctx, testEncodeFunctionArgs(t, dataConverter, 1)) 881 var result string 882 err := dataConverter.FromData(encResult, &result) 883 require.NoError(t, err) 884 require.Equal(t, "testResult", result) 885 require.Error(t, e) 886 errWD = e.(*CustomError) 887 require.Equal(t, "testReason", errWD.Reason()) 888 errWD.Details(&td) 889 require.Equal(t, testErrorDetails{T: "testErrorStack3"}, td) 890 891 a4 := activityExecutor{ 892 name: "test", 893 fn: func(arg1 int) (result string, err error) { 894 return "testResult4", NewCustomError("testReason", "testMultipleString", testErrorDetails{T: "testErrorStack4"}) 895 }} 896 encResult, e = a4.Execute(ctx, testEncodeFunctionArgs(t, dataConverter, 1)) 897 err = dataConverter.FromData(encResult, &result) 898 require.NoError(t, err) 899 require.Equal(t, "testResult4", result) 900 require.Error(t, e) 901 errWD = e.(*CustomError) 902 require.Equal(t, "testReason", errWD.Reason()) 903 var ed string 904 errWD.Details(&ed, &td) 905 require.Equal(t, "testMultipleString", ed) 906 require.Equal(t, testErrorDetails{T: "testErrorStack4"}, td) 907 } 908 909 func TestActivityErrorWithDetailsWithDataConverter(t *testing.T) { 910 dc := newTestDataConverter() 911 ctx := context.WithValue(context.Background(), activityEnvContextKey, &activityEnvironment{dataConverter: dc}) 912 testActivityErrorWithDetailsHelper(ctx, t, dc) 913 } 914 915 func testActivityCancelledErrorHelper(ctx context.Context, t *testing.T, dataConverter DataConverter) { 916 a1 := activityExecutor{ 917 name: "test", 918 fn: func(arg1 int) (err error) { 919 return NewCanceledError("testCancelStringDetails") 920 }} 921 _, e := a1.Execute(ctx, testEncodeFunctionArgs(t, dataConverter, 1)) 922 require.Error(t, e) 923 errWD := e.(*CanceledError) 924 var strDetails string 925 errWD.Details(&strDetails) 926 require.Equal(t, "testCancelStringDetails", strDetails) 927 928 a2 := activityExecutor{ 929 name: "test", 930 fn: func(arg1 int) (err error) { 931 return NewCanceledError(testErrorDetails{T: "testCancelErrorStack"}) 932 }} 933 _, e = a2.Execute(ctx, testEncodeFunctionArgs(t, dataConverter, 1)) 934 require.Error(t, e) 935 errWD = e.(*CanceledError) 936 var td testErrorDetails 937 errWD.Details(&td) 938 require.Equal(t, testErrorDetails{T: "testCancelErrorStack"}, td) 939 940 a3 := activityExecutor{ 941 name: "test", 942 fn: func(arg1 int) (result string, err error) { 943 return "testResult", NewCanceledError(testErrorDetails{T: "testErrorStack3"}) 944 }} 945 encResult, e := a3.Execute(ctx, testEncodeFunctionArgs(t, dataConverter, 1)) 946 var r string 947 err := dataConverter.FromData(encResult, &r) 948 require.NoError(t, err) 949 require.Equal(t, "testResult", r) 950 require.Error(t, e) 951 errWD = e.(*CanceledError) 952 errWD.Details(&td) 953 require.Equal(t, testErrorDetails{T: "testErrorStack3"}, td) 954 955 a4 := activityExecutor{ 956 name: "test", 957 fn: func(arg1 int) (result string, err error) { 958 return "testResult4", NewCanceledError("testMultipleString", testErrorDetails{T: "testErrorStack4"}) 959 }} 960 encResult, e = a4.Execute(ctx, testEncodeFunctionArgs(t, dataConverter, 1)) 961 err = dataConverter.FromData(encResult, &r) 962 require.NoError(t, err) 963 require.Equal(t, "testResult4", r) 964 require.Error(t, e) 965 errWD = e.(*CanceledError) 966 var ed string 967 errWD.Details(&ed, &td) 968 require.Equal(t, "testMultipleString", ed) 969 require.Equal(t, testErrorDetails{T: "testErrorStack4"}, td) 970 } 971 972 func TestActivityCancelledErrorWithDataConverter(t *testing.T) { 973 dc := newTestDataConverter() 974 ctx := context.WithValue(context.Background(), activityEnvContextKey, &activityEnvironment{dataConverter: dc}) 975 testActivityCancelledErrorHelper(ctx, t, dc) 976 } 977 978 func testActivityExecutionVariousTypesHelper(ctx context.Context, t *testing.T, dataConverter DataConverter) { 979 a1 := activityExecutor{ 980 fn: func(ctx context.Context, arg1 string) (*testWorkflowResult, error) { 981 return &testWorkflowResult{V: 1}, nil 982 }} 983 encResult, e := a1.Execute(ctx, testEncodeFunctionArgs(t, dataConverter, "test")) 984 require.NoError(t, e) 985 var r *testWorkflowResult 986 err := dataConverter.FromData(encResult, &r) 987 require.NoError(t, err) 988 require.Equal(t, 1, r.V) 989 990 a2 := activityExecutor{ 991 fn: func(ctx context.Context, arg1 *testWorkflowResult) (*testWorkflowResult, error) { 992 return &testWorkflowResult{V: 2}, nil 993 }} 994 encResult, e = a2.Execute(ctx, testEncodeFunctionArgs(t, dataConverter, r)) 995 require.NoError(t, e) 996 err = dataConverter.FromData(encResult, &r) 997 require.NoError(t, err) 998 require.Equal(t, 2, r.V) 999 } 1000 1001 func TestActivityExecutionVariousTypesWithDataConverter(t *testing.T) { 1002 dc := newTestDataConverter() 1003 ctx := context.WithValue(context.Background(), activityEnvContextKey, &activityEnvironment{ 1004 dataConverter: dc, 1005 }) 1006 testActivityExecutionVariousTypesHelper(ctx, t, dc) 1007 } 1008 1009 func TestActivityNilArgs(t *testing.T) { 1010 nilErr := errors.New("nils") 1011 activityFn := func(name string, idx int, strptr *string) error { 1012 if name == "" && idx == 0 && strptr == nil { 1013 return nilErr 1014 } 1015 return nil 1016 } 1017 1018 args := []interface{}{nil, nil, nil} 1019 _, err := getValidatedActivityFunction(activityFn, args, newRegistry()) 1020 require.NoError(t, err) 1021 1022 dataConverter := getDefaultDataConverter() 1023 data, _ := encodeArgs(dataConverter, args) 1024 reflectArgs, err := decodeArgs(dataConverter, reflect.TypeOf(activityFn), data) 1025 require.NoError(t, err) 1026 1027 reflectResults := reflect.ValueOf(activityFn).Call(reflectArgs) 1028 require.Equal(t, nilErr, reflectResults[0].Interface()) 1029 } 1030 1031 func TestWorkerOptionDefaults(t *testing.T) { 1032 domain := "worker-options-test" 1033 taskList := "worker-options-tl" 1034 aggWorker := newAggregatedWorker(nil, domain, taskList, WorkerOptions{}) 1035 decisionWorker := aggWorker.workflowWorker 1036 require.True(t, decisionWorker.executionParameters.Identity != "") 1037 require.NotNil(t, decisionWorker.executionParameters.Logger) 1038 require.NotNil(t, decisionWorker.executionParameters.MetricsScope) 1039 require.Nil(t, decisionWorker.executionParameters.ContextPropagators) 1040 1041 expected := workerExecutionParameters{ 1042 TaskList: taskList, 1043 WorkerOptions: WorkerOptions{ 1044 MaxConcurrentActivityTaskPollers: defaultConcurrentPollRoutineSize, 1045 MaxConcurrentDecisionTaskPollers: defaultConcurrentPollRoutineSize, 1046 MaxConcurrentLocalActivityExecutionSize: defaultMaxConcurrentLocalActivityExecutionSize, 1047 MaxConcurrentActivityExecutionSize: defaultMaxConcurrentActivityExecutionSize, 1048 MaxConcurrentDecisionTaskExecutionSize: defaultMaxConcurrentTaskExecutionSize, 1049 WorkerActivitiesPerSecond: defaultTaskListActivitiesPerSecond, 1050 WorkerDecisionTasksPerSecond: defaultWorkerTaskExecutionRate, 1051 TaskListActivitiesPerSecond: defaultTaskListActivitiesPerSecond, 1052 WorkerLocalActivitiesPerSecond: defaultWorkerLocalActivitiesPerSecond, 1053 StickyScheduleToStartTimeout: stickyDecisionScheduleToStartTimeoutSeconds * time.Second, 1054 DataConverter: getDefaultDataConverter(), 1055 Tracer: opentracing.NoopTracer{}, 1056 Logger: decisionWorker.executionParameters.Logger, 1057 MetricsScope: decisionWorker.executionParameters.MetricsScope, 1058 Identity: decisionWorker.executionParameters.Identity}, 1059 UserContext: decisionWorker.executionParameters.UserContext, 1060 } 1061 1062 assertWorkerExecutionParamsEqual(t, expected, decisionWorker.executionParameters) 1063 1064 activityWorker := aggWorker.activityWorker 1065 require.True(t, activityWorker.executionParameters.Identity != "") 1066 require.NotNil(t, activityWorker.executionParameters.Logger) 1067 require.NotNil(t, activityWorker.executionParameters.MetricsScope) 1068 require.Nil(t, activityWorker.executionParameters.ContextPropagators) 1069 assertWorkerExecutionParamsEqual(t, expected, activityWorker.executionParameters) 1070 } 1071 1072 func TestWorkerOptionNonDefaults(t *testing.T) { 1073 domain := "worker-options-test" 1074 taskList := "worker-options-tl" 1075 1076 options := WorkerOptions{ 1077 Identity: "143@worker-options-test-1", 1078 TaskListActivitiesPerSecond: 8888, 1079 MaxConcurrentSessionExecutionSize: 3333, 1080 MaxConcurrentDecisionTaskExecutionSize: 2222, 1081 MaxConcurrentActivityExecutionSize: 1111, 1082 MaxConcurrentLocalActivityExecutionSize: 101, 1083 MaxConcurrentDecisionTaskPollers: 11, 1084 MaxConcurrentActivityTaskPollers: 12, 1085 WorkerLocalActivitiesPerSecond: 222, 1086 WorkerDecisionTasksPerSecond: 111, 1087 WorkerActivitiesPerSecond: 99, 1088 StickyScheduleToStartTimeout: 555 * time.Minute, 1089 DataConverter: &defaultDataConverter{}, 1090 BackgroundActivityContext: context.Background(), 1091 Logger: zap.NewNop(), 1092 MetricsScope: tally.NoopScope, 1093 Tracer: opentracing.NoopTracer{}, 1094 } 1095 1096 aggWorker := newAggregatedWorker(nil, domain, taskList, options) 1097 decisionWorker := aggWorker.workflowWorker 1098 require.True(t, len(decisionWorker.executionParameters.ContextPropagators) > 0) 1099 1100 expected := workerExecutionParameters{ 1101 TaskList: taskList, 1102 WorkerOptions: WorkerOptions{ 1103 MaxConcurrentActivityTaskPollers: options.MaxConcurrentActivityTaskPollers, 1104 MaxConcurrentDecisionTaskPollers: options.MaxConcurrentDecisionTaskPollers, 1105 MaxConcurrentLocalActivityExecutionSize: options.MaxConcurrentLocalActivityExecutionSize, 1106 MaxConcurrentActivityExecutionSize: options.MaxConcurrentActivityExecutionSize, 1107 MaxConcurrentDecisionTaskExecutionSize: options.MaxConcurrentDecisionTaskExecutionSize, 1108 WorkerActivitiesPerSecond: options.WorkerActivitiesPerSecond, 1109 WorkerDecisionTasksPerSecond: options.WorkerDecisionTasksPerSecond, 1110 TaskListActivitiesPerSecond: options.TaskListActivitiesPerSecond, 1111 WorkerLocalActivitiesPerSecond: options.WorkerLocalActivitiesPerSecond, 1112 StickyScheduleToStartTimeout: options.StickyScheduleToStartTimeout, 1113 DataConverter: options.DataConverter, 1114 Tracer: options.Tracer, 1115 Logger: options.Logger, 1116 MetricsScope: options.MetricsScope, 1117 Identity: options.Identity}, 1118 } 1119 1120 assertWorkerExecutionParamsEqual(t, expected, decisionWorker.executionParameters) 1121 1122 activityWorker := aggWorker.activityWorker 1123 require.True(t, len(activityWorker.executionParameters.ContextPropagators) > 0) 1124 assertWorkerExecutionParamsEqual(t, expected, activityWorker.executionParameters) 1125 } 1126 1127 func assertWorkerExecutionParamsEqual(t *testing.T, paramsA workerExecutionParameters, paramsB workerExecutionParameters) { 1128 require.Equal(t, paramsA.TaskList, paramsA.TaskList) 1129 require.Equal(t, paramsA.Identity, paramsB.Identity) 1130 require.Equal(t, paramsA.DataConverter, paramsB.DataConverter) 1131 require.Equal(t, paramsA.Tracer, paramsB.Tracer) 1132 require.Equal(t, paramsA.MaxConcurrentLocalActivityExecutionSize, paramsB.MaxConcurrentLocalActivityExecutionSize) 1133 require.Equal(t, paramsA.MaxConcurrentActivityExecutionSize, paramsB.MaxConcurrentActivityExecutionSize) 1134 require.Equal(t, paramsA.MaxConcurrentDecisionTaskExecutionSize, paramsB.MaxConcurrentDecisionTaskExecutionSize) 1135 require.Equal(t, paramsA.WorkerActivitiesPerSecond, paramsB.WorkerActivitiesPerSecond) 1136 require.Equal(t, paramsA.WorkerDecisionTasksPerSecond, paramsB.WorkerDecisionTasksPerSecond) 1137 require.Equal(t, paramsA.TaskListActivitiesPerSecond, paramsB.TaskListActivitiesPerSecond) 1138 require.Equal(t, paramsA.StickyScheduleToStartTimeout, paramsB.StickyScheduleToStartTimeout) 1139 require.Equal(t, paramsA.MaxConcurrentDecisionTaskPollers, paramsB.MaxConcurrentDecisionTaskPollers) 1140 require.Equal(t, paramsA.MaxConcurrentActivityTaskPollers, paramsB.MaxConcurrentActivityTaskPollers) 1141 require.Equal(t, paramsA.NonDeterministicWorkflowPolicy, paramsB.NonDeterministicWorkflowPolicy) 1142 require.Equal(t, paramsA.EnableLoggingInReplay, paramsB.EnableLoggingInReplay) 1143 require.Equal(t, paramsA.DisableStickyExecution, paramsB.DisableStickyExecution) 1144 } 1145 1146 /* 1147 var testWorkflowID1 = s.WorkflowExecution{WorkflowId: common.StringPtr("testWID"), RunId: common.StringPtr("runID")} 1148 var testWorkflowID2 = s.WorkflowExecution{WorkflowId: common.StringPtr("testWID2"), RunId: common.StringPtr("runID2")} 1149 var thriftEncodingTests = []encodingTest{ 1150 {&thriftEncoding{}, []interface{}{&testWorkflowID1}}, 1151 {&thriftEncoding{}, []interface{}{&testWorkflowID1, &testWorkflowID2}}, 1152 {&thriftEncoding{}, []interface{}{&testWorkflowID1, &testWorkflowID2, &testWorkflowID1}}, 1153 } 1154 1155 // TODO: Disable until thriftrw encoding support is added to cadence client.(follow up change) 1156 func _TestThriftEncoding(t *testing.T) { 1157 // Success tests. 1158 for _, et := range thriftEncodingTests { 1159 data, err := et.encoding.Marshal(et.input) 1160 require.NoError(t, err) 1161 1162 var result []interface{} 1163 for _, v := range et.input { 1164 arg := reflect.New(reflect.ValueOf(v).Type()).Interface() 1165 result = append(result, arg) 1166 } 1167 err = et.encoding.Unmarshal(data, result) 1168 require.NoError(t, err) 1169 1170 for i := 0; i < len(et.input); i++ { 1171 vat := reflect.ValueOf(result[i]).Elem().Interface() 1172 require.Equal(t, et.input[i], vat) 1173 } 1174 } 1175 1176 // Failure tests. 1177 enc := &thriftEncoding{} 1178 _, err := enc.Marshal([]interface{}{testWorkflowID1}) 1179 require.Contains(t, err.Error(), "pointer to thrift.TStruct type is required") 1180 1181 err = enc.Unmarshal([]byte("dummy"), []interface{}{testWorkflowID1}) 1182 require.Contains(t, err.Error(), "pointer to pointer thrift.TStruct type is required") 1183 1184 err = enc.Unmarshal([]byte("dummy"), []interface{}{&testWorkflowID1}) 1185 require.Contains(t, err.Error(), "pointer to pointer thrift.TStruct type is required") 1186 1187 _, err = enc.Marshal([]interface{}{testWorkflowID1, &testWorkflowID2}) 1188 require.Contains(t, err.Error(), "pointer to thrift.TStruct type is required") 1189 1190 err = enc.Unmarshal([]byte("dummy"), []interface{}{testWorkflowID1, &testWorkflowID2}) 1191 require.Contains(t, err.Error(), "pointer to pointer thrift.TStruct type is required") 1192 } 1193 */ 1194 1195 // Encode function args 1196 func testEncodeFunctionArgs(t *testing.T, dataConverter DataConverter, args ...interface{}) []byte { 1197 input, err := encodeArgs(dataConverter, args) 1198 if err != nil { 1199 t.Error(err) 1200 panic("Failed to encode arguments") 1201 } 1202 return input 1203 } 1204 1205 func TestIsNonRetriableError(t *testing.T) { 1206 tests := []struct { 1207 err error 1208 expected bool 1209 }{ 1210 { 1211 err: nil, 1212 expected: false, 1213 }, 1214 { 1215 err: &shared.ServiceBusyError{}, 1216 expected: false, 1217 }, 1218 { 1219 err: &shared.BadRequestError{}, 1220 expected: true, 1221 }, 1222 { 1223 err: &shared.ClientVersionNotSupportedError{}, 1224 expected: true, 1225 }, 1226 } 1227 1228 for _, test := range tests { 1229 require.Equal(t, test.expected, isNonRetriableError(test.err)) 1230 } 1231 } 1232 1233 func Test_augmentWorkerOptions(t *testing.T) { 1234 type args struct { 1235 options WorkerOptions 1236 } 1237 tests := []struct { 1238 name string 1239 args args 1240 want WorkerOptions 1241 }{ 1242 { 1243 name: "happy", 1244 args: args{options: WorkerOptions{ 1245 MaxConcurrentActivityExecutionSize: 3, 1246 WorkerActivitiesPerSecond: 10, 1247 MaxConcurrentLocalActivityExecutionSize: 4, 1248 WorkerLocalActivitiesPerSecond: 20, 1249 TaskListActivitiesPerSecond: 30, 1250 MaxConcurrentActivityTaskPollers: 10, 1251 MinConcurrentActivityTaskPollers: 2, 1252 MaxConcurrentDecisionTaskExecutionSize: 40, 1253 WorkerDecisionTasksPerSecond: 50, 1254 MaxConcurrentDecisionTaskPollers: 15, 1255 MinConcurrentDecisionTaskPollers: 4, 1256 PollerAutoScalerCooldown: time.Minute * 2, 1257 PollerAutoScalerTargetUtilization: 0.8, 1258 PollerAutoScalerDryRun: false, 1259 Identity: "identity", 1260 MetricsScope: tally.NoopScope, 1261 Logger: zap.NewNop(), 1262 EnableLoggingInReplay: false, 1263 DisableWorkflowWorker: false, 1264 DisableActivityWorker: false, 1265 DisableStickyExecution: false, 1266 StickyScheduleToStartTimeout: time.Minute * 4, 1267 BackgroundActivityContext: context.Background(), 1268 NonDeterministicWorkflowPolicy: NonDeterministicWorkflowPolicyBlockWorkflow, 1269 DataConverter: DefaultDataConverter, 1270 WorkerStopTimeout: time.Minute * 5, 1271 EnableSessionWorker: false, 1272 MaxConcurrentSessionExecutionSize: 80, 1273 WorkflowInterceptorChainFactories: nil, 1274 ContextPropagators: nil, 1275 Tracer: nil, 1276 EnableShadowWorker: false, 1277 ShadowOptions: ShadowOptions{}, 1278 FeatureFlags: FeatureFlags{}, 1279 Authorization: nil, 1280 }}, 1281 want: WorkerOptions{ 1282 MaxConcurrentActivityExecutionSize: 3, 1283 WorkerActivitiesPerSecond: 10, 1284 MaxConcurrentLocalActivityExecutionSize: 4, 1285 WorkerLocalActivitiesPerSecond: 20, 1286 TaskListActivitiesPerSecond: 30, 1287 MaxConcurrentActivityTaskPollers: 10, 1288 MinConcurrentActivityTaskPollers: 2, 1289 MaxConcurrentDecisionTaskExecutionSize: 40, 1290 WorkerDecisionTasksPerSecond: 50, 1291 MaxConcurrentDecisionTaskPollers: 15, 1292 MinConcurrentDecisionTaskPollers: 4, 1293 PollerAutoScalerCooldown: time.Minute * 2, 1294 PollerAutoScalerTargetUtilization: 0.8, 1295 PollerAutoScalerDryRun: false, 1296 Identity: "identity", 1297 MetricsScope: tally.NoopScope, 1298 Logger: zap.NewNop(), 1299 EnableLoggingInReplay: false, 1300 DisableWorkflowWorker: false, 1301 DisableActivityWorker: false, 1302 DisableStickyExecution: false, 1303 StickyScheduleToStartTimeout: time.Minute * 4, 1304 BackgroundActivityContext: context.Background(), 1305 NonDeterministicWorkflowPolicy: NonDeterministicWorkflowPolicyBlockWorkflow, 1306 DataConverter: DefaultDataConverter, 1307 WorkerStopTimeout: time.Minute * 5, 1308 EnableSessionWorker: false, 1309 MaxConcurrentSessionExecutionSize: 80, 1310 WorkflowInterceptorChainFactories: nil, 1311 ContextPropagators: nil, 1312 Tracer: opentracing.NoopTracer{}, 1313 EnableShadowWorker: false, 1314 ShadowOptions: ShadowOptions{}, 1315 FeatureFlags: FeatureFlags{}, 1316 Authorization: nil, 1317 }, 1318 }, 1319 { 1320 name: "empty payload", 1321 args: args{options: WorkerOptions{}}, 1322 want: WorkerOptions{ 1323 MaxConcurrentActivityExecutionSize: 1000, 1324 WorkerActivitiesPerSecond: 100000, 1325 MaxConcurrentLocalActivityExecutionSize: 1000, 1326 WorkerLocalActivitiesPerSecond: 100000, 1327 TaskListActivitiesPerSecond: 100000, 1328 MaxConcurrentActivityTaskPollers: 2, 1329 MinConcurrentActivityTaskPollers: 1, 1330 MaxConcurrentDecisionTaskExecutionSize: 1000, 1331 WorkerDecisionTasksPerSecond: 100000, 1332 MaxConcurrentDecisionTaskPollers: 2, 1333 MinConcurrentDecisionTaskPollers: 1, 1334 PollerAutoScalerCooldown: time.Minute, 1335 PollerAutoScalerTargetUtilization: 0.6, 1336 PollerAutoScalerDryRun: false, 1337 Identity: "", 1338 MetricsScope: nil, 1339 Logger: nil, 1340 EnableLoggingInReplay: false, 1341 DisableWorkflowWorker: false, 1342 DisableActivityWorker: false, 1343 DisableStickyExecution: false, 1344 StickyScheduleToStartTimeout: time.Second * 5, 1345 BackgroundActivityContext: nil, 1346 NonDeterministicWorkflowPolicy: NonDeterministicWorkflowPolicyBlockWorkflow, 1347 DataConverter: DefaultDataConverter, 1348 WorkerStopTimeout: 0, 1349 EnableSessionWorker: false, 1350 MaxConcurrentSessionExecutionSize: 1000, 1351 WorkflowInterceptorChainFactories: nil, 1352 ContextPropagators: nil, 1353 Tracer: opentracing.NoopTracer{}, 1354 EnableShadowWorker: false, 1355 ShadowOptions: ShadowOptions{}, 1356 FeatureFlags: FeatureFlags{}, 1357 Authorization: nil, 1358 }, 1359 }, 1360 } 1361 for _, tt := range tests { 1362 t.Run(tt.name, func(t *testing.T) { 1363 assert.Equalf(t, tt.want, AugmentWorkerOptions(tt.args.options), "AugmentWorkerOptions(%v)", tt.args.options) 1364 }) 1365 } 1366 }