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  }