go.uber.org/cadence@v1.2.9/internal/internal_workflow_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 internal 22 23 import ( 24 "context" 25 "errors" 26 "fmt" 27 "strings" 28 "testing" 29 "time" 30 31 "github.com/stretchr/testify/mock" 32 "github.com/stretchr/testify/require" 33 "github.com/stretchr/testify/suite" 34 "go.uber.org/zap/zaptest" 35 36 "go.uber.org/cadence/internal/common/metrics" 37 ) 38 39 type WorkflowUnitTest struct { 40 suite.Suite 41 WorkflowTestSuite 42 activityOptions ActivityOptions 43 } 44 45 func (s *WorkflowUnitTest) SetupSuite() { 46 s.activityOptions = ActivityOptions{ 47 ScheduleToStartTimeout: time.Minute, 48 StartToCloseTimeout: time.Minute, 49 HeartbeatTimeout: 20 * time.Second, 50 } 51 } 52 func (s *WorkflowUnitTest) SetupTest() { 53 s.SetLogger(zaptest.NewLogger(s.T())) 54 } 55 56 func TestWorkflowUnitTest(t *testing.T) { 57 suite.Run(t, new(WorkflowUnitTest)) 58 } 59 60 func worldWorkflow(ctx Context, input string) (result string, err error) { 61 return input + " World!", nil 62 } 63 64 func (s *WorkflowUnitTest) Test_WorldWorkflow() { 65 env := newTestWorkflowEnv(s.T()) 66 env.ExecuteWorkflow(worldWorkflow, "Hello") 67 s.True(env.IsWorkflowCompleted()) 68 s.NoError(env.GetWorkflowError()) 69 } 70 71 func helloWorldAct(ctx context.Context) (string, error) { 72 s := ctx.Value(unitTestKey).(*WorkflowUnitTest) 73 info := GetActivityInfo(ctx) 74 s.Equal(tasklist, info.TaskList) 75 s.Equal(2*time.Second, info.HeartbeatTimeout) 76 return "test", nil 77 } 78 79 type key int 80 81 const unitTestKey key = 1 82 83 func singleActivityWorkflowWithOptions(s *WorkflowUnitTest, ao ActivityOptions) error { 84 helloWorldActivityWorkflow := func(ctx Context, input string) (result string, err error) { 85 ctx1 := WithActivityOptions(ctx, ao) 86 f := ExecuteActivity(ctx1, helloWorldAct) 87 var r1 string 88 err = f.Get(ctx, &r1) 89 if err != nil { 90 return "", err 91 } 92 return r1, nil 93 } 94 95 env := newTestWorkflowEnv(s.T()) 96 ctx := context.WithValue(context.Background(), unitTestKey, s) 97 env.SetWorkerOptions(WorkerOptions{BackgroundActivityContext: ctx}) 98 env.RegisterActivity(helloWorldAct) 99 env.ExecuteWorkflow(helloWorldActivityWorkflow, "Hello") 100 s.True(env.IsWorkflowCompleted()) 101 return env.GetWorkflowError() 102 } 103 104 func (s *WorkflowUnitTest) Test_SingleActivityWorkflow() { 105 ao := ActivityOptions{ 106 ScheduleToStartTimeout: 10 * time.Second, 107 StartToCloseTimeout: 5 * time.Second, 108 HeartbeatTimeout: 2 * time.Second, 109 ActivityID: "id1", 110 TaskList: tasklist, 111 } 112 err := singleActivityWorkflowWithOptions(s, ao) 113 s.NoError(err) 114 } 115 116 func (s *WorkflowUnitTest) Test_SingleActivityWorkflowIsErrorMessagesMatched() { 117 testCases := []struct { 118 name string 119 ScheduleToStartTimeout time.Duration 120 StartToCloseTimeout time.Duration 121 ScheduleToCloseTimeout time.Duration 122 expectedErrorMessage string 123 }{ 124 { 125 name: "ZeroScheduleToStartTimeout", 126 ScheduleToStartTimeout: 0 * time.Second, 127 StartToCloseTimeout: 5 * time.Second, 128 ScheduleToCloseTimeout: 0 * time.Second, 129 expectedErrorMessage: "missing or negative ScheduleToStartTimeoutSeconds", 130 }, 131 { 132 name: "ZeroStartToCloseTimeout", 133 ScheduleToStartTimeout: 10 * time.Second, 134 StartToCloseTimeout: 0 * time.Second, 135 ScheduleToCloseTimeout: 0 * time.Second, 136 expectedErrorMessage: "missing or negative StartToCloseTimeoutSeconds", 137 }, 138 { 139 name: "NegativeScheduleToCloseTimeout", 140 ScheduleToStartTimeout: 10 * time.Second, 141 StartToCloseTimeout: 5 * time.Second, 142 ScheduleToCloseTimeout: -1 * time.Second, 143 expectedErrorMessage: "invalid negative ScheduleToCloseTimeoutSeconds", 144 }, 145 } 146 147 for _, testCase := range testCases { 148 ao := ActivityOptions{ 149 ScheduleToStartTimeout: testCase.ScheduleToStartTimeout, 150 StartToCloseTimeout: testCase.StartToCloseTimeout, 151 ScheduleToCloseTimeout: testCase.ScheduleToCloseTimeout, 152 HeartbeatTimeout: 2 * time.Second, 153 ActivityID: "id1", 154 TaskList: tasklist, 155 } 156 s.Run(testCase.name, func() { 157 err := singleActivityWorkflowWithOptions(s, ao) 158 s.ErrorContains(err, testCase.expectedErrorMessage) 159 }) 160 } 161 } 162 163 func splitJoinActivityWorkflow(ctx Context, testPanic bool) (result string, err error) { 164 var result1, result2 string 165 var err1, err2 error 166 167 ao := ActivityOptions{ 168 ScheduleToStartTimeout: 10 * time.Second, 169 StartToCloseTimeout: 5 * time.Second, 170 } 171 ctx = WithActivityOptions(ctx, ao) 172 173 c1 := NewChannel(ctx) 174 c2 := NewChannel(ctx) 175 Go(ctx, func(ctx Context) { 176 ao.ActivityID = "id1" 177 ctx1 := WithActivityOptions(ctx, ao) 178 f := ExecuteActivity(ctx1, testAct) 179 err1 = f.Get(ctx, &result1) 180 if err1 == nil { 181 c1.Send(ctx, true) 182 } 183 }) 184 Go(ctx, func(ctx Context) { 185 ao.ActivityID = "id2" 186 ctx2 := WithActivityOptions(ctx, ao) 187 f := ExecuteActivity(ctx2, testAct) 188 err1 := f.Get(ctx, &result2) 189 if testPanic { 190 panic("simulated") 191 } 192 if err1 == nil { 193 c2.Send(ctx, true) 194 } 195 }) 196 197 c1.Receive(ctx, nil) 198 // Use selector to test it 199 selected := false 200 NewSelector(ctx).AddReceive(c2, func(c Channel, more bool) { 201 if !more { 202 panic("more should be true") 203 } 204 selected = true 205 }).Select(ctx) 206 if !selected { 207 return "", errors.New("selector does not work") 208 } 209 if err1 != nil { 210 return "", err1 211 } 212 if err2 != nil { 213 return "", err2 214 } 215 216 return result1 + result2, nil 217 } 218 219 func returnPanicWorkflow(ctx Context) (err error) { 220 return newPanicError("panicError", "stackTrace") 221 } 222 223 func (s *WorkflowUnitTest) Test_SplitJoinActivityWorkflow() { 224 env := newTestWorkflowEnv(s.T()) 225 env.RegisterWorkflowWithOptions(splitJoinActivityWorkflow, RegisterWorkflowOptions{Name: "splitJoinActivityWorkflow"}) 226 env.RegisterActivityWithOptions(testAct, RegisterActivityOptions{Name: "testActivityWithOptions"}) 227 env.OnActivity(testAct, mock.Anything).Return(func(ctx context.Context) (string, error) { 228 activityID := GetActivityInfo(ctx).ActivityID 229 switch activityID { 230 case "id1": 231 return "Hello", nil 232 case "id2": 233 return " Flow!", nil 234 default: 235 panic(fmt.Sprintf("Unexpected activityID: %v", activityID)) 236 } 237 }).Twice() 238 tracer := tracingInterceptorFactory{} 239 env.SetWorkerOptions(WorkerOptions{WorkflowInterceptorChainFactories: []WorkflowInterceptorFactory{&tracer}}) 240 env.ExecuteWorkflow(splitJoinActivityWorkflow, false) 241 s.True(env.IsWorkflowCompleted()) 242 s.NoError(env.GetWorkflowError()) 243 env.AssertExpectations(s.T()) 244 var result string 245 env.GetWorkflowResult(&result) 246 s.Equal("Hello Flow!", result) 247 s.Equal(1, len(tracer.instances)) 248 trace := tracer.instances[len(tracer.instances)-1].trace 249 s.Equal([]string{ 250 "ExecuteWorkflow splitJoinActivityWorkflow begin", 251 "ExecuteActivity testActivityWithOptions", 252 "ExecuteActivity testActivityWithOptions", 253 "ExecuteWorkflow splitJoinActivityWorkflow end", 254 }, trace) 255 } 256 257 func TestWorkflowPanic(t *testing.T) { 258 env := newTestWorkflowEnv(t) 259 env.RegisterActivity(testAct) 260 env.ExecuteWorkflow(splitJoinActivityWorkflow, true) 261 require.True(t, env.IsWorkflowCompleted()) 262 require.NotNil(t, env.GetWorkflowError()) 263 resultErr := env.GetWorkflowError().(*PanicError) 264 require.EqualValues(t, "simulated", resultErr.Error()) 265 require.Contains(t, resultErr.StackTrace(), "cadence/internal.splitJoinActivityWorkflow") 266 } 267 268 func TestWorkflowReturnsPanic(t *testing.T) { 269 env := newTestWorkflowEnv(t) 270 env.ExecuteWorkflow(returnPanicWorkflow) 271 require.True(t, env.IsWorkflowCompleted()) 272 require.NotNil(t, env.GetWorkflowError()) 273 resultErr := env.GetWorkflowError().(*PanicError) 274 require.EqualValues(t, "panicError", resultErr.Error()) 275 require.EqualValues(t, "stackTrace", resultErr.StackTrace()) 276 } 277 278 func testClockWorkflow(ctx Context) (time.Time, error) { 279 c := Now(ctx) 280 return c, nil 281 } 282 283 func (s *WorkflowUnitTest) Test_ClockWorkflow() { 284 env := newTestWorkflowEnv(s.T()) 285 env.ExecuteWorkflow(testClockWorkflow) 286 s.True(env.IsWorkflowCompleted()) 287 s.NoError(env.GetWorkflowError()) 288 var nowTime time.Time 289 env.GetWorkflowResult(&nowTime) 290 s.False(nowTime.IsZero()) 291 } 292 293 type testTimerWorkflow struct { 294 t *testing.T 295 } 296 297 func (w *testTimerWorkflow) Execute(ctx Context, input []byte) (result []byte, err error) { 298 // Start a timer. 299 t := NewTimer(ctx, 1) 300 301 isWokeByTimer := false 302 303 NewSelector(ctx).AddFuture(t, func(f Future) { 304 err := f.Get(ctx, nil) 305 require.NoError(w.t, err) 306 isWokeByTimer = true 307 }).Select(ctx) 308 309 require.True(w.t, isWokeByTimer) 310 311 // Start a timer and cancel it. 312 ctx2, c2 := WithCancel(ctx) 313 t2 := NewTimer(ctx2, 1) 314 c2() 315 err2 := t2.Get(ctx2, nil) 316 317 require.Error(w.t, err2) 318 _, isCancelErr := err2.(*CanceledError) 319 require.True(w.t, isCancelErr) 320 321 // Sleep 1 sec 322 ctx3, _ := WithCancel(ctx) 323 err3 := Sleep(ctx3, 1) 324 require.NoError(w.t, err3) 325 326 // Sleep and cancel. 327 ctx4, c4 := WithCancel(ctx) 328 c4() 329 err4 := Sleep(ctx4, 1) 330 331 require.Error(w.t, err4) 332 _, isCancelErr = err4.(*CanceledError) 333 require.True(w.t, isCancelErr) 334 335 return []byte("workflow-completed"), nil 336 } 337 338 func TestTimerWorkflow(t *testing.T) { 339 env := newTestWorkflowEnv(t) 340 w := &testTimerWorkflow{t: t} 341 env.RegisterWorkflow(w.Execute) 342 env.ExecuteWorkflow(w.Execute, []byte{1, 2}) 343 require.True(t, env.IsWorkflowCompleted()) 344 require.NoError(t, env.GetWorkflowError()) 345 } 346 347 type testActivityCancelWorkflow struct { 348 t *testing.T 349 } 350 351 func testAct(ctx context.Context) (string, error) { 352 return "test", nil 353 } 354 355 func (w *testActivityCancelWorkflow) Execute(ctx Context, input []byte) (result []byte, err error) { 356 ao := ActivityOptions{ 357 ScheduleToStartTimeout: 10 * time.Second, 358 StartToCloseTimeout: 5 * time.Second, 359 } 360 ctx = WithActivityOptions(ctx, ao) 361 362 // Sync cancellation 363 ctx1, c1 := WithCancel(ctx) 364 defer c1() 365 366 ao.ActivityID = "id1" 367 ctx1 = WithActivityOptions(ctx1, ao) 368 f := ExecuteActivity(ctx1, testAct) 369 var res1 string 370 err1 := f.Get(ctx, &res1) 371 require.NoError(w.t, err1, err1) 372 require.Equal(w.t, res1, "test") 373 374 // Async Cancellation (Callback completes before cancel) 375 ctx2, c2 := WithCancel(ctx) 376 ao.ActivityID = "id2" 377 ctx2 = WithActivityOptions(ctx2, ao) 378 f = ExecuteActivity(ctx2, testAct) 379 c2() 380 var res2 string 381 err2 := f.Get(ctx, &res2) 382 require.NotNil(w.t, err2) 383 _, ok := err2.(*CanceledError) 384 require.True(w.t, ok) 385 return []byte("workflow-completed"), nil 386 } 387 388 func TestActivityCancellation(t *testing.T) { 389 env := newTestWorkflowEnv(t) 390 env.RegisterActivity(testAct) 391 w := &testActivityCancelWorkflow{t: t} 392 env.RegisterWorkflow(w.Execute) 393 env.ExecuteWorkflow(w.Execute, []byte{1, 2}) 394 require.True(t, env.IsWorkflowCompleted()) 395 require.NoError(t, env.GetWorkflowError()) 396 } 397 398 type sayGreetingActivityRequest struct { 399 Name string 400 Greeting string 401 } 402 403 func getGreetingActivity() (string, error) { 404 return "Hello", nil 405 } 406 func getNameActivity() (string, error) { 407 return "cadence", nil 408 } 409 func sayGreetingActivity(input *sayGreetingActivityRequest) (string, error) { 410 return fmt.Sprintf("%v %v!", input.Greeting, input.Name), nil 411 } 412 413 // Greetings Workflow Decider. 414 func greetingsWorkflow(ctx Context) (result string, err error) { 415 // Get Greeting. 416 ao := ActivityOptions{ 417 ScheduleToStartTimeout: 10 * time.Second, 418 StartToCloseTimeout: 5 * time.Second, 419 } 420 ctx1 := WithActivityOptions(ctx, ao) 421 422 f := ExecuteActivity(ctx1, getGreetingActivity) 423 var greetResult string 424 err = f.Get(ctx, &greetResult) 425 if err != nil { 426 return "", err 427 } 428 429 // Get Name. 430 f = ExecuteActivity(ctx1, getNameActivity) 431 var nameResult string 432 err = f.Get(ctx, &nameResult) 433 if err != nil { 434 return "", err 435 } 436 437 // Say Greeting. 438 request := &sayGreetingActivityRequest{Name: nameResult, Greeting: greetResult} 439 err = ExecuteActivity(ctx1, sayGreetingActivity, request).Get(ctx, &result) 440 if err != nil { 441 return "", err 442 } 443 return result, nil 444 } 445 446 func (s *WorkflowUnitTest) Test_ExternalExampleWorkflow() { 447 env := newTestWorkflowEnv(s.T()) 448 env.RegisterActivity(getGreetingActivity) 449 env.RegisterActivity(getNameActivity) 450 env.RegisterActivity(sayGreetingActivity) 451 452 env.ExecuteWorkflow(greetingsWorkflow) 453 454 s.True(env.IsWorkflowCompleted()) 455 s.NoError(env.GetWorkflowError()) 456 var result string 457 env.GetWorkflowResult(&result) 458 s.Equal("Hello cadence!", result) 459 } 460 461 func continueAsNewWorkflowTest(ctx Context) error { 462 return NewContinueAsNewError(ctx, "continueAsNewWorkflowTest", []byte("start")) 463 } 464 465 func (s *WorkflowUnitTest) Test_ContinueAsNewWorkflow() { 466 env := newTestWorkflowEnv(s.T()) 467 env.ExecuteWorkflow(continueAsNewWorkflowTest) 468 s.True(env.IsWorkflowCompleted()) 469 s.NotNil(env.GetWorkflowError()) 470 resultErr := env.GetWorkflowError().(*ContinueAsNewError) 471 s.EqualValues("continueAsNewWorkflowTest", resultErr.params.workflowType.Name) 472 s.EqualValues(1, *resultErr.params.executionStartToCloseTimeoutSeconds) 473 s.EqualValues(1, *resultErr.params.taskStartToCloseTimeoutSeconds) 474 s.EqualValues("default-test-tasklist", *resultErr.params.taskListName) 475 } 476 477 func cancelWorkflowTest(ctx Context) (string, error) { 478 if ctx.Done().Receive(ctx, nil); ctx.Err() == ErrCanceled { 479 return "Cancelled.", ctx.Err() 480 } 481 return "Completed.", nil 482 } 483 484 func (s *WorkflowUnitTest) Test_CancelWorkflow() { 485 env := newTestWorkflowEnv(s.T()) 486 env.RegisterDelayedCallback(func() { 487 env.CancelWorkflow() 488 }, time.Hour) 489 env.ExecuteWorkflow(cancelWorkflowTest) 490 s.True(env.IsWorkflowCompleted(), "Workflow failed to complete") 491 } 492 493 func cancelWorkflowAfterActivityTest(ctx Context) ([]byte, error) { 494 // The workflow cancellation should handle activity and timer cancellation 495 // not to propagate those decisions. 496 497 // schedule an activity. 498 ao := ActivityOptions{ 499 ScheduleToStartTimeout: 10 * time.Second, 500 StartToCloseTimeout: 5 * time.Second, 501 } 502 ctx = WithActivityOptions(ctx, ao) 503 504 err := ExecuteActivity(ctx, testAct).Get(ctx, nil) 505 if err != nil { 506 return nil, err 507 } 508 509 // schedule a timer 510 err2 := Sleep(ctx, 1) 511 if err2 != nil { 512 return nil, err2 513 } 514 515 if ctx.Done().Receive(ctx, nil); ctx.Err() == ErrCanceled { 516 return []byte("Cancelled."), ctx.Err() 517 } 518 return []byte("Completed."), nil 519 } 520 521 func (s *WorkflowUnitTest) Test_CancelWorkflowAfterActivity() { 522 env := newTestWorkflowEnv(s.T()) 523 env.RegisterDelayedCallback(func() { 524 env.CancelWorkflow() 525 }, time.Hour) 526 env.ExecuteWorkflow(cancelWorkflowAfterActivityTest) 527 s.True(env.IsWorkflowCompleted()) 528 } 529 530 func signalWorkflowTest(ctx Context) ([]byte, error) { 531 // read multiple times. 532 var result string 533 ch := GetSignalChannel(ctx, "testSig1") 534 var v string 535 ok := ch.ReceiveAsync(&v) 536 if !ok { 537 return nil, errors.New("testSig1 not received") 538 } 539 result += v 540 ch.Receive(ctx, &v) 541 result += v 542 543 // Read on a selector. 544 ch2 := GetSignalChannel(ctx, "testSig2") 545 s := NewSelector(ctx) 546 s.AddReceive(ch2, func(c Channel, more bool) { 547 c.Receive(ctx, &v) 548 result += v 549 }) 550 s.Select(ctx) 551 s.Select(ctx) 552 s.Select(ctx) 553 554 // Read on a selector inside the callback, multiple times. 555 ch2 = GetSignalChannel(ctx, "testSig2") 556 s = NewSelector(ctx) 557 s.AddReceive(ch2, func(c Channel, more bool) { 558 for i := 0; i < 4; i++ { 559 c.Receive(ctx, &v) 560 result += v 561 } 562 }) 563 s.Select(ctx) 564 565 // Check un handled signals. 566 list := getWorkflowEnvOptions(ctx).getUnhandledSignalNames() 567 if len(list) != 1 || list[0] != "testSig3" { 568 panic("expecting one unhandled signal") 569 } 570 ch3 := GetSignalChannel(ctx, "testSig3") 571 ch3.Receive(ctx, &v) 572 result += v 573 list = getWorkflowEnvOptions(ctx).getUnhandledSignalNames() 574 if len(list) != 0 { 575 panic("expecting no unhandled signals") 576 } 577 return []byte(result), nil 578 } 579 580 func (s *WorkflowUnitTest) Test_SignalWorkflow() { 581 expected := []string{ 582 "Sig1Value1;", 583 "Sig1Value2;", 584 "Sig2Value1;", 585 "Sig2Value2;", 586 "Sig2Value3;", 587 "Sig2Value4;", 588 "Sig2Value5;", 589 "Sig2Value6;", 590 "Sig2Value7;", 591 "Sig3Value1;", 592 } 593 env := newTestWorkflowEnv(s.T()) 594 595 // Setup signals. 596 for i := 0; i < 2; i++ { 597 msg := expected[i] 598 var delay time.Duration 599 if i > 0 { 600 delay = time.Second 601 } 602 env.RegisterDelayedCallback(func() { 603 env.SignalWorkflow("testSig1", msg) 604 }, delay) 605 } 606 env.RegisterDelayedCallback(func() { 607 env.SignalWorkflow("testSig3", expected[9]) 608 }, time.Hour) 609 for i := 2; i < 9; i++ { 610 msg := expected[i] 611 env.RegisterDelayedCallback(func() { 612 env.SignalWorkflow("testSig2", msg) 613 }, time.Hour) 614 } 615 616 env.ExecuteWorkflow(signalWorkflowTest) 617 s.True(env.IsWorkflowCompleted()) 618 s.NoError(env.GetWorkflowError()) 619 var result []byte 620 env.GetWorkflowResult(&result) 621 s.EqualValues(strings.Join(expected, ""), string(result)) 622 } 623 624 type message struct { 625 Value string 626 } 627 628 func receiveCorruptSignalWorkflowTest(ctx Context) ([]message, error) { 629 ch := GetSignalChannel(ctx, "channelExpectingTypeMessage") 630 var result []message 631 var m message 632 ch.Receive(ctx, &m) 633 result = append(result, m) 634 return result, nil 635 } 636 637 func receiveCorruptSignalOnClosedChannelWorkflowTest(ctx Context) ([]message, error) { 638 ch := GetSignalChannel(ctx, "channelExpectingTypeMessage") 639 var result []message 640 var m message 641 ch.Close() 642 more := ch.Receive(ctx, &m) 643 644 result = append(result, message{Value: fmt.Sprintf("%v", more)}) 645 return result, nil 646 } 647 648 func receiveWithSelectorCorruptSignalWorkflowTest(ctx Context) ([]message, error) { 649 var result []message 650 651 // Read on a selector 652 ch := GetSignalChannel(ctx, "channelExpectingTypeMessage") 653 s := NewSelector(ctx) 654 s.AddReceive(ch, func(c Channel, more bool) { 655 var m message 656 ch.Receive(ctx, &m) 657 result = append(result, m) 658 }) 659 s.Select(ctx) 660 return result, nil 661 } 662 663 func receiveAsyncCorruptSignalOnClosedChannelWorkflowTest(ctx Context) ([]int, error) { 664 ch := GetSignalChannel(ctx, "channelExpectingInt") 665 var result []int 666 var m int 667 668 ch.SendAsync("wrong") 669 ch.Close() 670 ok := ch.ReceiveAsync(&m) 671 if ok == true { 672 result = append(result, m) 673 } 674 675 return result, nil 676 } 677 678 func receiveAsyncCorruptSignalWorkflowTest(ctx Context) ([]message, error) { 679 ch := GetSignalChannel(ctx, "channelExpectingTypeMessage") 680 var result []message 681 var m message 682 683 ch.SendAsync("wrong") 684 ok := ch.ReceiveAsync(&m) 685 if ok == true { 686 result = append(result, m) 687 } 688 689 ch.SendAsync("wrong again") 690 ch.SendAsync(message{ 691 Value: "the right interface", 692 }) 693 ok = ch.ReceiveAsync(&m) 694 if ok == true { 695 result = append(result, m) 696 } 697 return result, nil 698 } 699 700 func (s *WorkflowUnitTest) Test_CorruptedSignalWorkflow_ShouldLogMetricsAndNotPanic() { 701 scope, closer, reporter := metrics.NewTaggedMetricsScope() 702 s.SetMetricsScope(scope) 703 env := s.NewTestWorkflowEnvironment() 704 env.Test(s.T()) 705 706 // Setup signals. 707 env.RegisterDelayedCallback(func() { 708 env.SignalWorkflow("channelExpectingTypeMessage", "wrong") 709 }, time.Millisecond) 710 711 env.RegisterDelayedCallback(func() { 712 env.SignalWorkflow("channelExpectingTypeMessage", message{ 713 Value: "the right interface", 714 }) 715 }, time.Second) 716 717 env.ExecuteWorkflow(receiveCorruptSignalWorkflowTest) 718 s.True(env.IsWorkflowCompleted()) 719 s.NoError(env.GetWorkflowError()) 720 721 var result []message 722 env.GetWorkflowResult(&result) 723 724 s.EqualValues(1, len(result)) 725 s.EqualValues("the right interface", result[0].Value) 726 727 closer.Close() 728 counts := reporter.Counts() 729 s.EqualValues(1, len(counts)) 730 s.EqualValues(metrics.CorruptedSignalsCounter, counts[0].Name()) 731 s.EqualValues(1, counts[0].Value()) 732 } 733 734 func (s *WorkflowUnitTest) Test_CorruptedSignalWorkflow_OnSelectorRead_ShouldLogMetricsAndNotPanic() { 735 scope, closer, reporter := metrics.NewTaggedMetricsScope() 736 s.SetMetricsScope(scope) 737 env := s.NewTestWorkflowEnvironment() 738 env.Test(s.T()) 739 740 // Setup signals. 741 env.RegisterDelayedCallback(func() { 742 env.SignalWorkflow("channelExpectingTypeMessage", "wrong") 743 }, time.Second) 744 745 env.RegisterDelayedCallback(func() { 746 env.SignalWorkflow("channelExpectingTypeMessage", message{ 747 Value: "the right interface", 748 }) 749 }, 3*time.Second) 750 751 env.ExecuteWorkflow(receiveWithSelectorCorruptSignalWorkflowTest) 752 s.True(env.IsWorkflowCompleted()) 753 s.NoError(env.GetWorkflowError()) 754 755 var result []message 756 env.GetWorkflowResult(&result) 757 758 s.EqualValues(1, len(result)) 759 s.EqualValues("the right interface", result[0].Value) 760 761 closer.Close() 762 counts := reporter.Counts() 763 s.EqualValues(1, len(counts)) 764 s.EqualValues(metrics.CorruptedSignalsCounter, counts[0].Name()) 765 s.EqualValues(1, counts[0].Value()) 766 } 767 768 func (s *WorkflowUnitTest) Test_CorruptedSignalWorkflow_ReceiveAsync_ShouldLogMetricsAndNotPanic() { 769 scope, closer, reporter := metrics.NewTaggedMetricsScope() 770 s.SetMetricsScope(scope) 771 env := s.NewTestWorkflowEnvironment() 772 env.Test(s.T()) 773 774 env.ExecuteWorkflow(receiveAsyncCorruptSignalWorkflowTest) 775 s.True(env.IsWorkflowCompleted()) 776 s.NoError(env.GetWorkflowError()) 777 778 var result []message 779 env.GetWorkflowResult(&result) 780 s.EqualValues(1, len(result)) 781 s.EqualValues("the right interface", result[0].Value) 782 783 closer.Close() 784 counts := reporter.Counts() 785 s.EqualValues(1, len(counts)) 786 s.EqualValues(metrics.CorruptedSignalsCounter, counts[0].Name()) 787 s.EqualValues(2, counts[0].Value()) 788 } 789 790 func (s *WorkflowUnitTest) Test_CorruptedSignalOnClosedChannelWorkflow_ReceiveAsync_ShouldComplete() { 791 env := newTestWorkflowEnv(s.T()) 792 793 env.ExecuteWorkflow(receiveAsyncCorruptSignalOnClosedChannelWorkflowTest) 794 s.True(env.IsWorkflowCompleted()) 795 s.NoError(env.GetWorkflowError()) 796 797 var result []message 798 env.GetWorkflowResult(&result) 799 s.EqualValues(0, len(result)) 800 } 801 802 func (s *WorkflowUnitTest) Test_CorruptedSignalOnClosedChannelWorkflow_Receive_ShouldComplete() { 803 env := newTestWorkflowEnv(s.T()) 804 805 // Setup signals. 806 env.RegisterDelayedCallback(func() { 807 env.SignalWorkflow("channelExpectingTypeMessage", "wrong") 808 }, time.Second) 809 810 env.ExecuteWorkflow(receiveCorruptSignalOnClosedChannelWorkflowTest) 811 s.True(env.IsWorkflowCompleted()) 812 s.NoError(env.GetWorkflowError()) 813 814 var result []message 815 env.GetWorkflowResult(&result) 816 s.EqualValues(1, len(result)) 817 s.Equal("false", result[0].Value) 818 } 819 820 func closeChannelTest(ctx Context) error { 821 ch := NewChannel(ctx) 822 Go(ctx, func(ctx Context) { 823 var dummy struct{} 824 ch.Receive(ctx, &dummy) 825 ch.Close() 826 }) 827 828 ch.Send(ctx, struct{}{}) 829 return nil 830 } 831 832 func (s *WorkflowUnitTest) Test_CloseChannelWorkflow() { 833 env := newTestWorkflowEnv(s.T()) 834 env.ExecuteWorkflow(closeChannelTest) 835 s.True(env.IsWorkflowCompleted()) 836 s.NoError(env.GetWorkflowError()) 837 } 838 839 func closeChannelInSelectTest(ctx Context) error { 840 s := NewSelector(ctx) 841 sendCh := NewChannel(ctx) 842 receiveCh := NewChannel(ctx) 843 expectedValue := "expected value" 844 845 Go(ctx, func(ctx Context) { 846 sendCh.Close() 847 receiveCh.Send(ctx, expectedValue) 848 }) 849 850 var v string 851 s.AddSend(sendCh, struct{}{}, func() { 852 panic("callback for sendCh should not be executed") 853 }) 854 s.AddReceive(receiveCh, func(c Channel, m bool) { 855 c.Receive(ctx, &v) 856 }) 857 s.Select(ctx) 858 if v != expectedValue { 859 panic("callback for receiveCh is not executed") 860 } 861 return nil 862 } 863 864 func (s *WorkflowUnitTest) Test_CloseChannelInSelectWorkflow() { 865 env := newTestWorkflowEnv(s.T()) 866 env.ExecuteWorkflow(closeChannelInSelectTest) 867 s.True(env.IsWorkflowCompleted()) 868 s.NoError(env.GetWorkflowError()) 869 } 870 871 func bufferedChanWorkflowTest(ctx Context, bufferSize int) error { 872 bufferedCh := NewBufferedChannel(ctx, bufferSize) 873 874 Go(ctx, func(ctx Context) { 875 var dummy int 876 for i := 0; i < bufferSize; i++ { 877 bufferedCh.Receive(ctx, &dummy) 878 } 879 }) 880 881 for i := 0; i < bufferSize+1; i++ { 882 bufferedCh.Send(ctx, i) 883 } 884 return nil 885 } 886 887 func (s *WorkflowUnitTest) Test_BufferedChanWorkflow() { 888 bufferSizeList := []int{1, 5} 889 for _, bufferSize := range bufferSizeList { 890 env := newTestWorkflowEnv(s.T()) 891 env.ExecuteWorkflow(bufferedChanWorkflowTest, bufferSize) 892 s.True(env.IsWorkflowCompleted()) 893 s.NoError(env.GetWorkflowError()) 894 } 895 } 896 897 func bufferedChanWithSelectorWorkflowTest(ctx Context, bufferSize int) error { 898 bufferedCh := NewBufferedChannel(ctx, bufferSize) 899 selectedCh := NewChannel(ctx) 900 done := NewChannel(ctx) 901 var dummy struct{} 902 903 // 1. First we need to fill the buffer 904 for i := 0; i < bufferSize; i++ { 905 bufferedCh.Send(ctx, dummy) 906 } 907 908 // DO NOT change the order of these coroutines. 909 Go(ctx, func(ctx Context) { 910 // 3. Add another send callback to bufferedCh's blockedSends. 911 bufferedCh.Send(ctx, dummy) 912 done.Send(ctx, dummy) 913 }) 914 915 Go(ctx, func(ctx Context) { 916 // 4. Make sure selectedCh is selected 917 selectedCh.Receive(ctx, nil) 918 919 // 5. Get a value from channel buffer. Receive call will also check if there's any blocked sends. 920 // The first blockedSends is added by Select(). Since bufferedCh is not selected, it's fn() will 921 // return false. The Receive call should continue to check other blockedSends, until fn() returns 922 // true or the list is empty. In this case, it will move the value sent in step 3 into buffer 923 // and thus unblocks it. 924 bufferedCh.Receive(ctx, nil) 925 }) 926 927 selector := NewSelector(ctx) 928 selector.AddSend(selectedCh, dummy, func() {}) 929 selector.AddSend(bufferedCh, dummy, func() {}) 930 // 2. When select is called, callback for the second send will be added to bufferedCh's blockedSends 931 selector.Select(ctx) 932 933 // Make sure no coroutine blocks 934 done.Receive(ctx, nil) 935 return nil 936 } 937 938 func (s *WorkflowUnitTest) Test_BufferedChanWithSelectorWorkflow() { 939 bufferSizeList := []int{1, 5} 940 for _, bufferSize := range bufferSizeList { 941 bufferSize := bufferSize 942 env := newTestWorkflowEnv(s.T()) 943 env.ExecuteWorkflow(bufferedChanWithSelectorWorkflowTest, bufferSize) 944 s.True(env.IsWorkflowCompleted()) 945 s.NoError(env.GetWorkflowError()) 946 } 947 } 948 949 func activityOptionsWorkflow(ctx Context) (result string, err error) { 950 ao1 := ActivityOptions{ 951 ActivityID: "id1", 952 } 953 ao2 := ActivityOptions{ 954 ActivityID: "id2", 955 } 956 ctx1 := WithActivityOptions(ctx, ao1) 957 ctx2 := WithActivityOptions(ctx, ao2) 958 959 ctx1Ao := getActivityOptions(ctx1) 960 ctx2Ao := getActivityOptions(ctx2) 961 return *ctx1Ao.ActivityID + " " + *ctx2Ao.ActivityID, nil 962 } 963 964 // Test that activity options are correctly spawned with WithActivityOptions is called. 965 // See https://github.com/uber-go/cadence-client/issues/372 966 func (s *WorkflowUnitTest) Test_ActivityOptionsWorkflow() { 967 env := newTestWorkflowEnv(s.T()) 968 env.ExecuteWorkflow(activityOptionsWorkflow) 969 s.True(env.IsWorkflowCompleted()) 970 s.NoError(env.GetWorkflowError()) 971 var result string 972 env.GetWorkflowResult(&result) 973 s.Equal("id1 id2", result) 974 } 975 976 const ( 977 memoTestKey = "testKey" 978 memoTestVal = "testVal" 979 ) 980 981 func getMemoTest(ctx Context) (result string, err error) { 982 info := GetWorkflowInfo(ctx) 983 val, ok := info.Memo.Fields[memoTestKey] 984 if !ok { 985 return "", errors.New("no memo found") 986 } 987 err = NewValue(val).Get(&result) 988 return result, err 989 } 990 991 func (s *WorkflowUnitTest) Test_MemoWorkflow() { 992 env := newTestWorkflowEnv(s.T()) 993 memo := map[string]interface{}{ 994 memoTestKey: memoTestVal, 995 } 996 err := env.SetMemoOnStart(memo) 997 s.NoError(err) 998 999 env.ExecuteWorkflow(getMemoTest) 1000 s.True(env.IsWorkflowCompleted()) 1001 s.NoError(env.GetWorkflowError()) 1002 var result string 1003 env.GetWorkflowResult(&result) 1004 s.Equal(memoTestVal, result) 1005 } 1006 1007 func sleepWorkflow(ctx Context, input time.Duration) (int, error) { 1008 if err := Sleep(ctx, input); err != nil { 1009 return 0, err 1010 } 1011 1012 return 1, nil 1013 } 1014 1015 func waitGroupWorkflowTest(ctx Context, n int) (int, error) { 1016 ctx = WithChildWorkflowOptions(ctx, ChildWorkflowOptions{ 1017 ExecutionStartToCloseTimeout: time.Second * 30, 1018 }) 1019 1020 var err error 1021 results := make([]int, 0, n) 1022 waitGroup := NewWaitGroup(ctx) 1023 for i := 0; i < n; i++ { 1024 waitGroup.Add(1) 1025 t := time.Second * time.Duration(i+1) 1026 Go(ctx, func(ctx Context) { 1027 var result int 1028 err = ExecuteChildWorkflow(ctx, sleepWorkflow, t).Get(ctx, &result) 1029 results = append(results, result) 1030 waitGroup.Done() 1031 }) 1032 } 1033 1034 waitGroup.Wait(ctx) 1035 if err != nil { 1036 return 0, err 1037 } 1038 1039 sum := 0 1040 for _, v := range results { 1041 sum = sum + v 1042 } 1043 1044 return sum, nil 1045 } 1046 1047 func waitGroupWaitForMWorkflowTest(ctx Context, n int, m int) (int, error) { 1048 ctx = WithChildWorkflowOptions(ctx, ChildWorkflowOptions{ 1049 ExecutionStartToCloseTimeout: time.Second * 30, 1050 }) 1051 1052 var err error 1053 results := make([]int, 0, n) 1054 waitGroup := NewWaitGroup(ctx) 1055 waitGroup.Add(m) 1056 for i := 0; i < n; i++ { 1057 t := time.Second * time.Duration(i+1) 1058 Go(ctx, func(ctx Context) { 1059 var result int 1060 err = ExecuteChildWorkflow(ctx, sleepWorkflow, t).Get(ctx, &result) 1061 results = append(results, result) 1062 waitGroup.Done() 1063 }) 1064 } 1065 1066 waitGroup.Wait(ctx) 1067 if err != nil { 1068 return 0, err 1069 } 1070 1071 sum := 0 1072 for _, v := range results { 1073 sum = sum + v 1074 } 1075 1076 return sum, nil 1077 } 1078 1079 func waitGroupMultipleWaitsWorkflowTest(ctx Context) (int, error) { 1080 ctx = WithChildWorkflowOptions(ctx, ChildWorkflowOptions{ 1081 ExecutionStartToCloseTimeout: time.Second * 30, 1082 }) 1083 1084 n := 10 1085 var err error 1086 results := make([]int, 0, n) 1087 waitGroup := NewWaitGroup(ctx) 1088 waitGroup.Add(4) 1089 for i := 0; i < n; i++ { 1090 t := time.Second * time.Duration(i+1) 1091 Go(ctx, func(ctx Context) { 1092 var result int 1093 err = ExecuteChildWorkflow(ctx, sleepWorkflow, t).Get(ctx, &result) 1094 results = append(results, result) 1095 waitGroup.Done() 1096 }) 1097 } 1098 1099 waitGroup.Wait(ctx) 1100 if err != nil { 1101 return 0, err 1102 } 1103 1104 waitGroup.Add(6) 1105 waitGroup.Wait(ctx) 1106 if err != nil { 1107 return 0, err 1108 } 1109 1110 sum := 0 1111 for _, v := range results { 1112 sum = sum + v 1113 } 1114 1115 return sum, nil 1116 } 1117 1118 func waitGroupMultipleConcurrentWaitsPanicsWorkflowTest(ctx Context) (int, error) { 1119 ctx = WithChildWorkflowOptions(ctx, ChildWorkflowOptions{ 1120 ExecutionStartToCloseTimeout: time.Second * 30, 1121 }) 1122 1123 var err error 1124 var result1 int 1125 var result2 int 1126 1127 waitGroup := NewWaitGroup(ctx) 1128 waitGroup.Add(2) 1129 1130 Go(ctx, func(ctx Context) { 1131 err = ExecuteChildWorkflow(ctx, sleepWorkflow, time.Second*5).Get(ctx, &result1) 1132 waitGroup.Done() 1133 }) 1134 1135 Go(ctx, func(ctx Context) { 1136 err = ExecuteChildWorkflow(ctx, sleepWorkflow, time.Second*10).Get(ctx, &result2) 1137 waitGroup.Wait(ctx) 1138 }) 1139 1140 waitGroup.Wait(ctx) 1141 if err != nil { 1142 return 0, err 1143 } 1144 1145 return result1 + result2, nil 1146 } 1147 1148 func waitGroupNegativeCounterPanicsWorkflowTest(ctx Context) (int, error) { 1149 ctx = WithChildWorkflowOptions(ctx, ChildWorkflowOptions{ 1150 ExecutionStartToCloseTimeout: time.Second * 30, 1151 }) 1152 1153 var err error 1154 var result int 1155 waitGroup := NewWaitGroup(ctx) 1156 1157 Go(ctx, func(ctx Context) { 1158 waitGroup.Done() 1159 err = ExecuteChildWorkflow(ctx, sleepWorkflow, time.Second*5).Get(ctx, &result) 1160 }) 1161 1162 waitGroup.Wait(ctx) 1163 if err != nil { 1164 return 0, err 1165 } 1166 1167 return result, nil 1168 } 1169 1170 func (s *WorkflowUnitTest) Test_waitGroupNegativeCounterPanicsWorkflowTest() { 1171 env := newTestWorkflowEnv(s.T()) 1172 env.RegisterWorkflow(waitGroupNegativeCounterPanicsWorkflowTest) 1173 env.ExecuteWorkflow(waitGroupNegativeCounterPanicsWorkflowTest) 1174 s.True(env.IsWorkflowCompleted()) 1175 1176 resultErr := env.GetWorkflowError().(*PanicError) 1177 s.EqualValues("negative WaitGroup counter", resultErr.Error()) 1178 s.Contains(resultErr.StackTrace(), "cadence/internal.waitGroupNegativeCounterPanicsWorkflowTest") 1179 } 1180 1181 func (s *WorkflowUnitTest) Test_WaitGroupMultipleConcurrentWaitsPanicsWorkflowTest() { 1182 env := newTestWorkflowEnv(s.T()) 1183 env.RegisterWorkflow(waitGroupMultipleConcurrentWaitsPanicsWorkflowTest) 1184 env.RegisterWorkflow(sleepWorkflow) 1185 env.ExecuteWorkflow(waitGroupMultipleConcurrentWaitsPanicsWorkflowTest) 1186 s.True(env.IsWorkflowCompleted()) 1187 1188 resultErr := env.GetWorkflowError().(*PanicError) 1189 s.EqualValues("WaitGroup is reused before previous Wait has returned", resultErr.Error()) 1190 s.Contains(resultErr.StackTrace(), "cadence/internal.waitGroupMultipleConcurrentWaitsPanicsWorkflowTest") 1191 } 1192 1193 func (s *WorkflowUnitTest) Test_WaitGroupMultipleWaitsWorkflowTest() { 1194 env := newTestWorkflowEnv(s.T()) 1195 env.RegisterWorkflow(waitGroupMultipleWaitsWorkflowTest) 1196 env.RegisterWorkflow(sleepWorkflow) 1197 env.ExecuteWorkflow(waitGroupMultipleWaitsWorkflowTest) 1198 s.True(env.IsWorkflowCompleted()) 1199 s.NoError(env.GetWorkflowError()) 1200 1201 var total int 1202 env.GetWorkflowResult(&total) 1203 s.Equal(10, total) 1204 } 1205 1206 func (s *WorkflowUnitTest) Test_WaitGroupWaitForMWorkflowTest() { 1207 env := newTestWorkflowEnv(s.T()) 1208 env.RegisterWorkflow(waitGroupWaitForMWorkflowTest) 1209 env.RegisterWorkflow(sleepWorkflow) 1210 1211 n := 10 1212 m := 5 1213 env.ExecuteWorkflow(waitGroupWaitForMWorkflowTest, n, m) 1214 s.True(env.IsWorkflowCompleted()) 1215 s.NoError(env.GetWorkflowError()) 1216 1217 var total int 1218 env.GetWorkflowResult(&total) 1219 s.Equal(m, total) 1220 } 1221 1222 func (s *WorkflowUnitTest) Test_WaitGroupWorkflowTest() { 1223 env := newTestWorkflowEnv(s.T()) 1224 env.RegisterWorkflow(waitGroupWorkflowTest) 1225 env.RegisterWorkflow(sleepWorkflow) 1226 1227 n := 10 1228 env.ExecuteWorkflow(waitGroupWorkflowTest, n) 1229 s.True(env.IsWorkflowCompleted()) 1230 s.Nil(env.GetWorkflowError()) 1231 s.NoError(env.GetWorkflowError()) 1232 1233 var total int 1234 env.GetWorkflowResult(&total) 1235 s.Equal(n, total) 1236 } 1237 1238 func (s *WorkflowUnitTest) Test_StaleGoroutinesAreShutDown() { 1239 env := newTestWorkflowEnv(s.T()) 1240 deferred := make(chan struct{}) 1241 after := make(chan struct{}) 1242 wf := func(ctx Context) error { 1243 Go(ctx, func(ctx Context) { 1244 defer func() { close(deferred) }() 1245 _ = Sleep(ctx, time.Hour) // outlive the workflow 1246 close(after) 1247 }) 1248 _ = Sleep(ctx, time.Minute) 1249 return nil 1250 } 1251 env.RegisterWorkflow(wf) 1252 1253 env.ExecuteWorkflow(wf) 1254 s.True(env.IsWorkflowCompleted()) 1255 s.NoError(env.GetWorkflowError()) 1256 1257 // goroutines are shut down async at the moment, so wait with a timeout. 1258 // give it up to 1s total. 1259 1260 started := time.Now() 1261 maxWait := time.NewTimer(time.Second) 1262 defer maxWait.Stop() 1263 select { 1264 case <-deferred: 1265 s.T().Logf("deferred callback executed after %v", time.Now().Sub(started)) 1266 case <-maxWait.C: 1267 s.Fail("deferred func should have been called within 1 second") 1268 } 1269 // if deferred code has run, this has already occurred-or-not. 1270 // if it timed out waiting for the deferred code, it has waited long enough, and this is mostly a curiosity. 1271 select { 1272 case <-after: 1273 s.Fail("code after sleep should not have run") 1274 default: 1275 s.T().Log("code after sleep correctly not executed") 1276 } 1277 } 1278 1279 var _ WorkflowInterceptorFactory = (*tracingInterceptorFactory)(nil) 1280 1281 type tracingInterceptorFactory struct { 1282 instances []*tracingInterceptor 1283 } 1284 1285 func (t *tracingInterceptorFactory) NewInterceptor(info *WorkflowInfo, next WorkflowInterceptor) WorkflowInterceptor { 1286 result := &tracingInterceptor{ 1287 WorkflowInterceptorBase: WorkflowInterceptorBase{Next: next}, 1288 } 1289 t.instances = append(t.instances, result) 1290 return result 1291 } 1292 1293 var _ WorkflowInterceptor = (*tracingInterceptor)(nil) 1294 1295 type tracingInterceptor struct { 1296 WorkflowInterceptorBase 1297 trace []string 1298 } 1299 1300 func (t *tracingInterceptor) ExecuteActivity(ctx Context, activityType string, args ...interface{}) Future { 1301 t.trace = append(t.trace, "ExecuteActivity "+activityType) 1302 return t.Next.ExecuteActivity(ctx, activityType, args...) 1303 } 1304 1305 func (t *tracingInterceptor) ExecuteWorkflow(ctx Context, workflowType string, args ...interface{}) []interface{} { 1306 t.trace = append(t.trace, "ExecuteWorkflow "+workflowType+" begin") 1307 result := t.Next.ExecuteWorkflow(ctx, workflowType, args...) 1308 t.trace = append(t.trace, "ExecuteWorkflow "+workflowType+" end") 1309 return result 1310 } 1311 1312 type WorkflowOptionTest struct { 1313 suite.Suite 1314 } 1315 1316 func TestWorkflowOption(t *testing.T) { 1317 suite.Run(t, new(WorkflowOptionTest)) 1318 } 1319 1320 func (t *WorkflowOptionTest) TestKnowQueryType_NoHandlers() { 1321 wo := workflowOptions{queryHandlers: make(map[string]func([]byte) ([]byte, error))} 1322 t.ElementsMatch( 1323 []string{ 1324 QueryTypeStackTrace, 1325 QueryTypeOpenSessions, 1326 QueryTypeQueryTypes, 1327 }, 1328 wo.KnownQueryTypes()) 1329 } 1330 1331 func (t *WorkflowOptionTest) TestKnowQueryType_WithHandlers() { 1332 wo := workflowOptions{queryHandlers: map[string]func([]byte) ([]byte, error){ 1333 "a": nil, 1334 "b": nil, 1335 }} 1336 1337 t.ElementsMatch( 1338 []string{ 1339 QueryTypeStackTrace, 1340 QueryTypeOpenSessions, 1341 QueryTypeQueryTypes, 1342 "a", 1343 "b", 1344 }, 1345 wo.KnownQueryTypes()) 1346 }