From 810a02225fbb3a59722d0ab16aca6a4da0f07860 Mon Sep 17 00:00:00 2001 From: taylan isikdemir Date: Tue, 7 May 2024 17:25:10 -0700 Subject: [PATCH 1/4] History engine start/stop unit tests --- common/resource/resource.go | 2 - .../engine/engineimpl/history_engine.go | 95 +- .../engineimpl/history_engine_suite_test.go | 5466 +++++++++++++++++ .../engine/engineimpl/history_engine_test.go | 5442 +--------------- .../engine/testdata/engine_for_tests.go | 186 + service/history/handler/handler.go | 3 + service/history/queue/factory.go | 128 + service/history/queue/factory_mock.go | 108 + service/history/replication/task_fetcher.go | 2 + .../history/replication/task_fetcher_mock.go | 185 + 10 files changed, 6130 insertions(+), 5487 deletions(-) create mode 100644 service/history/engine/engineimpl/history_engine_suite_test.go create mode 100644 service/history/engine/testdata/engine_for_tests.go create mode 100644 service/history/queue/factory.go create mode 100644 service/history/queue/factory_mock.go create mode 100644 service/history/replication/task_fetcher_mock.go diff --git a/common/resource/resource.go b/common/resource/resource.go index 6c1639622c3..da705cb017b 100644 --- a/common/resource/resource.go +++ b/common/resource/resource.go @@ -90,7 +90,6 @@ type ( GetClientBean() client.Bean // persistence clients - GetDomainManager() persistence.DomainManager GetTaskManager() persistence.TaskManager GetVisibilityManager() persistence.VisibilityManager @@ -103,7 +102,6 @@ type ( GetHostName() string // loggers - GetLogger() log.Logger GetThrottledLogger() log.Logger diff --git a/service/history/engine/engineimpl/history_engine.go b/service/history/engine/engineimpl/history_engine.go index b15b3f79790..8d52c1a5c82 100644 --- a/service/history/engine/engineimpl/history_engine.go +++ b/service/history/engine/engineimpl/history_engine.go @@ -80,52 +80,48 @@ var ( errDomainDeprecated = &types.BadRequestError{Message: "Domain is deprecated."} ) -type ( - historyEngineImpl struct { - currentClusterName string - shard shard.Context - timeSource clock.TimeSource - decisionHandler decision.Handler - clusterMetadata cluster.Metadata - historyV2Mgr persistence.HistoryManager - executionManager persistence.ExecutionManager - visibilityMgr persistence.VisibilityManager - txProcessor queue.Processor - timerProcessor queue.Processor - crossClusterProcessor queue.Processor - nDCReplicator ndc.HistoryReplicator - nDCActivityReplicator ndc.ActivityReplicator - historyEventNotifier events.Notifier - tokenSerializer common.TaskTokenSerializer - executionCache *execution.Cache - metricsClient metrics.Client - logger log.Logger - throttledLogger log.Logger - config *config.Config - archivalClient warchiver.Client - workflowResetter reset.WorkflowResetter - queueTaskProcessor task.Processor - crossClusterTaskProcessors common.Daemon - replicationTaskProcessors []replication.TaskProcessor - replicationAckManager replication.TaskAckManager - replicationTaskStore *replication.TaskStore - replicationHydrator replication.TaskHydrator - replicationMetricsEmitter *replication.MetricsEmitterImpl - publicClient workflowserviceclient.Interface - eventsReapplier ndc.EventsReapplier - matchingClient matching.Client - rawMatchingClient matching.Client - clientChecker client.VersionChecker - replicationDLQHandler replication.DLQHandler - failoverMarkerNotifier failover.MarkerNotifier - wfIDCache workflowcache.WFCache - ratelimitInternalPerWorkflowID dynamicconfig.BoolPropertyFnWithDomainFilter - - updateWithActionFn func(context.Context, *execution.Cache, string, types.WorkflowExecution, bool, time.Time, func(wfContext execution.Context, mutableState execution.MutableState) error) error - } -) - -var _ engine.Engine = (*historyEngineImpl)(nil) +type historyEngineImpl struct { + currentClusterName string + shard shard.Context + timeSource clock.TimeSource + decisionHandler decision.Handler + clusterMetadata cluster.Metadata + historyV2Mgr persistence.HistoryManager + executionManager persistence.ExecutionManager + visibilityMgr persistence.VisibilityManager + txProcessor queue.Processor + timerProcessor queue.Processor + crossClusterProcessor queue.Processor + nDCReplicator ndc.HistoryReplicator + nDCActivityReplicator ndc.ActivityReplicator + historyEventNotifier events.Notifier + tokenSerializer common.TaskTokenSerializer + executionCache *execution.Cache + metricsClient metrics.Client + logger log.Logger + throttledLogger log.Logger + config *config.Config + archivalClient warchiver.Client + workflowResetter reset.WorkflowResetter + queueTaskProcessor task.Processor + crossClusterTaskProcessors common.Daemon + replicationTaskProcessors []replication.TaskProcessor + replicationAckManager replication.TaskAckManager + replicationTaskStore *replication.TaskStore + replicationHydrator replication.TaskHydrator + replicationMetricsEmitter *replication.MetricsEmitterImpl + publicClient workflowserviceclient.Interface + eventsReapplier ndc.EventsReapplier + matchingClient matching.Client + rawMatchingClient matching.Client + clientChecker client.VersionChecker + replicationDLQHandler replication.DLQHandler + failoverMarkerNotifier failover.MarkerNotifier + wfIDCache workflowcache.WFCache + ratelimitInternalPerWorkflowID dynamicconfig.BoolPropertyFnWithDomainFilter + + updateWithActionFn func(context.Context, *execution.Cache, string, types.WorkflowExecution, bool, time.Time, func(wfContext execution.Context, mutableState execution.MutableState) error) error +} var ( // FailedWorkflowCloseState is a set of failed workflow close states, used for start workflow policy @@ -153,6 +149,7 @@ func NewEngineWithShardContext( failoverCoordinator failover.Coordinator, wfIDCache workflowcache.WFCache, ratelimitInternalPerWorkflowID dynamicconfig.BoolPropertyFnWithDomainFilter, + queueProcessorFactory queue.ProcessorFactory, ) engine.Engine { currentClusterName := shard.GetService().GetClusterMetadata().GetCurrentClusterName() @@ -251,7 +248,7 @@ func NewEngineWithShardContext( ) openExecutionCheck := invariant.NewConcreteExecutionExists(pRetry, shard.GetDomainCache()) - historyEngImpl.txProcessor = queue.NewTransferQueueProcessor( + historyEngImpl.txProcessor = queueProcessorFactory.NewTransferQueueProcessor( shard, historyEngImpl, queueTaskProcessor, @@ -263,7 +260,7 @@ func NewEngineWithShardContext( historyEngImpl.ratelimitInternalPerWorkflowID, ) - historyEngImpl.timerProcessor = queue.NewTimerQueueProcessor( + historyEngImpl.timerProcessor = queueProcessorFactory.NewTimerQueueProcessor( shard, historyEngImpl, queueTaskProcessor, @@ -272,7 +269,7 @@ func NewEngineWithShardContext( openExecutionCheck, ) - historyEngImpl.crossClusterProcessor = queue.NewCrossClusterQueueProcessor( + historyEngImpl.crossClusterProcessor = queueProcessorFactory.NewCrossClusterQueueProcessor( shard, historyEngImpl, executionCache, diff --git a/service/history/engine/engineimpl/history_engine_suite_test.go b/service/history/engine/engineimpl/history_engine_suite_test.go new file mode 100644 index 00000000000..aed2550367f --- /dev/null +++ b/service/history/engine/engineimpl/history_engine_suite_test.go @@ -0,0 +1,5466 @@ +// Copyright (c) 2017-2021 Uber Technologies Inc. +// Portions of the Software are attributed to Copyright (c) 2021 Temporal Technologies Inc. +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +// THE SOFTWARE. + +package engineimpl + +import ( + "context" + "encoding/json" + "errors" + "sync" + "testing" + "time" + + "github.com/golang/mock/gomock" + "github.com/pborman/uuid" + "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/mock" + "github.com/stretchr/testify/require" + "github.com/stretchr/testify/suite" + "github.com/uber-go/tally" + "go.uber.org/yarpc/api/encoding" + "go.uber.org/yarpc/api/transport" + + hclient "github.com/uber/cadence/client/history" + "github.com/uber/cadence/client/matching" + "github.com/uber/cadence/common" + "github.com/uber/cadence/common/cache" + cc "github.com/uber/cadence/common/client" + "github.com/uber/cadence/common/clock" + "github.com/uber/cadence/common/cluster" + "github.com/uber/cadence/common/dynamicconfig" + "github.com/uber/cadence/common/log/testlogger" + "github.com/uber/cadence/common/metrics" + "github.com/uber/cadence/common/mocks" + "github.com/uber/cadence/common/persistence" + "github.com/uber/cadence/common/types" + "github.com/uber/cadence/common/types/mapper/thrift" + "github.com/uber/cadence/service/history/config" + "github.com/uber/cadence/service/history/constants" + "github.com/uber/cadence/service/history/decision" + "github.com/uber/cadence/service/history/events" + "github.com/uber/cadence/service/history/execution" + "github.com/uber/cadence/service/history/ndc" + "github.com/uber/cadence/service/history/query" + "github.com/uber/cadence/service/history/queue" + "github.com/uber/cadence/service/history/reset" + "github.com/uber/cadence/service/history/shard" + test "github.com/uber/cadence/service/history/testing" + "github.com/uber/cadence/service/history/workflow" +) + +type ( + engineSuite struct { + suite.Suite + *require.Assertions + + controller *gomock.Controller + mockShard *shard.TestContext + mockTxProcessor *queue.MockProcessor + mockTimerProcessor *queue.MockProcessor + mockDomainCache *cache.MockDomainCache + mockHistoryClient *hclient.MockClient + mockMatchingClient *matching.MockClient + mockEventsReapplier *ndc.MockEventsReapplier + mockWorkflowResetter *reset.MockWorkflowResetter + + mockHistoryEngine *historyEngineImpl + mockExecutionMgr *mocks.ExecutionManager + mockHistoryV2Mgr *mocks.HistoryV2Manager + mockShardManager *mocks.ShardManager + + eventsCache events.Cache + config *config.Config + } +) + +func TestEngineSuite(t *testing.T) { + s := new(engineSuite) + suite.Run(t, s) +} + +func (s *engineSuite) SetupSuite() { + s.config = config.NewForTest() +} + +func (s *engineSuite) TearDownSuite() { +} + +func (s *engineSuite) SetupTest() { + s.Assertions = require.New(s.T()) + + s.controller = gomock.NewController(s.T()) + s.mockTxProcessor = queue.NewMockProcessor(s.controller) + s.mockTimerProcessor = queue.NewMockProcessor(s.controller) + s.mockEventsReapplier = ndc.NewMockEventsReapplier(s.controller) + s.mockWorkflowResetter = reset.NewMockWorkflowResetter(s.controller) + s.mockTxProcessor.EXPECT().NotifyNewTask(gomock.Any(), gomock.Any()).AnyTimes() + s.mockTimerProcessor.EXPECT().NotifyNewTask(gomock.Any(), gomock.Any()).AnyTimes() + + s.mockShard = shard.NewTestContext( + s.T(), + s.controller, + &persistence.ShardInfo{ + RangeID: 1, + TransferAckLevel: 0, + }, + s.config, + ) + s.eventsCache = events.NewCache( + s.mockShard.GetShardID(), + s.mockShard.GetHistoryManager(), + s.config, + s.mockShard.GetLogger(), + s.mockShard.GetMetricsClient(), + s.mockDomainCache, + ) + s.mockShard.SetEventsCache(s.eventsCache) + + s.mockMatchingClient = s.mockShard.Resource.MatchingClient + s.mockHistoryClient = s.mockShard.Resource.HistoryClient + s.mockExecutionMgr = s.mockShard.Resource.ExecutionMgr + s.mockHistoryV2Mgr = s.mockShard.Resource.HistoryMgr + s.mockShardManager = s.mockShard.Resource.ShardMgr + s.mockDomainCache = s.mockShard.Resource.DomainCache + s.mockDomainCache.EXPECT().GetDomainByID(constants.TestDomainID).Return(constants.TestLocalDomainEntry, nil).AnyTimes() + s.mockDomainCache.EXPECT().GetDomainName(constants.TestDomainID).Return(constants.TestDomainName, nil).AnyTimes() + s.mockDomainCache.EXPECT().GetDomain(constants.TestDomainName).Return(constants.TestLocalDomainEntry, nil).AnyTimes() + s.mockDomainCache.EXPECT().GetDomainID(constants.TestDomainName).Return(constants.TestDomainID, nil).AnyTimes() + + historyEventNotifier := events.NewNotifier( + clock.NewRealTimeSource(), + s.mockShard.Resource.MetricsClient, + func(workflowID string) int { + return len(workflowID) + }, + ) + + h := &historyEngineImpl{ + currentClusterName: s.mockShard.GetClusterMetadata().GetCurrentClusterName(), + shard: s.mockShard, + timeSource: s.mockShard.GetTimeSource(), + clusterMetadata: s.mockShard.Resource.ClusterMetadata, + executionManager: s.mockExecutionMgr, + historyV2Mgr: s.mockHistoryV2Mgr, + executionCache: execution.NewCache(s.mockShard), + logger: s.mockShard.GetLogger(), + metricsClient: s.mockShard.GetMetricsClient(), + tokenSerializer: common.NewJSONTaskTokenSerializer(), + historyEventNotifier: historyEventNotifier, + config: config.NewForTest(), + txProcessor: s.mockTxProcessor, + timerProcessor: s.mockTimerProcessor, + clientChecker: cc.NewVersionChecker(), + eventsReapplier: s.mockEventsReapplier, + workflowResetter: s.mockWorkflowResetter, + } + s.mockShard.SetEngine(h) + h.decisionHandler = decision.NewHandler(s.mockShard, h.executionCache, h.tokenSerializer) + + h.historyEventNotifier.Start() + + s.mockHistoryEngine = h +} + +func (s *engineSuite) TearDownTest() { + s.controller.Finish() + s.mockShard.Finish(s.T()) + s.mockHistoryEngine.historyEventNotifier.Stop() +} + +func (s *engineSuite) TestGetMutableStateSync() { + ctx := context.Background() + + workflowExecution := types.WorkflowExecution{ + WorkflowID: "test-get-workflow-execution-event-id", + RunID: constants.TestRunID, + } + tasklist := "testTaskList" + identity := "testIdentity" + + msBuilder := execution.NewMutableStateBuilderWithEventV2( + s.mockHistoryEngine.shard, + testlogger.New(s.Suite.T()), + workflowExecution.GetRunID(), + constants.TestLocalDomainEntry, + ) + test.AddWorkflowExecutionStartedEvent(msBuilder, workflowExecution, "wType", tasklist, []byte("input"), 100, 200, identity) + di := test.AddDecisionTaskScheduledEvent(msBuilder) + test.AddDecisionTaskStartedEvent(msBuilder, di.ScheduleID, tasklist, identity) + ms := execution.CreatePersistenceMutableState(msBuilder) + gweResponse := &persistence.GetWorkflowExecutionResponse{State: ms} + // right now the next event ID is 4 + s.mockExecutionMgr.On("GetWorkflowExecution", mock.Anything, mock.Anything).Return(gweResponse, nil).Once() + + // test get the next event ID instantly + response, err := s.mockHistoryEngine.GetMutableState(ctx, &types.GetMutableStateRequest{ + DomainUUID: constants.TestDomainID, + Execution: &workflowExecution, + }) + s.Nil(err) + s.Equal(int64(4), response.GetNextEventID()) +} + +func (s *engineSuite) TestGetMutableState_IntestRunID() { + ctx := context.Background() + + execution := types.WorkflowExecution{ + WorkflowID: "test-get-workflow-execution-event-id", + RunID: "run-id-not-valid-uuid", + } + + _, err := s.mockHistoryEngine.GetMutableState(ctx, &types.GetMutableStateRequest{ + DomainUUID: constants.TestDomainID, + Execution: &execution, + }) + s.Equal(constants.ErrRunIDNotValid, err) +} + +func (s *engineSuite) TestGetMutableState_EmptyRunID() { + ctx := context.Background() + + execution := types.WorkflowExecution{ + WorkflowID: "test-get-workflow-execution-event-id", + } + + s.mockExecutionMgr.On("GetCurrentExecution", mock.Anything, mock.Anything).Return(nil, &types.EntityNotExistsError{}).Once() + + _, err := s.mockHistoryEngine.GetMutableState(ctx, &types.GetMutableStateRequest{ + DomainUUID: constants.TestDomainID, + Execution: &execution, + }) + s.Equal(&types.EntityNotExistsError{}, err) +} + +func (s *engineSuite) TestGetMutableStateLongPoll() { + ctx := context.Background() + + workflowExecution := types.WorkflowExecution{ + WorkflowID: "test-get-workflow-execution-event-id", + RunID: constants.TestRunID, + } + tasklist := "testTaskList" + identity := "testIdentity" + + msBuilder := execution.NewMutableStateBuilderWithEventV2( + s.mockHistoryEngine.shard, + testlogger.New(s.Suite.T()), + workflowExecution.GetRunID(), + constants.TestLocalDomainEntry, + ) + test.AddWorkflowExecutionStartedEvent(msBuilder, workflowExecution, "wType", tasklist, []byte("input"), 100, 200, identity) + di := test.AddDecisionTaskScheduledEvent(msBuilder) + test.AddDecisionTaskStartedEvent(msBuilder, di.ScheduleID, tasklist, identity) + ms := execution.CreatePersistenceMutableState(msBuilder) + gweResponse := &persistence.GetWorkflowExecutionResponse{State: ms} + // right now the next event ID is 4 + s.mockExecutionMgr.On("GetWorkflowExecution", mock.Anything, mock.Anything).Return(gweResponse, nil).Once() + + // test long poll on next event ID change + waitGroup := &sync.WaitGroup{} + waitGroup.Add(1) + asycWorkflowUpdate := func(delay time.Duration) { + taskToken, _ := json.Marshal(&common.TaskToken{ + WorkflowID: workflowExecution.WorkflowID, + RunID: workflowExecution.RunID, + ScheduleID: 2, + }) + s.mockHistoryV2Mgr.On("AppendHistoryNodes", mock.Anything, mock.Anything).Return(&persistence.AppendHistoryNodesResponse{}, nil).Once() + s.mockExecutionMgr.On("UpdateWorkflowExecution", mock.Anything, mock.Anything).Return(&persistence.UpdateWorkflowExecutionResponse{MutableStateUpdateSessionStats: &persistence.MutableStateUpdateSessionStats{}}, nil).Once() + + timer := time.NewTimer(delay) + + <-timer.C + _, err := s.mockHistoryEngine.RespondDecisionTaskCompleted(context.Background(), &types.HistoryRespondDecisionTaskCompletedRequest{ + DomainUUID: constants.TestDomainID, + CompleteRequest: &types.RespondDecisionTaskCompletedRequest{ + TaskToken: taskToken, + Identity: identity, + }, + }) + s.Nil(err) + waitGroup.Done() + // right now the next event ID is 5 + } + + // return immediately, since the expected next event ID appears + response, err := s.mockHistoryEngine.GetMutableState(ctx, &types.GetMutableStateRequest{ + DomainUUID: constants.TestDomainID, + Execution: &workflowExecution, + ExpectedNextEventID: 3, + }) + s.Nil(err) + s.Equal(int64(4), response.NextEventID) + + // long poll, new event happen before long poll timeout + go asycWorkflowUpdate(time.Second * 2) + start := time.Now() + pollResponse, err := s.mockHistoryEngine.PollMutableState(ctx, &types.PollMutableStateRequest{ + DomainUUID: constants.TestDomainID, + Execution: &workflowExecution, + ExpectedNextEventID: 4, + }) + s.True(time.Now().After(start.Add(time.Second * 1))) + s.Nil(err) + s.Equal(int64(5), pollResponse.GetNextEventID()) + waitGroup.Wait() +} + +func (s *engineSuite) TestGetMutableStateLongPoll_CurrentBranchChanged() { + ctx := context.Background() + + workflowExecution := types.WorkflowExecution{ + WorkflowID: "test-get-workflow-execution-event-id", + RunID: constants.TestRunID, + } + tasklist := "testTaskList" + identity := "testIdentity" + + msBuilder := execution.NewMutableStateBuilderWithEventV2( + s.mockHistoryEngine.shard, + testlogger.New(s.Suite.T()), + workflowExecution.GetRunID(), + constants.TestLocalDomainEntry, + ) + test.AddWorkflowExecutionStartedEvent(msBuilder, workflowExecution, "wType", tasklist, []byte("input"), 100, 200, identity) + di := test.AddDecisionTaskScheduledEvent(msBuilder) + test.AddDecisionTaskStartedEvent(msBuilder, di.ScheduleID, tasklist, identity) + ms := execution.CreatePersistenceMutableState(msBuilder) + gweResponse := &persistence.GetWorkflowExecutionResponse{State: ms} + // right now the next event ID is 4 + s.mockExecutionMgr.On("GetWorkflowExecution", mock.Anything, mock.Anything).Return(gweResponse, nil).Once() + + // test long poll on next event ID change + asyncBranchTokenUpdate := func(delay time.Duration) { + timer := time.NewTimer(delay) + <-timer.C + newExecution := &types.WorkflowExecution{ + WorkflowID: workflowExecution.WorkflowID, + RunID: workflowExecution.RunID, + } + s.mockHistoryEngine.historyEventNotifier.NotifyNewHistoryEvent(events.NewNotification( + "constants.TestDomainID", + newExecution, + int64(1), + int64(4), + int64(1), + []byte{1}, + persistence.WorkflowStateCreated, + persistence.WorkflowCloseStatusNone)) + } + + // return immediately, since the expected next event ID appears + response0, err := s.mockHistoryEngine.GetMutableState(ctx, &types.GetMutableStateRequest{ + DomainUUID: constants.TestDomainID, + Execution: &workflowExecution, + ExpectedNextEventID: 3, + }) + s.Nil(err) + s.Equal(int64(4), response0.GetNextEventID()) + + // long poll, new event happen before long poll timeout + go asyncBranchTokenUpdate(time.Second * 2) + start := time.Now() + response1, err := s.mockHistoryEngine.GetMutableState(ctx, &types.GetMutableStateRequest{ + DomainUUID: constants.TestDomainID, + Execution: &workflowExecution, + ExpectedNextEventID: 10, + }) + s.True(time.Now().After(start.Add(time.Second * 1))) + s.Nil(err) + s.Equal(response0.GetCurrentBranchToken(), response1.GetCurrentBranchToken()) +} + +func (s *engineSuite) TestGetMutableStateLongPollTimeout() { + ctx := context.Background() + + workflowExecution := types.WorkflowExecution{ + WorkflowID: "test-get-workflow-execution-event-id", + RunID: constants.TestRunID, + } + tasklist := "testTaskList" + identity := "testIdentity" + + msBuilder := execution.NewMutableStateBuilderWithEventV2( + s.mockHistoryEngine.shard, + testlogger.New(s.Suite.T()), + workflowExecution.GetRunID(), + constants.TestLocalDomainEntry, + ) + test.AddWorkflowExecutionStartedEvent(msBuilder, workflowExecution, "wType", tasklist, []byte("input"), 100, 200, identity) + di := test.AddDecisionTaskScheduledEvent(msBuilder) + test.AddDecisionTaskStartedEvent(msBuilder, di.ScheduleID, tasklist, identity) + ms := execution.CreatePersistenceMutableState(msBuilder) + gweResponse := &persistence.GetWorkflowExecutionResponse{State: ms} + // right now the next event ID is 4 + s.mockExecutionMgr.On("GetWorkflowExecution", mock.Anything, mock.Anything).Return(gweResponse, nil).Once() + + // long poll, no event happen after long poll timeout + response, err := s.mockHistoryEngine.GetMutableState(ctx, &types.GetMutableStateRequest{ + DomainUUID: constants.TestDomainID, + Execution: &workflowExecution, + ExpectedNextEventID: 4, + }) + s.Nil(err) + s.Equal(int64(4), response.GetNextEventID()) +} + +func (s *engineSuite) TestQueryWorkflow_RejectBasedOnNotEnabled() { + s.mockHistoryEngine.config.EnableConsistentQueryByDomain = dynamicconfig.GetBoolPropertyFnFilteredByDomain(false) + request := &types.HistoryQueryWorkflowRequest{ + DomainUUID: constants.TestDomainID, + Request: &types.QueryWorkflowRequest{ + QueryConsistencyLevel: types.QueryConsistencyLevelStrong.Ptr(), + }, + } + resp, err := s.mockHistoryEngine.QueryWorkflow(context.Background(), request) + s.Nil(resp) + s.Equal(workflow.ErrConsistentQueryNotEnabled, err) + + s.mockHistoryEngine.config.EnableConsistentQueryByDomain = dynamicconfig.GetBoolPropertyFnFilteredByDomain(true) + s.mockHistoryEngine.config.EnableConsistentQuery = dynamicconfig.GetBoolPropertyFn(false) + resp, err = s.mockHistoryEngine.QueryWorkflow(context.Background(), request) + s.Nil(resp) + s.Equal(workflow.ErrConsistentQueryNotEnabled, err) +} + +func (s *engineSuite) TestQueryWorkflow_RejectBasedOnCompleted() { + workflowExecution := types.WorkflowExecution{ + WorkflowID: "TestQueryWorkflow_RejectBasedOnCompleted", + RunID: constants.TestRunID, + } + tasklist := "testTaskList" + identity := "testIdentity" + + msBuilder := execution.NewMutableStateBuilderWithEventV2( + s.mockHistoryEngine.shard, + testlogger.New(s.Suite.T()), + workflowExecution.GetRunID(), + constants.TestLocalDomainEntry, + ) + test.AddWorkflowExecutionStartedEvent(msBuilder, workflowExecution, "wType", tasklist, []byte("input"), 100, 200, identity) + di := test.AddDecisionTaskScheduledEvent(msBuilder) + event := test.AddDecisionTaskStartedEvent(msBuilder, di.ScheduleID, tasklist, identity) + di.StartedID = event.ID + event = test.AddDecisionTaskCompletedEvent(msBuilder, di.ScheduleID, di.StartedID, nil, "some random identity") + test.AddCompleteWorkflowEvent(msBuilder, event.ID, nil) + ms := execution.CreatePersistenceMutableState(msBuilder) + gweResponse := &persistence.GetWorkflowExecutionResponse{State: ms} + s.mockExecutionMgr.On("GetWorkflowExecution", mock.Anything, mock.Anything).Return(gweResponse, nil).Once() + + request := &types.HistoryQueryWorkflowRequest{ + DomainUUID: constants.TestDomainID, + Request: &types.QueryWorkflowRequest{ + Execution: &workflowExecution, + Query: &types.WorkflowQuery{}, + QueryRejectCondition: types.QueryRejectConditionNotOpen.Ptr(), + }, + } + resp, err := s.mockHistoryEngine.QueryWorkflow(context.Background(), request) + s.NoError(err) + s.Nil(resp.GetResponse().QueryResult) + s.NotNil(resp.GetResponse().QueryRejected) + s.Equal(types.WorkflowExecutionCloseStatusCompleted.Ptr(), resp.GetResponse().GetQueryRejected().CloseStatus) +} + +func (s *engineSuite) TestQueryWorkflow_RejectBasedOnFailed() { + workflowExecution := types.WorkflowExecution{ + WorkflowID: "TestQueryWorkflow_RejectBasedOnFailed", + RunID: constants.TestRunID, + } + tasklist := "testTaskList" + identity := "testIdentity" + + msBuilder := execution.NewMutableStateBuilderWithEventV2( + s.mockHistoryEngine.shard, + testlogger.New(s.Suite.T()), + workflowExecution.GetRunID(), + constants.TestLocalDomainEntry, + ) + test.AddWorkflowExecutionStartedEvent(msBuilder, workflowExecution, "wType", tasklist, []byte("input"), 100, 200, identity) + di := test.AddDecisionTaskScheduledEvent(msBuilder) + event := test.AddDecisionTaskStartedEvent(msBuilder, di.ScheduleID, tasklist, identity) + di.StartedID = event.ID + event = test.AddDecisionTaskCompletedEvent(msBuilder, di.ScheduleID, di.StartedID, nil, "some random identity") + test.AddFailWorkflowEvent(msBuilder, event.ID, "failure reason", []byte{1, 2, 3}) + ms := execution.CreatePersistenceMutableState(msBuilder) + gweResponse := &persistence.GetWorkflowExecutionResponse{State: ms} + s.mockExecutionMgr.On("GetWorkflowExecution", mock.Anything, mock.Anything).Return(gweResponse, nil).Once() + + request := &types.HistoryQueryWorkflowRequest{ + DomainUUID: constants.TestDomainID, + Request: &types.QueryWorkflowRequest{ + Execution: &workflowExecution, + Query: &types.WorkflowQuery{}, + QueryRejectCondition: types.QueryRejectConditionNotOpen.Ptr(), + }, + } + resp, err := s.mockHistoryEngine.QueryWorkflow(context.Background(), request) + s.NoError(err) + s.Nil(resp.GetResponse().QueryResult) + s.NotNil(resp.GetResponse().QueryRejected) + s.Equal(types.WorkflowExecutionCloseStatusFailed.Ptr(), resp.GetResponse().GetQueryRejected().CloseStatus) + + request = &types.HistoryQueryWorkflowRequest{ + DomainUUID: constants.TestDomainID, + Request: &types.QueryWorkflowRequest{ + Execution: &workflowExecution, + Query: &types.WorkflowQuery{}, + QueryRejectCondition: types.QueryRejectConditionNotCompletedCleanly.Ptr(), + }, + } + resp, err = s.mockHistoryEngine.QueryWorkflow(context.Background(), request) + s.NoError(err) + s.Nil(resp.GetResponse().QueryResult) + s.NotNil(resp.GetResponse().QueryRejected) + s.Equal(types.WorkflowExecutionCloseStatusFailed.Ptr(), resp.GetResponse().GetQueryRejected().CloseStatus) +} + +func (s *engineSuite) TestQueryWorkflow_FirstDecisionNotCompleted() { + workflowExecution := types.WorkflowExecution{ + WorkflowID: "TestQueryWorkflow_FirstDecisionNotCompleted", + RunID: constants.TestRunID, + } + tasklist := "testTaskList" + identity := "testIdentity" + + msBuilder := execution.NewMutableStateBuilderWithEventV2( + s.mockHistoryEngine.shard, + testlogger.New(s.Suite.T()), + workflowExecution.GetRunID(), + constants.TestLocalDomainEntry, + ) + test.AddWorkflowExecutionStartedEvent(msBuilder, workflowExecution, "wType", tasklist, []byte("input"), 100, 200, identity) + di := test.AddDecisionTaskScheduledEvent(msBuilder) + test.AddDecisionTaskStartedEvent(msBuilder, di.ScheduleID, tasklist, identity) + ms := execution.CreatePersistenceMutableState(msBuilder) + gweResponse := &persistence.GetWorkflowExecutionResponse{State: ms} + s.mockExecutionMgr.On("GetWorkflowExecution", mock.Anything, mock.Anything).Return(gweResponse, nil).Once() + + request := &types.HistoryQueryWorkflowRequest{ + DomainUUID: constants.TestDomainID, + Request: &types.QueryWorkflowRequest{ + Execution: &workflowExecution, + Query: &types.WorkflowQuery{}, + }, + } + resp, err := s.mockHistoryEngine.QueryWorkflow(context.Background(), request) + s.Equal(workflow.ErrQueryWorkflowBeforeFirstDecision, err) + s.Nil(resp) +} + +func (s *engineSuite) TestQueryWorkflow_DirectlyThroughMatching() { + workflowExecution := types.WorkflowExecution{ + WorkflowID: "TestQueryWorkflow_DirectlyThroughMatching", + RunID: constants.TestRunID, + } + tasklist := "testTaskList" + identity := "testIdentity" + + msBuilder := execution.NewMutableStateBuilderWithEventV2( + s.mockHistoryEngine.shard, + testlogger.New(s.Suite.T()), + workflowExecution.GetRunID(), + constants.TestLocalDomainEntry, + ) + test.AddWorkflowExecutionStartedEvent(msBuilder, workflowExecution, "wType", tasklist, []byte("input"), 100, 200, identity) + di := test.AddDecisionTaskScheduledEvent(msBuilder) + startedEvent := test.AddDecisionTaskStartedEvent(msBuilder, di.ScheduleID, tasklist, identity) + test.AddDecisionTaskCompletedEvent(msBuilder, di.ScheduleID, startedEvent.ID, nil, identity) + di = test.AddDecisionTaskScheduledEvent(msBuilder) + test.AddDecisionTaskStartedEvent(msBuilder, di.ScheduleID, tasklist, identity) + + ms := execution.CreatePersistenceMutableState(msBuilder) + gweResponse := &persistence.GetWorkflowExecutionResponse{State: ms} + s.mockExecutionMgr.On("GetWorkflowExecution", mock.Anything, mock.Anything).Return(gweResponse, nil).Once() + s.mockMatchingClient.EXPECT().QueryWorkflow(gomock.Any(), gomock.Any()).Return(&types.QueryWorkflowResponse{QueryResult: []byte{1, 2, 3}}, nil) + s.mockHistoryEngine.matchingClient = s.mockMatchingClient + request := &types.HistoryQueryWorkflowRequest{ + DomainUUID: constants.TestDomainID, + Request: &types.QueryWorkflowRequest{ + Execution: &workflowExecution, + Query: &types.WorkflowQuery{}, + // since workflow is open this filter does not reject query + QueryRejectCondition: types.QueryRejectConditionNotOpen.Ptr(), + QueryConsistencyLevel: types.QueryConsistencyLevelEventual.Ptr(), + }, + } + resp, err := s.mockHistoryEngine.QueryWorkflow(context.Background(), request) + s.NoError(err) + s.NotNil(resp.GetResponse().QueryResult) + s.Nil(resp.GetResponse().QueryRejected) + s.Equal([]byte{1, 2, 3}, resp.GetResponse().GetQueryResult()) +} + +func (s *engineSuite) TestQueryWorkflow_DecisionTaskDispatch_Timeout() { + workflowExecution := types.WorkflowExecution{ + WorkflowID: "TestQueryWorkflow_DecisionTaskDispatch_Timeout", + RunID: constants.TestRunID, + } + tasklist := "testTaskList" + identity := "testIdentity" + msBuilder := execution.NewMutableStateBuilderWithEventV2( + s.mockHistoryEngine.shard, + testlogger.New(s.Suite.T()), + workflowExecution.GetRunID(), + constants.TestLocalDomainEntry, + ) + test.AddWorkflowExecutionStartedEvent(msBuilder, workflowExecution, "wType", tasklist, []byte("input"), 100, 200, identity) + di := test.AddDecisionTaskScheduledEvent(msBuilder) + startedEvent := test.AddDecisionTaskStartedEvent(msBuilder, di.ScheduleID, tasklist, identity) + test.AddDecisionTaskCompletedEvent(msBuilder, di.ScheduleID, startedEvent.ID, nil, identity) + di = test.AddDecisionTaskScheduledEvent(msBuilder) + test.AddDecisionTaskStartedEvent(msBuilder, di.ScheduleID, tasklist, identity) + + ms := execution.CreatePersistenceMutableState(msBuilder) + gweResponse := &persistence.GetWorkflowExecutionResponse{State: ms} + s.mockExecutionMgr.On("GetWorkflowExecution", mock.Anything, mock.Anything).Return(gweResponse, nil).Once() + request := &types.HistoryQueryWorkflowRequest{ + DomainUUID: constants.TestDomainID, + Request: &types.QueryWorkflowRequest{ + Execution: &workflowExecution, + Query: &types.WorkflowQuery{}, + // since workflow is open this filter does not reject query + QueryRejectCondition: types.QueryRejectConditionNotOpen.Ptr(), + QueryConsistencyLevel: types.QueryConsistencyLevelStrong.Ptr(), + }, + } + + wg := &sync.WaitGroup{} + wg.Add(1) + go func() { + ctx, cancel := context.WithTimeout(context.Background(), time.Second*2) + defer cancel() + resp, err := s.mockHistoryEngine.QueryWorkflow(ctx, request) + s.Error(err) + s.Nil(resp) + wg.Done() + }() + + <-time.After(time.Second) + builder := s.getBuilder(constants.TestDomainID, workflowExecution) + s.NotNil(builder) + qr := builder.GetQueryRegistry() + s.True(qr.HasBufferedQuery()) + s.False(qr.HasCompletedQuery()) + s.False(qr.HasUnblockedQuery()) + s.False(qr.HasFailedQuery()) + wg.Wait() + s.False(qr.HasBufferedQuery()) + s.False(qr.HasCompletedQuery()) + s.False(qr.HasUnblockedQuery()) + s.False(qr.HasFailedQuery()) +} + +func (s *engineSuite) TestQueryWorkflow_ConsistentQueryBufferFull() { + workflowExecution := types.WorkflowExecution{ + WorkflowID: "TestQueryWorkflow_ConsistentQueryBufferFull", + RunID: constants.TestRunID, + } + tasklist := "testTaskList" + identity := "testIdentity" + msBuilder := execution.NewMutableStateBuilderWithEventV2( + s.mockHistoryEngine.shard, + testlogger.New(s.Suite.T()), + workflowExecution.GetRunID(), + constants.TestLocalDomainEntry, + ) + test.AddWorkflowExecutionStartedEvent(msBuilder, workflowExecution, "wType", tasklist, []byte("input"), 100, 200, identity) + di := test.AddDecisionTaskScheduledEvent(msBuilder) + startedEvent := test.AddDecisionTaskStartedEvent(msBuilder, di.ScheduleID, tasklist, identity) + test.AddDecisionTaskCompletedEvent(msBuilder, di.ScheduleID, startedEvent.ID, nil, identity) + di = test.AddDecisionTaskScheduledEvent(msBuilder) + test.AddDecisionTaskStartedEvent(msBuilder, di.ScheduleID, tasklist, identity) + + ms := execution.CreatePersistenceMutableState(msBuilder) + gweResponse := &persistence.GetWorkflowExecutionResponse{State: ms} + s.mockExecutionMgr.On("GetWorkflowExecution", mock.Anything, mock.Anything).Return(gweResponse, nil).Once() + + // buffer query so that when types.QueryWorkflow is called buffer is already full + ctx, release, err := s.mockHistoryEngine.executionCache.GetOrCreateWorkflowExecutionForBackground(constants.TestDomainID, workflowExecution) + s.NoError(err) + loadedMS, err := ctx.LoadWorkflowExecution(context.Background()) + s.NoError(err) + qr := query.NewRegistry() + qr.BufferQuery(&types.WorkflowQuery{}) + loadedMS.SetQueryRegistry(qr) + release(nil) + + request := &types.HistoryQueryWorkflowRequest{ + DomainUUID: constants.TestDomainID, + Request: &types.QueryWorkflowRequest{ + Execution: &workflowExecution, + Query: &types.WorkflowQuery{}, + QueryConsistencyLevel: types.QueryConsistencyLevelStrong.Ptr(), + }, + } + resp, err := s.mockHistoryEngine.QueryWorkflow(context.Background(), request) + s.Nil(resp) + s.Equal(workflow.ErrConsistentQueryBufferExceeded, err) +} + +func (s *engineSuite) TestQueryWorkflow_DecisionTaskDispatch_Complete() { + workflowExecution := types.WorkflowExecution{ + WorkflowID: "TestQueryWorkflow_DecisionTaskDispatch_Complete", + RunID: constants.TestRunID, + } + tasklist := "testTaskList" + identity := "testIdentity" + msBuilder := execution.NewMutableStateBuilderWithEventV2( + s.mockHistoryEngine.shard, + testlogger.New(s.Suite.T()), + workflowExecution.GetRunID(), + constants.TestLocalDomainEntry, + ) + test.AddWorkflowExecutionStartedEvent(msBuilder, workflowExecution, "wType", tasklist, []byte("input"), 100, 200, identity) + di := test.AddDecisionTaskScheduledEvent(msBuilder) + startedEvent := test.AddDecisionTaskStartedEvent(msBuilder, di.ScheduleID, tasklist, identity) + test.AddDecisionTaskCompletedEvent(msBuilder, di.ScheduleID, startedEvent.ID, nil, identity) + di = test.AddDecisionTaskScheduledEvent(msBuilder) + test.AddDecisionTaskStartedEvent(msBuilder, di.ScheduleID, tasklist, identity) + + ms := execution.CreatePersistenceMutableState(msBuilder) + gweResponse := &persistence.GetWorkflowExecutionResponse{State: ms} + s.mockExecutionMgr.On("GetWorkflowExecution", mock.Anything, mock.Anything).Return(gweResponse, nil).Once() + + waitGroup := &sync.WaitGroup{} + waitGroup.Add(1) + asyncQueryUpdate := func(delay time.Duration, answer []byte) { + defer waitGroup.Done() + <-time.After(delay) + builder := s.getBuilder(constants.TestDomainID, workflowExecution) + s.NotNil(builder) + qr := builder.GetQueryRegistry() + buffered := qr.GetBufferedIDs() + for _, id := range buffered { + resultType := types.QueryResultTypeAnswered + completedTerminationState := &query.TerminationState{ + TerminationType: query.TerminationTypeCompleted, + QueryResult: &types.WorkflowQueryResult{ + ResultType: &resultType, + Answer: answer, + }, + } + err := qr.SetTerminationState(id, completedTerminationState) + s.NoError(err) + state, err := qr.GetTerminationState(id) + s.NoError(err) + s.Equal(query.TerminationTypeCompleted, state.TerminationType) + } + } + + request := &types.HistoryQueryWorkflowRequest{ + DomainUUID: constants.TestDomainID, + Request: &types.QueryWorkflowRequest{ + Execution: &workflowExecution, + Query: &types.WorkflowQuery{}, + QueryConsistencyLevel: types.QueryConsistencyLevelStrong.Ptr(), + }, + } + go asyncQueryUpdate(time.Second*2, []byte{1, 2, 3}) + start := time.Now() + resp, err := s.mockHistoryEngine.QueryWorkflow(context.Background(), request) + s.True(time.Now().After(start.Add(time.Second))) + s.NoError(err) + s.Equal([]byte{1, 2, 3}, resp.GetResponse().GetQueryResult()) + builder := s.getBuilder(constants.TestDomainID, workflowExecution) + s.NotNil(builder) + qr := builder.GetQueryRegistry() + s.False(qr.HasBufferedQuery()) + s.False(qr.HasCompletedQuery()) + waitGroup.Wait() +} + +func (s *engineSuite) TestQueryWorkflow_DecisionTaskDispatch_Unblocked() { + workflowExecution := types.WorkflowExecution{ + WorkflowID: "TestQueryWorkflow_DecisionTaskDispatch_Unblocked", + RunID: constants.TestRunID, + } + tasklist := "testTaskList" + identity := "testIdentity" + msBuilder := execution.NewMutableStateBuilderWithEventV2( + s.mockHistoryEngine.shard, + testlogger.New(s.Suite.T()), + workflowExecution.GetRunID(), + constants.TestLocalDomainEntry, + ) + test.AddWorkflowExecutionStartedEvent(msBuilder, workflowExecution, "wType", tasklist, []byte("input"), 100, 200, identity) + di := test.AddDecisionTaskScheduledEvent(msBuilder) + startedEvent := test.AddDecisionTaskStartedEvent(msBuilder, di.ScheduleID, tasklist, identity) + test.AddDecisionTaskCompletedEvent(msBuilder, di.ScheduleID, startedEvent.ID, nil, identity) + di = test.AddDecisionTaskScheduledEvent(msBuilder) + test.AddDecisionTaskStartedEvent(msBuilder, di.ScheduleID, tasklist, identity) + + ms := execution.CreatePersistenceMutableState(msBuilder) + gweResponse := &persistence.GetWorkflowExecutionResponse{State: ms} + s.mockExecutionMgr.On("GetWorkflowExecution", mock.Anything, mock.Anything).Return(gweResponse, nil).Once() + s.mockMatchingClient.EXPECT().QueryWorkflow(gomock.Any(), gomock.Any()).Return(&types.QueryWorkflowResponse{QueryResult: []byte{1, 2, 3}}, nil) + s.mockHistoryEngine.matchingClient = s.mockMatchingClient + waitGroup := &sync.WaitGroup{} + waitGroup.Add(1) + asyncQueryUpdate := func(delay time.Duration, answer []byte) { + defer waitGroup.Done() + <-time.After(delay) + builder := s.getBuilder(constants.TestDomainID, workflowExecution) + s.NotNil(builder) + qr := builder.GetQueryRegistry() + buffered := qr.GetBufferedIDs() + for _, id := range buffered { + s.NoError(qr.SetTerminationState(id, &query.TerminationState{TerminationType: query.TerminationTypeUnblocked})) + state, err := qr.GetTerminationState(id) + s.NoError(err) + s.Equal(query.TerminationTypeUnblocked, state.TerminationType) + } + } + + request := &types.HistoryQueryWorkflowRequest{ + DomainUUID: constants.TestDomainID, + Request: &types.QueryWorkflowRequest{ + Execution: &workflowExecution, + Query: &types.WorkflowQuery{}, + QueryConsistencyLevel: types.QueryConsistencyLevelStrong.Ptr(), + }, + } + go asyncQueryUpdate(time.Second*2, []byte{1, 2, 3}) + start := time.Now() + resp, err := s.mockHistoryEngine.QueryWorkflow(context.Background(), request) + s.True(time.Now().After(start.Add(time.Second))) + s.NoError(err) + s.Equal([]byte{1, 2, 3}, resp.GetResponse().GetQueryResult()) + builder := s.getBuilder(constants.TestDomainID, workflowExecution) + s.NotNil(builder) + qr := builder.GetQueryRegistry() + s.False(qr.HasBufferedQuery()) + s.False(qr.HasCompletedQuery()) + s.False(qr.HasUnblockedQuery()) + waitGroup.Wait() +} + +func (s *engineSuite) TestRespondDecisionTaskCompletedInvalidToken() { + + invalidToken, _ := json.Marshal("bad token") + identity := "testIdentity" + + _, err := s.mockHistoryEngine.RespondDecisionTaskCompleted(context.Background(), &types.HistoryRespondDecisionTaskCompletedRequest{ + DomainUUID: constants.TestDomainID, + CompleteRequest: &types.RespondDecisionTaskCompletedRequest{ + TaskToken: invalidToken, + Decisions: nil, + ExecutionContext: nil, + Identity: identity, + }, + }) + + s.NotNil(err) + s.IsType(&types.BadRequestError{}, err) +} + +func (s *engineSuite) TestRespondDecisionTaskCompletedIfNoExecution() { + + taskToken, _ := json.Marshal(&common.TaskToken{ + WorkflowID: "wId", + RunID: constants.TestRunID, + ScheduleID: 2, + }) + identity := "testIdentity" + + s.mockExecutionMgr.On("GetWorkflowExecution", mock.Anything, mock.Anything).Return(nil, &types.EntityNotExistsError{}).Once() + + _, err := s.mockHistoryEngine.RespondDecisionTaskCompleted(context.Background(), &types.HistoryRespondDecisionTaskCompletedRequest{ + DomainUUID: constants.TestDomainID, + CompleteRequest: &types.RespondDecisionTaskCompletedRequest{ + TaskToken: taskToken, + Identity: identity, + }, + }) + s.NotNil(err) + s.IsType(&types.EntityNotExistsError{}, err) +} + +func (s *engineSuite) TestRespondDecisionTaskCompletedIfGetExecutionFailed() { + + taskToken, _ := json.Marshal(&common.TaskToken{ + WorkflowID: "wId", + RunID: constants.TestRunID, + ScheduleID: 2, + }) + identity := "testIdentity" + + s.mockExecutionMgr.On("GetWorkflowExecution", mock.Anything, mock.Anything).Return(nil, errors.New("FAILED")).Once() + + _, err := s.mockHistoryEngine.RespondDecisionTaskCompleted(context.Background(), &types.HistoryRespondDecisionTaskCompletedRequest{ + DomainUUID: constants.TestDomainID, + CompleteRequest: &types.RespondDecisionTaskCompletedRequest{ + TaskToken: taskToken, + Identity: identity, + }, + }) + s.EqualError(err, "FAILED") +} + +func (s *engineSuite) TestRespondDecisionTaskCompletedUpdateExecutionFailed() { + + we := types.WorkflowExecution{ + WorkflowID: "wId", + RunID: constants.TestRunID, + } + tl := "testTaskList" + + taskToken, _ := json.Marshal(&common.TaskToken{ + WorkflowID: we.WorkflowID, + RunID: we.RunID, + ScheduleID: 2, + }) + identity := "testIdentity" + + msBuilder := execution.NewMutableStateBuilderWithEventV2( + s.mockHistoryEngine.shard, + testlogger.New(s.Suite.T()), + we.GetRunID(), + constants.TestLocalDomainEntry, + ) + test.AddWorkflowExecutionStartedEvent(msBuilder, we, "wType", tl, []byte("input"), 100, 200, identity) + di := test.AddDecisionTaskScheduledEvent(msBuilder) + test.AddDecisionTaskStartedEvent(msBuilder, di.ScheduleID, tl, identity) + + ms := execution.CreatePersistenceMutableState(msBuilder) + gwmsResponse := &persistence.GetWorkflowExecutionResponse{State: ms} + + s.mockExecutionMgr.On("GetWorkflowExecution", mock.Anything, mock.Anything).Return(gwmsResponse, nil).Once() + s.mockHistoryV2Mgr.On("AppendHistoryNodes", mock.Anything, mock.Anything).Return(&persistence.AppendHistoryNodesResponse{}, nil).Once() + s.mockExecutionMgr.On("UpdateWorkflowExecution", mock.Anything, mock.Anything).Return(&persistence.UpdateWorkflowExecutionResponse{MutableStateUpdateSessionStats: &persistence.MutableStateUpdateSessionStats{}}, errors.New("FAILED")).Once() + s.mockShardManager.On("UpdateShard", mock.Anything, mock.Anything).Return(nil).Once() + + _, err := s.mockHistoryEngine.RespondDecisionTaskCompleted(context.Background(), &types.HistoryRespondDecisionTaskCompletedRequest{ + DomainUUID: constants.TestDomainID, + CompleteRequest: &types.RespondDecisionTaskCompletedRequest{ + TaskToken: taskToken, + Identity: identity, + }, + }) + s.NotNil(err) + s.EqualError(err, "FAILED") +} + +func (s *engineSuite) TestRespondDecisionTaskCompletedIfTaskCompleted() { + + we := types.WorkflowExecution{ + WorkflowID: "wId", + RunID: constants.TestRunID, + } + tl := "testTaskList" + taskToken, _ := json.Marshal(&common.TaskToken{ + WorkflowID: we.WorkflowID, + RunID: we.RunID, + ScheduleID: 2, + }) + identity := "testIdentity" + + msBuilder := execution.NewMutableStateBuilderWithEventV2( + s.mockHistoryEngine.shard, + testlogger.New(s.Suite.T()), + we.GetRunID(), + constants.TestLocalDomainEntry, + ) + test.AddWorkflowExecutionStartedEvent(msBuilder, we, "wType", tl, []byte("input"), 100, 200, identity) + di := test.AddDecisionTaskScheduledEvent(msBuilder) + startedEvent := test.AddDecisionTaskStartedEvent(msBuilder, di.ScheduleID, tl, identity) + test.AddDecisionTaskCompletedEvent(msBuilder, di.ScheduleID, startedEvent.ID, nil, identity) + + ms := execution.CreatePersistenceMutableState(msBuilder) + gwmsResponse := &persistence.GetWorkflowExecutionResponse{State: ms} + + s.mockExecutionMgr.On("GetWorkflowExecution", mock.Anything, mock.Anything).Return(gwmsResponse, nil).Once() + + _, err := s.mockHistoryEngine.RespondDecisionTaskCompleted(context.Background(), &types.HistoryRespondDecisionTaskCompletedRequest{ + DomainUUID: constants.TestDomainID, + CompleteRequest: &types.RespondDecisionTaskCompletedRequest{ + TaskToken: taskToken, + Identity: identity, + }, + }) + s.NotNil(err) + s.IsType(&types.EntityNotExistsError{}, err) +} + +func (s *engineSuite) TestRespondDecisionTaskCompletedIfTaskNotStarted() { + + we := types.WorkflowExecution{ + WorkflowID: "wId", + RunID: constants.TestRunID, + } + tl := "testTaskList" + taskToken, _ := json.Marshal(&common.TaskToken{ + WorkflowID: we.WorkflowID, + RunID: we.RunID, + ScheduleID: 2, + }) + identity := "testIdentity" + + msBuilder := execution.NewMutableStateBuilderWithEventV2( + s.mockHistoryEngine.shard, + testlogger.New(s.Suite.T()), + we.GetRunID(), + constants.TestLocalDomainEntry, + ) + test.AddWorkflowExecutionStartedEvent(msBuilder, we, "wType", tl, []byte("input"), 100, 200, identity) + test.AddDecisionTaskScheduledEvent(msBuilder) + + ms := execution.CreatePersistenceMutableState(msBuilder) + gwmsResponse := &persistence.GetWorkflowExecutionResponse{State: ms} + + s.mockExecutionMgr.On("GetWorkflowExecution", mock.Anything, mock.Anything).Return(gwmsResponse, nil).Once() + + _, err := s.mockHistoryEngine.RespondDecisionTaskCompleted(context.Background(), &types.HistoryRespondDecisionTaskCompletedRequest{ + DomainUUID: constants.TestDomainID, + CompleteRequest: &types.RespondDecisionTaskCompletedRequest{ + TaskToken: taskToken, + }, + }) + s.NotNil(err) + s.IsType(&types.EntityNotExistsError{}, err) +} + +func (s *engineSuite) TestRespondDecisionTaskCompletedConflictOnUpdate() { + + we := types.WorkflowExecution{ + WorkflowID: "wId", + RunID: constants.TestRunID, + } + tl := "testTaskList" + identity := "testIdentity" + executionContext := []byte("context") + activity1ID := "activity1" + activity1Type := "activity_type1" + activity1Input := []byte("input1") + activity1Result := []byte("activity1_result") + activity2ID := "activity2" + activity2Type := "activity_type2" + activity2Input := []byte("input2") + activity2Result := []byte("activity2_result") + activity3ID := "activity3" + activity3Type := "activity_type3" + activity3Input := []byte("input3") + + msBuilder := execution.NewMutableStateBuilderWithEventV2( + s.mockHistoryEngine.shard, + testlogger.New(s.Suite.T()), + we.GetRunID(), + constants.TestLocalDomainEntry, + ) + test.AddWorkflowExecutionStartedEvent(msBuilder, we, "wType", tl, []byte("input"), 100, 100, identity) + di1 := test.AddDecisionTaskScheduledEvent(msBuilder) + decisionStartedEvent1 := test.AddDecisionTaskStartedEvent(msBuilder, di1.ScheduleID, tl, identity) + decisionCompletedEvent1 := test.AddDecisionTaskCompletedEvent(msBuilder, di1.ScheduleID, + decisionStartedEvent1.ID, nil, identity) + activity1ScheduledEvent, _ := test.AddActivityTaskScheduledEvent(msBuilder, decisionCompletedEvent1.ID, + activity1ID, activity1Type, tl, activity1Input, 100, 10, 1, 5) + activity2ScheduledEvent, _ := test.AddActivityTaskScheduledEvent(msBuilder, decisionCompletedEvent1.ID, + activity2ID, activity2Type, tl, activity2Input, 100, 10, 1, 5) + activity1StartedEvent := test.AddActivityTaskStartedEvent(msBuilder, activity1ScheduledEvent.ID, identity) + activity2StartedEvent := test.AddActivityTaskStartedEvent(msBuilder, activity2ScheduledEvent.ID, identity) + test.AddActivityTaskCompletedEvent(msBuilder, activity1ScheduledEvent.ID, + activity1StartedEvent.ID, activity1Result, identity) + di2 := test.AddDecisionTaskScheduledEvent(msBuilder) + decisionStartedEvent2 := test.AddDecisionTaskStartedEvent(msBuilder, di2.ScheduleID, tl, identity) + + taskToken, _ := json.Marshal(&common.TaskToken{ + WorkflowID: "wId", + RunID: we.GetRunID(), + ScheduleID: di2.ScheduleID, + }) + + decisions := []*types.Decision{{ + DecisionType: types.DecisionTypeScheduleActivityTask.Ptr(), + ScheduleActivityTaskDecisionAttributes: &types.ScheduleActivityTaskDecisionAttributes{ + ActivityID: activity3ID, + ActivityType: &types.ActivityType{Name: activity3Type}, + TaskList: &types.TaskList{Name: tl}, + Input: activity3Input, + ScheduleToCloseTimeoutSeconds: common.Int32Ptr(100), + ScheduleToStartTimeoutSeconds: common.Int32Ptr(10), + StartToCloseTimeoutSeconds: common.Int32Ptr(50), + HeartbeatTimeoutSeconds: common.Int32Ptr(5), + }, + }} + + ms := execution.CreatePersistenceMutableState(msBuilder) + gwmsResponse := &persistence.GetWorkflowExecutionResponse{State: ms} + + test.AddActivityTaskCompletedEvent(msBuilder, activity2ScheduledEvent.ID, + activity2StartedEvent.ID, activity2Result, identity) + + ms2 := execution.CreatePersistenceMutableState(msBuilder) + gwmsResponse2 := &persistence.GetWorkflowExecutionResponse{State: ms2} + + s.mockExecutionMgr.On("GetWorkflowExecution", mock.Anything, mock.Anything).Return(gwmsResponse, nil).Once() + s.mockHistoryV2Mgr.On("AppendHistoryNodes", mock.Anything, mock.Anything).Return(&persistence.AppendHistoryNodesResponse{}, nil).Once() + s.mockExecutionMgr.On("UpdateWorkflowExecution", mock.Anything, mock.Anything).Return(&persistence.UpdateWorkflowExecutionResponse{MutableStateUpdateSessionStats: &persistence.MutableStateUpdateSessionStats{}}, + &persistence.ConditionFailedError{}).Once() + + s.mockExecutionMgr.On("GetWorkflowExecution", mock.Anything, mock.Anything).Return(gwmsResponse2, nil).Once() + s.mockHistoryV2Mgr.On("AppendHistoryNodes", mock.Anything, mock.Anything).Return(&persistence.AppendHistoryNodesResponse{}, nil).Once() + s.mockExecutionMgr.On("UpdateWorkflowExecution", mock.Anything, mock.Anything).Return(&persistence.UpdateWorkflowExecutionResponse{MutableStateUpdateSessionStats: &persistence.MutableStateUpdateSessionStats{}}, nil).Once() + + _, err := s.mockHistoryEngine.RespondDecisionTaskCompleted(context.Background(), &types.HistoryRespondDecisionTaskCompletedRequest{ + DomainUUID: constants.TestDomainID, + CompleteRequest: &types.RespondDecisionTaskCompletedRequest{ + TaskToken: taskToken, + Decisions: decisions, + ExecutionContext: executionContext, + Identity: identity, + }, + }) + s.Nil(err, s.printHistory(msBuilder)) + s.Equal(int64(16), ms2.ExecutionInfo.NextEventID) + s.Equal(decisionStartedEvent2.ID, ms2.ExecutionInfo.LastProcessedEvent) + s.Equal(executionContext, ms2.ExecutionInfo.ExecutionContext) + + executionBuilder := s.getBuilder(constants.TestDomainID, we) + activity3Attributes := s.getActivityScheduledEvent(executionBuilder, 13).ActivityTaskScheduledEventAttributes + s.Equal(activity3ID, activity3Attributes.ActivityID) + s.Equal(activity3Type, activity3Attributes.ActivityType.Name) + s.Equal(int64(12), activity3Attributes.DecisionTaskCompletedEventID) + s.Equal(tl, activity3Attributes.TaskList.Name) + s.Equal(activity3Input, activity3Attributes.Input) + s.Equal(int32(100), *activity3Attributes.ScheduleToCloseTimeoutSeconds) + s.Equal(int32(10), *activity3Attributes.ScheduleToStartTimeoutSeconds) + s.Equal(int32(50), *activity3Attributes.StartToCloseTimeoutSeconds) + s.Equal(int32(5), *activity3Attributes.HeartbeatTimeoutSeconds) + + di, ok := executionBuilder.GetDecisionInfo(15) + s.True(ok) + s.Equal(int32(100), di.DecisionTimeout) +} + +func (s *engineSuite) TestValidateSignalRequest() { + workflowType := "testType" + input := []byte("input") + startRequest := &types.StartWorkflowExecutionRequest{ + WorkflowID: "ID", + WorkflowType: &types.WorkflowType{Name: workflowType}, + TaskList: &types.TaskList{Name: "taskptr"}, + Input: input, + ExecutionStartToCloseTimeoutSeconds: common.Int32Ptr(10), + TaskStartToCloseTimeoutSeconds: common.Int32Ptr(10), + Identity: "identity", + } + + err := s.mockHistoryEngine.validateStartWorkflowExecutionRequest(startRequest, 0) + s.Error(err, "startRequest doesn't have request id, it should error out") +} + +func (s *engineSuite) TestRespondDecisionTaskCompletedMaxAttemptsExceeded() { + + we := types.WorkflowExecution{ + WorkflowID: "wId", + RunID: constants.TestRunID, + } + tl := "testTaskList" + taskToken, _ := json.Marshal(&common.TaskToken{ + WorkflowID: we.WorkflowID, + RunID: we.RunID, + ScheduleID: 2, + }) + identity := "testIdentity" + executionContext := []byte("context") + input := []byte("input") + + msBuilder := execution.NewMutableStateBuilderWithEventV2( + s.mockHistoryEngine.shard, + testlogger.New(s.Suite.T()), + we.GetRunID(), + constants.TestLocalDomainEntry, + ) + test.AddWorkflowExecutionStartedEvent(msBuilder, we, "wType", tl, []byte("input"), 100, 200, identity) + di := test.AddDecisionTaskScheduledEvent(msBuilder) + test.AddDecisionTaskStartedEvent(msBuilder, di.ScheduleID, tl, identity) + + decisions := []*types.Decision{{ + DecisionType: types.DecisionTypeScheduleActivityTask.Ptr(), + ScheduleActivityTaskDecisionAttributes: &types.ScheduleActivityTaskDecisionAttributes{ + ActivityID: "activity1", + ActivityType: &types.ActivityType{Name: "activity_type1"}, + TaskList: &types.TaskList{Name: tl}, + Input: input, + ScheduleToCloseTimeoutSeconds: common.Int32Ptr(100), + ScheduleToStartTimeoutSeconds: common.Int32Ptr(10), + StartToCloseTimeoutSeconds: common.Int32Ptr(50), + HeartbeatTimeoutSeconds: common.Int32Ptr(5), + }, + }} + + for i := 0; i < workflow.ConditionalRetryCount; i++ { + ms := execution.CreatePersistenceMutableState(msBuilder) + gwmsResponse := &persistence.GetWorkflowExecutionResponse{State: ms} + + s.mockExecutionMgr.On("GetWorkflowExecution", mock.Anything, mock.Anything).Return(gwmsResponse, nil).Once() + s.mockHistoryV2Mgr.On("AppendHistoryNodes", mock.Anything, mock.Anything).Return(&persistence.AppendHistoryNodesResponse{}, nil).Once() + s.mockExecutionMgr.On("UpdateWorkflowExecution", mock.Anything, mock.Anything).Return(&persistence.UpdateWorkflowExecutionResponse{MutableStateUpdateSessionStats: &persistence.MutableStateUpdateSessionStats{}}, + &persistence.ConditionFailedError{}).Once() + } + + _, err := s.mockHistoryEngine.RespondDecisionTaskCompleted(context.Background(), &types.HistoryRespondDecisionTaskCompletedRequest{ + DomainUUID: constants.TestDomainID, + CompleteRequest: &types.RespondDecisionTaskCompletedRequest{ + TaskToken: taskToken, + Decisions: decisions, + ExecutionContext: executionContext, + Identity: identity, + }, + }) + s.NotNil(err) + s.Equal(workflow.ErrMaxAttemptsExceeded, err) +} + +func (s *engineSuite) TestRespondDecisionTaskCompletedCompleteWorkflowFailed() { + + we := types.WorkflowExecution{ + WorkflowID: "wId", + RunID: constants.TestRunID, + } + tl := "testTaskList" + identity := "testIdentity" + executionContext := []byte("context") + activity1ID := "activity1" + activity1Type := "activity_type1" + activity1Input := []byte("input1") + activity1Result := []byte("activity1_result") + activity2ID := "activity2" + activity2Type := "activity_type2" + activity2Input := []byte("input2") + activity2Result := []byte("activity2_result") + workflowResult := []byte("workflow result") + + msBuilder := execution.NewMutableStateBuilderWithEventV2( + s.mockHistoryEngine.shard, + testlogger.New(s.Suite.T()), + we.GetRunID(), + constants.TestLocalDomainEntry, + ) + test.AddWorkflowExecutionStartedEvent(msBuilder, we, "wType", tl, []byte("input"), 25, 200, identity) + di1 := test.AddDecisionTaskScheduledEvent(msBuilder) + decisionStartedEvent1 := test.AddDecisionTaskStartedEvent(msBuilder, di1.ScheduleID, tl, identity) + decisionCompletedEvent1 := test.AddDecisionTaskCompletedEvent(msBuilder, di1.ScheduleID, + decisionStartedEvent1.ID, nil, identity) + activity1ScheduledEvent, _ := test.AddActivityTaskScheduledEvent(msBuilder, decisionCompletedEvent1.ID, + activity1ID, activity1Type, tl, activity1Input, 100, 10, 1, 5) + activity2ScheduledEvent, _ := test.AddActivityTaskScheduledEvent(msBuilder, decisionCompletedEvent1.ID, + activity2ID, activity2Type, tl, activity2Input, 100, 10, 1, 5) + activity1StartedEvent := test.AddActivityTaskStartedEvent(msBuilder, activity1ScheduledEvent.ID, identity) + activity2StartedEvent := test.AddActivityTaskStartedEvent(msBuilder, activity2ScheduledEvent.ID, identity) + test.AddActivityTaskCompletedEvent(msBuilder, activity1ScheduledEvent.ID, + activity1StartedEvent.ID, activity1Result, identity) + di2 := test.AddDecisionTaskScheduledEvent(msBuilder) + test.AddDecisionTaskStartedEvent(msBuilder, di2.ScheduleID, tl, identity) + test.AddActivityTaskCompletedEvent(msBuilder, activity2ScheduledEvent.ID, + activity2StartedEvent.ID, activity2Result, identity) + + taskToken, _ := json.Marshal(&common.TaskToken{ + WorkflowID: we.WorkflowID, + RunID: we.RunID, + ScheduleID: di2.ScheduleID, + }) + + decisions := []*types.Decision{{ + DecisionType: types.DecisionTypeCompleteWorkflowExecution.Ptr(), + CompleteWorkflowExecutionDecisionAttributes: &types.CompleteWorkflowExecutionDecisionAttributes{ + Result: workflowResult, + }, + }} + + for i := 0; i < 2; i++ { + ms := execution.CreatePersistenceMutableState(msBuilder) + gwmsResponse := &persistence.GetWorkflowExecutionResponse{State: ms} + s.mockExecutionMgr.On("GetWorkflowExecution", mock.Anything, mock.Anything).Return(gwmsResponse, nil).Once() + } + + s.mockHistoryV2Mgr.On("AppendHistoryNodes", mock.Anything, mock.Anything).Return(&persistence.AppendHistoryNodesResponse{}, nil).Once() + s.mockExecutionMgr.On("UpdateWorkflowExecution", mock.Anything, mock.Anything).Return(&persistence.UpdateWorkflowExecutionResponse{MutableStateUpdateSessionStats: &persistence.MutableStateUpdateSessionStats{}}, nil).Once() + + _, err := s.mockHistoryEngine.RespondDecisionTaskCompleted(context.Background(), &types.HistoryRespondDecisionTaskCompletedRequest{ + DomainUUID: constants.TestDomainID, + CompleteRequest: &types.RespondDecisionTaskCompletedRequest{ + TaskToken: taskToken, + Decisions: decisions, + ExecutionContext: executionContext, + Identity: identity, + }, + }) + s.Nil(err, s.printHistory(msBuilder)) + executionBuilder := s.getBuilder(constants.TestDomainID, we) + s.Equal(int64(15), executionBuilder.GetExecutionInfo().NextEventID) + s.Equal(decisionStartedEvent1.ID, executionBuilder.GetExecutionInfo().LastProcessedEvent) + s.Empty(executionBuilder.GetExecutionInfo().ExecutionContext) + s.Equal(persistence.WorkflowStateRunning, executionBuilder.GetExecutionInfo().State) + s.True(executionBuilder.HasPendingDecision()) + di3, ok := executionBuilder.GetDecisionInfo(executionBuilder.GetExecutionInfo().NextEventID - 1) + s.True(ok) + s.Equal(executionBuilder.GetExecutionInfo().NextEventID-1, di3.ScheduleID) + s.Equal(int64(0), di3.Attempt) +} + +func (s *engineSuite) TestRespondDecisionTaskCompletedFailWorkflowFailed() { + + we := types.WorkflowExecution{ + WorkflowID: "wId", + RunID: constants.TestRunID, + } + tl := "testTaskList" + identity := "testIdentity" + executionContext := []byte("context") + activity1ID := "activity1" + activity1Type := "activity_type1" + activity1Input := []byte("input1") + activity1Result := []byte("activity1_result") + activity2ID := "activity2" + activity2Type := "activity_type2" + activity2Input := []byte("input2") + activity2Result := []byte("activity2_result") + reason := "workflow fail reason" + details := []byte("workflow fail details") + + msBuilder := execution.NewMutableStateBuilderWithEventV2( + s.mockHistoryEngine.shard, + testlogger.New(s.Suite.T()), + we.GetRunID(), + constants.TestLocalDomainEntry, + ) + test.AddWorkflowExecutionStartedEvent(msBuilder, we, "wType", tl, []byte("input"), 25, 200, identity) + di1 := test.AddDecisionTaskScheduledEvent(msBuilder) + decisionStartedEvent1 := test.AddDecisionTaskStartedEvent(msBuilder, di1.ScheduleID, tl, identity) + decisionCompletedEvent1 := test.AddDecisionTaskCompletedEvent(msBuilder, di1.ScheduleID, + decisionStartedEvent1.ID, nil, identity) + activity1ScheduledEvent, _ := test.AddActivityTaskScheduledEvent(msBuilder, decisionCompletedEvent1.ID, activity1ID, + activity1Type, tl, activity1Input, 100, 10, 1, 5) + activity2ScheduledEvent, _ := test.AddActivityTaskScheduledEvent(msBuilder, decisionCompletedEvent1.ID, activity2ID, + activity2Type, tl, activity2Input, 100, 10, 1, 5) + activity1StartedEvent := test.AddActivityTaskStartedEvent(msBuilder, activity1ScheduledEvent.ID, identity) + activity2StartedEvent := test.AddActivityTaskStartedEvent(msBuilder, activity2ScheduledEvent.ID, identity) + test.AddActivityTaskCompletedEvent(msBuilder, activity1ScheduledEvent.ID, + activity1StartedEvent.ID, activity1Result, identity) + di2 := test.AddDecisionTaskScheduledEvent(msBuilder) + test.AddDecisionTaskStartedEvent(msBuilder, di2.ScheduleID, tl, identity) + test.AddActivityTaskCompletedEvent(msBuilder, activity2ScheduledEvent.ID, + activity2StartedEvent.ID, activity2Result, identity) + + taskToken, _ := json.Marshal(&common.TaskToken{ + WorkflowID: we.WorkflowID, + RunID: we.RunID, + ScheduleID: di2.ScheduleID, + }) + + decisions := []*types.Decision{{ + DecisionType: types.DecisionTypeFailWorkflowExecution.Ptr(), + FailWorkflowExecutionDecisionAttributes: &types.FailWorkflowExecutionDecisionAttributes{ + Reason: &reason, + Details: details, + }, + }} + + for i := 0; i < 2; i++ { + ms := execution.CreatePersistenceMutableState(msBuilder) + gwmsResponse := &persistence.GetWorkflowExecutionResponse{State: ms} + s.mockExecutionMgr.On("GetWorkflowExecution", mock.Anything, mock.Anything).Return(gwmsResponse, nil).Once() + } + + s.mockHistoryV2Mgr.On("AppendHistoryNodes", mock.Anything, mock.Anything).Return(&persistence.AppendHistoryNodesResponse{}, nil).Once() + s.mockExecutionMgr.On("UpdateWorkflowExecution", mock.Anything, mock.Anything).Return(&persistence.UpdateWorkflowExecutionResponse{MutableStateUpdateSessionStats: &persistence.MutableStateUpdateSessionStats{}}, nil).Once() + + _, err := s.mockHistoryEngine.RespondDecisionTaskCompleted(context.Background(), &types.HistoryRespondDecisionTaskCompletedRequest{ + DomainUUID: constants.TestDomainID, + CompleteRequest: &types.RespondDecisionTaskCompletedRequest{ + TaskToken: taskToken, + Decisions: decisions, + ExecutionContext: executionContext, + Identity: identity, + }, + }) + s.Nil(err, s.printHistory(msBuilder)) + executionBuilder := s.getBuilder(constants.TestDomainID, we) + s.Equal(int64(15), executionBuilder.GetExecutionInfo().NextEventID) + s.Equal(decisionStartedEvent1.ID, executionBuilder.GetExecutionInfo().LastProcessedEvent) + s.Empty(executionBuilder.GetExecutionInfo().ExecutionContext) + s.Equal(persistence.WorkflowStateRunning, executionBuilder.GetExecutionInfo().State) + s.True(executionBuilder.HasPendingDecision()) + di3, ok := executionBuilder.GetDecisionInfo(executionBuilder.GetExecutionInfo().NextEventID - 1) + s.True(ok) + s.Equal(executionBuilder.GetExecutionInfo().NextEventID-1, di3.ScheduleID) + s.Equal(int64(0), di3.Attempt) +} + +func (s *engineSuite) TestRespondDecisionTaskCompletedBadDecisionAttributes() { + + we := types.WorkflowExecution{ + WorkflowID: "wId", + RunID: constants.TestRunID, + } + tl := "testTaskList" + identity := "testIdentity" + executionContext := []byte("context") + activity1ID := "activity1" + activity1Type := "activity_type1" + activity1Input := []byte("input1") + activity1Result := []byte("activity1_result") + + msBuilder := execution.NewMutableStateBuilderWithEventV2( + s.mockHistoryEngine.shard, + testlogger.New(s.Suite.T()), + we.GetRunID(), + constants.TestLocalDomainEntry, + ) + test.AddWorkflowExecutionStartedEvent(msBuilder, we, "wType", tl, []byte("input"), 25, 200, identity) + di1 := test.AddDecisionTaskScheduledEvent(msBuilder) + decisionStartedEvent1 := test.AddDecisionTaskStartedEvent(msBuilder, di1.ScheduleID, tl, identity) + decisionCompletedEvent1 := test.AddDecisionTaskCompletedEvent(msBuilder, di1.ScheduleID, + decisionStartedEvent1.ID, nil, identity) + activity1ScheduledEvent, _ := test.AddActivityTaskScheduledEvent(msBuilder, decisionCompletedEvent1.ID, activity1ID, + activity1Type, tl, activity1Input, 100, 10, 1, 5) + activity1StartedEvent := test.AddActivityTaskStartedEvent(msBuilder, activity1ScheduledEvent.ID, identity) + test.AddActivityTaskCompletedEvent(msBuilder, activity1ScheduledEvent.ID, + activity1StartedEvent.ID, activity1Result, identity) + di2 := test.AddDecisionTaskScheduledEvent(msBuilder) + test.AddDecisionTaskStartedEvent(msBuilder, di2.ScheduleID, tl, identity) + + taskToken, _ := json.Marshal(&common.TaskToken{ + WorkflowID: we.WorkflowID, + RunID: we.RunID, + ScheduleID: di2.ScheduleID, + }) + + // Decision with nil attributes + decisions := []*types.Decision{{ + DecisionType: types.DecisionTypeCompleteWorkflowExecution.Ptr(), + }} + + gwmsResponse1 := &persistence.GetWorkflowExecutionResponse{State: execution.CreatePersistenceMutableState(msBuilder)} + gwmsResponse2 := &persistence.GetWorkflowExecutionResponse{State: execution.CreatePersistenceMutableState(msBuilder)} + s.mockExecutionMgr.On("GetWorkflowExecution", mock.Anything, mock.Anything).Return(gwmsResponse1, nil).Once() + s.mockExecutionMgr.On("GetWorkflowExecution", mock.Anything, mock.Anything).Return(gwmsResponse2, nil).Once() + + s.mockHistoryV2Mgr.On("AppendHistoryNodes", mock.Anything, mock.Anything).Return(&persistence.AppendHistoryNodesResponse{}, nil).Once() + s.mockExecutionMgr.On("UpdateWorkflowExecution", mock.Anything, mock.Anything).Return(&persistence.UpdateWorkflowExecutionResponse{ + MutableStateUpdateSessionStats: &persistence.MutableStateUpdateSessionStats{}}, nil, + ).Once() + + _, err := s.mockHistoryEngine.RespondDecisionTaskCompleted(context.Background(), &types.HistoryRespondDecisionTaskCompletedRequest{ + DomainUUID: constants.TestDomainID, + CompleteRequest: &types.RespondDecisionTaskCompletedRequest{ + TaskToken: taskToken, + Decisions: decisions, + ExecutionContext: executionContext, + Identity: identity, + }, + }) + s.Nil(err) +} + +// This test unit tests the activity schedule timeout validation logic of HistoryEngine's RespondDecisionTaskComplete function. +// An scheduled activity decision has 3 timeouts: ScheduleToClose, ScheduleToStart and StartToClose. +// This test verifies that when either ScheduleToClose or ScheduleToStart and StartToClose are specified, +// HistoryEngine's validateActivityScheduleAttribute will deduce the missing timeout and fill it in +// instead of returning a BadRequest error and only when all three are missing should a BadRequest be returned. +func (s *engineSuite) TestRespondDecisionTaskCompletedSingleActivityScheduledAttribute() { + workflowTimeout := int32(100) + testIterationVariables := []struct { + scheduleToClose *int32 + scheduleToStart *int32 + startToClose *int32 + heartbeat *int32 + expectedScheduleToClose int32 + expectedScheduleToStart int32 + expectedStartToClose int32 + expectDecisionFail bool + }{ + // No ScheduleToClose timeout, will use ScheduleToStart + StartToClose + {nil, common.Int32Ptr(3), common.Int32Ptr(7), nil, + 3 + 7, 3, 7, false}, + // Has ScheduleToClose timeout but not ScheduleToStart or StartToClose, + // will use ScheduleToClose for ScheduleToStart and StartToClose + {common.Int32Ptr(7), nil, nil, nil, + 7, 7, 7, false}, + // No ScheduleToClose timeout, ScheduleToStart or StartToClose, expect error return + {nil, nil, nil, nil, + 0, 0, 0, true}, + // Negative ScheduleToClose, expect error return + {common.Int32Ptr(-1), nil, nil, nil, + 0, 0, 0, true}, + // Negative ScheduleToStart, expect error return + {nil, common.Int32Ptr(-1), nil, nil, + 0, 0, 0, true}, + // Negative StartToClose, expect error return + {nil, nil, common.Int32Ptr(-1), nil, + 0, 0, 0, true}, + // Negative HeartBeat, expect error return + {nil, nil, nil, common.Int32Ptr(-1), + 0, 0, 0, true}, + // Use workflow timeout + {common.Int32Ptr(workflowTimeout), nil, nil, nil, + workflowTimeout, workflowTimeout, workflowTimeout, false}, + // Timeout larger than workflow timeout + {common.Int32Ptr(workflowTimeout + 1), nil, nil, nil, + workflowTimeout, workflowTimeout, workflowTimeout, false}, + {nil, common.Int32Ptr(workflowTimeout + 1), nil, nil, + 0, 0, 0, true}, + {nil, nil, common.Int32Ptr(workflowTimeout + 1), nil, + 0, 0, 0, true}, + {nil, nil, nil, common.Int32Ptr(workflowTimeout + 1), + 0, 0, 0, true}, + // No ScheduleToClose timeout, will use ScheduleToStart + StartToClose, but exceed limit + {nil, common.Int32Ptr(workflowTimeout), common.Int32Ptr(10), nil, + workflowTimeout, workflowTimeout, 10, false}, + } + + for _, iVar := range testIterationVariables { + + we := types.WorkflowExecution{ + WorkflowID: "wId", + RunID: constants.TestRunID, + } + tl := "testTaskList" + taskToken, _ := json.Marshal(&common.TaskToken{ + WorkflowID: "wId", + RunID: we.GetRunID(), + ScheduleID: 2, + }) + identity := "testIdentity" + executionContext := []byte("context") + input := []byte("input") + + msBuilder := execution.NewMutableStateBuilderWithEventV2( + s.mockHistoryEngine.shard, + testlogger.New(s.Suite.T()), + we.GetRunID(), + constants.TestLocalDomainEntry, + ) + test.AddWorkflowExecutionStartedEvent(msBuilder, we, "wType", tl, []byte("input"), workflowTimeout, 200, identity) + di := test.AddDecisionTaskScheduledEvent(msBuilder) + test.AddDecisionTaskStartedEvent(msBuilder, di.ScheduleID, tl, identity) + + decisions := []*types.Decision{{ + DecisionType: types.DecisionTypeScheduleActivityTask.Ptr(), + ScheduleActivityTaskDecisionAttributes: &types.ScheduleActivityTaskDecisionAttributes{ + ActivityID: "activity1", + ActivityType: &types.ActivityType{Name: "activity_type1"}, + TaskList: &types.TaskList{Name: tl}, + Input: input, + ScheduleToCloseTimeoutSeconds: iVar.scheduleToClose, + ScheduleToStartTimeoutSeconds: iVar.scheduleToStart, + StartToCloseTimeoutSeconds: iVar.startToClose, + HeartbeatTimeoutSeconds: iVar.heartbeat, + }, + }} + + gwmsResponse1 := &persistence.GetWorkflowExecutionResponse{State: execution.CreatePersistenceMutableState(msBuilder)} + s.mockExecutionMgr.On("GetWorkflowExecution", mock.Anything, mock.Anything).Return(gwmsResponse1, nil).Once() + if iVar.expectDecisionFail { + gwmsResponse2 := &persistence.GetWorkflowExecutionResponse{State: execution.CreatePersistenceMutableState(msBuilder)} + s.mockExecutionMgr.On("GetWorkflowExecution", mock.Anything, mock.Anything).Return(gwmsResponse2, nil).Once() + } + + s.mockHistoryV2Mgr.On("AppendHistoryNodes", mock.Anything, mock.Anything).Return(&persistence.AppendHistoryNodesResponse{}, nil).Once() + s.mockExecutionMgr.On("UpdateWorkflowExecution", mock.Anything, mock.Anything).Return(&persistence.UpdateWorkflowExecutionResponse{MutableStateUpdateSessionStats: &persistence.MutableStateUpdateSessionStats{}}, nil).Once() + + _, err := s.mockHistoryEngine.RespondDecisionTaskCompleted(context.Background(), &types.HistoryRespondDecisionTaskCompletedRequest{ + DomainUUID: constants.TestDomainID, + CompleteRequest: &types.RespondDecisionTaskCompletedRequest{ + TaskToken: taskToken, + Decisions: decisions, + ExecutionContext: executionContext, + Identity: identity, + }, + }) + + s.Nil(err, s.printHistory(msBuilder)) + executionBuilder := s.getBuilder(constants.TestDomainID, we) + if !iVar.expectDecisionFail { + s.Equal(int64(6), executionBuilder.GetExecutionInfo().NextEventID) + s.Equal(int64(3), executionBuilder.GetExecutionInfo().LastProcessedEvent) + s.Equal(persistence.WorkflowStateRunning, executionBuilder.GetExecutionInfo().State) + s.False(executionBuilder.HasPendingDecision()) + + activity1Attributes := s.getActivityScheduledEvent(executionBuilder, int64(5)).ActivityTaskScheduledEventAttributes + s.Equal(iVar.expectedScheduleToClose, activity1Attributes.GetScheduleToCloseTimeoutSeconds()) + s.Equal(iVar.expectedScheduleToStart, activity1Attributes.GetScheduleToStartTimeoutSeconds()) + s.Equal(iVar.expectedStartToClose, activity1Attributes.GetStartToCloseTimeoutSeconds()) + } else { + s.Equal(int64(5), executionBuilder.GetExecutionInfo().NextEventID) + s.Equal(common.EmptyEventID, executionBuilder.GetExecutionInfo().LastProcessedEvent) + s.Equal(persistence.WorkflowStateRunning, executionBuilder.GetExecutionInfo().State) + s.True(executionBuilder.HasPendingDecision()) + } + s.TearDownTest() + s.SetupTest() + } +} + +func (s *engineSuite) TestRespondDecisionTaskCompletedBadBinary() { + domainID := uuid.New() + we := types.WorkflowExecution{ + WorkflowID: "wId", + RunID: constants.TestRunID, + } + tl := "testTaskList" + taskToken, _ := json.Marshal(&common.TaskToken{ + WorkflowID: "wId", + RunID: we.GetRunID(), + ScheduleID: 2, + }) + identity := "testIdentity" + executionContext := []byte("context") + domainEntry := cache.NewLocalDomainCacheEntryForTest( + &persistence.DomainInfo{ID: domainID, Name: constants.TestDomainName}, + &persistence.DomainConfig{ + Retention: 2, + BadBinaries: types.BadBinaries{ + Binaries: map[string]*types.BadBinaryInfo{ + "test-bad-binary": {}, + }, + }, + }, + cluster.TestCurrentClusterName, + ) + + msBuilder := execution.NewMutableStateBuilderWithEventV2( + s.mockHistoryEngine.shard, + testlogger.New(s.Suite.T()), + we.GetRunID(), + domainEntry, + ) + test.AddWorkflowExecutionStartedEvent(msBuilder, we, "wType", tl, []byte("input"), 100, 200, identity) + di := test.AddDecisionTaskScheduledEvent(msBuilder) + test.AddDecisionTaskStartedEvent(msBuilder, di.ScheduleID, tl, identity) + + var decisions []*types.Decision + + gwmsResponse1 := &persistence.GetWorkflowExecutionResponse{State: execution.CreatePersistenceMutableState(msBuilder)} + gwmsResponse2 := &persistence.GetWorkflowExecutionResponse{State: execution.CreatePersistenceMutableState(msBuilder)} + + s.mockExecutionMgr.On("GetWorkflowExecution", mock.Anything, mock.Anything).Return(gwmsResponse1, nil).Once() + s.mockExecutionMgr.On("GetWorkflowExecution", mock.Anything, mock.Anything).Return(gwmsResponse2, nil).Once() + s.mockHistoryV2Mgr.On("AppendHistoryNodes", mock.Anything, mock.Anything).Return(&persistence.AppendHistoryNodesResponse{}, nil).Once() + s.mockExecutionMgr.On("UpdateWorkflowExecution", mock.Anything, mock.Anything).Return(&persistence.UpdateWorkflowExecutionResponse{MutableStateUpdateSessionStats: &persistence.MutableStateUpdateSessionStats{}}, nil).Once() + s.mockDomainCache.EXPECT().GetDomainByID(domainID).Return(domainEntry, nil).AnyTimes() + s.mockDomainCache.EXPECT().GetDomainName(domainID).Return(constants.TestDomainName, nil).AnyTimes() + + _, err := s.mockHistoryEngine.RespondDecisionTaskCompleted(context.Background(), &types.HistoryRespondDecisionTaskCompletedRequest{ + DomainUUID: domainID, + CompleteRequest: &types.RespondDecisionTaskCompletedRequest{ + TaskToken: taskToken, + Decisions: decisions, + ExecutionContext: executionContext, + Identity: identity, + BinaryChecksum: "test-bad-binary", + }, + }) + s.Nil(err, s.printHistory(msBuilder)) + executionBuilder := s.getBuilder(domainID, we) + s.Equal(int64(5), executionBuilder.GetExecutionInfo().NextEventID) + s.Equal(common.EmptyEventID, executionBuilder.GetExecutionInfo().LastProcessedEvent) + s.Empty(executionBuilder.GetExecutionInfo().ExecutionContext) + s.Equal(persistence.WorkflowStateRunning, executionBuilder.GetExecutionInfo().State) + s.True(executionBuilder.HasPendingDecision()) +} + +func (s *engineSuite) TestRespondDecisionTaskCompletedSingleActivityScheduledDecision() { + + we := types.WorkflowExecution{ + WorkflowID: "wId", + RunID: constants.TestRunID, + } + tl := "testTaskList" + taskToken, _ := json.Marshal(&common.TaskToken{ + WorkflowID: "wId", + RunID: we.GetRunID(), + ScheduleID: 2, + }) + identity := "testIdentity" + executionContext := []byte("context") + input := []byte("input") + + msBuilder := execution.NewMutableStateBuilderWithEventV2( + s.mockHistoryEngine.shard, + testlogger.New(s.Suite.T()), + we.GetRunID(), + constants.TestLocalDomainEntry, + ) + test.AddWorkflowExecutionStartedEvent(msBuilder, we, "wType", tl, []byte("input"), 100, 200, identity) + di := test.AddDecisionTaskScheduledEvent(msBuilder) + test.AddDecisionTaskStartedEvent(msBuilder, di.ScheduleID, tl, identity) + + decisions := []*types.Decision{{ + DecisionType: types.DecisionTypeScheduleActivityTask.Ptr(), + ScheduleActivityTaskDecisionAttributes: &types.ScheduleActivityTaskDecisionAttributes{ + ActivityID: "activity1", + ActivityType: &types.ActivityType{Name: "activity_type1"}, + TaskList: &types.TaskList{Name: tl}, + Input: input, + ScheduleToCloseTimeoutSeconds: common.Int32Ptr(100), + ScheduleToStartTimeoutSeconds: common.Int32Ptr(10), + StartToCloseTimeoutSeconds: common.Int32Ptr(50), + HeartbeatTimeoutSeconds: common.Int32Ptr(5), + }, + }} + + ms := execution.CreatePersistenceMutableState(msBuilder) + gwmsResponse := &persistence.GetWorkflowExecutionResponse{State: ms} + + s.mockExecutionMgr.On("GetWorkflowExecution", mock.Anything, mock.Anything).Return(gwmsResponse, nil).Once() + s.mockHistoryV2Mgr.On("AppendHistoryNodes", mock.Anything, mock.Anything).Return(&persistence.AppendHistoryNodesResponse{}, nil).Once() + s.mockExecutionMgr.On("UpdateWorkflowExecution", mock.Anything, mock.Anything).Return(&persistence.UpdateWorkflowExecutionResponse{MutableStateUpdateSessionStats: &persistence.MutableStateUpdateSessionStats{}}, nil).Once() + + _, err := s.mockHistoryEngine.RespondDecisionTaskCompleted(context.Background(), &types.HistoryRespondDecisionTaskCompletedRequest{ + DomainUUID: constants.TestDomainID, + CompleteRequest: &types.RespondDecisionTaskCompletedRequest{ + TaskToken: taskToken, + Decisions: decisions, + ExecutionContext: executionContext, + Identity: identity, + }, + }) + s.Nil(err, s.printHistory(msBuilder)) + executionBuilder := s.getBuilder(constants.TestDomainID, we) + s.Equal(int64(6), executionBuilder.GetExecutionInfo().NextEventID) + s.Equal(int64(3), executionBuilder.GetExecutionInfo().LastProcessedEvent) + s.Equal(executionContext, executionBuilder.GetExecutionInfo().ExecutionContext) + s.Equal(persistence.WorkflowStateRunning, executionBuilder.GetExecutionInfo().State) + s.False(executionBuilder.HasPendingDecision()) + + activity1Attributes := s.getActivityScheduledEvent(executionBuilder, int64(5)).ActivityTaskScheduledEventAttributes + s.Equal("activity1", activity1Attributes.ActivityID) + s.Equal("activity_type1", activity1Attributes.ActivityType.Name) + s.Equal(int64(4), activity1Attributes.DecisionTaskCompletedEventID) + s.Equal(tl, activity1Attributes.TaskList.Name) + s.Equal(input, activity1Attributes.Input) + s.Equal(int32(100), *activity1Attributes.ScheduleToCloseTimeoutSeconds) + s.Equal(int32(10), *activity1Attributes.ScheduleToStartTimeoutSeconds) + s.Equal(int32(50), *activity1Attributes.StartToCloseTimeoutSeconds) + s.Equal(int32(5), *activity1Attributes.HeartbeatTimeoutSeconds) +} + +func (s *engineSuite) TestRespondDecisionTaskCompleted_DecisionHeartbeatTimeout() { + + we := types.WorkflowExecution{ + WorkflowID: "wId", + RunID: constants.TestRunID, + } + tl := "testTaskList" + taskToken, _ := json.Marshal(&common.TaskToken{ + WorkflowID: we.WorkflowID, + RunID: we.RunID, + ScheduleID: 2, + }) + identity := "testIdentity" + executionContext := []byte("context") + + msBuilder := execution.NewMutableStateBuilderWithEventV2( + s.mockHistoryEngine.shard, + testlogger.New(s.Suite.T()), + we.GetRunID(), + constants.TestLocalDomainEntry, + ) + test.AddWorkflowExecutionStartedEvent(msBuilder, we, "wType", tl, []byte("input"), 100, 200, identity) + di := test.AddDecisionTaskScheduledEvent(msBuilder) + test.AddDecisionTaskStartedEvent(msBuilder, di.ScheduleID, tl, identity) + msBuilder.GetExecutionInfo().DecisionOriginalScheduledTimestamp = time.Now().Add(-time.Hour).UnixNano() + + decisions := []*types.Decision{} + + ms := execution.CreatePersistenceMutableState(msBuilder) + gwmsResponse := &persistence.GetWorkflowExecutionResponse{State: ms} + + s.mockExecutionMgr.On("GetWorkflowExecution", mock.Anything, mock.Anything).Return(gwmsResponse, nil).Once() + s.mockHistoryV2Mgr.On("AppendHistoryNodes", mock.Anything, mock.Anything).Return(&persistence.AppendHistoryNodesResponse{}, nil).Once() + s.mockExecutionMgr.On("UpdateWorkflowExecution", mock.Anything, mock.Anything).Return(&persistence.UpdateWorkflowExecutionResponse{MutableStateUpdateSessionStats: &persistence.MutableStateUpdateSessionStats{}}, nil).Once() + + _, err := s.mockHistoryEngine.RespondDecisionTaskCompleted(context.Background(), &types.HistoryRespondDecisionTaskCompletedRequest{ + DomainUUID: constants.TestDomainID, + CompleteRequest: &types.RespondDecisionTaskCompletedRequest{ + ForceCreateNewDecisionTask: true, + TaskToken: taskToken, + Decisions: decisions, + ExecutionContext: executionContext, + Identity: identity, + }, + }) + s.Error(err, "decision heartbeat timeout") +} + +func (s *engineSuite) TestRespondDecisionTaskCompleted_DecisionHeartbeatNotTimeout() { + + we := types.WorkflowExecution{ + WorkflowID: "wId", + RunID: constants.TestRunID, + } + tl := "testTaskList" + taskToken, _ := json.Marshal(&common.TaskToken{ + WorkflowID: we.WorkflowID, + RunID: we.RunID, + ScheduleID: 2, + }) + identity := "testIdentity" + executionContext := []byte("context") + + msBuilder := execution.NewMutableStateBuilderWithEventV2( + s.mockHistoryEngine.shard, + testlogger.New(s.Suite.T()), + we.GetRunID(), + constants.TestLocalDomainEntry, + ) + test.AddWorkflowExecutionStartedEvent(msBuilder, we, "wType", tl, []byte("input"), 100, 200, identity) + di := test.AddDecisionTaskScheduledEvent(msBuilder) + test.AddDecisionTaskStartedEvent(msBuilder, di.ScheduleID, tl, identity) + msBuilder.GetExecutionInfo().DecisionOriginalScheduledTimestamp = time.Now().Add(-time.Minute).UnixNano() + + decisions := []*types.Decision{} + + ms := execution.CreatePersistenceMutableState(msBuilder) + gwmsResponse := &persistence.GetWorkflowExecutionResponse{State: ms} + + s.mockExecutionMgr.On("GetWorkflowExecution", mock.Anything, mock.Anything).Return(gwmsResponse, nil).Once() + s.mockHistoryV2Mgr.On("AppendHistoryNodes", mock.Anything, mock.Anything).Return(&persistence.AppendHistoryNodesResponse{}, nil).Once() + s.mockExecutionMgr.On("UpdateWorkflowExecution", mock.Anything, mock.Anything).Return(&persistence.UpdateWorkflowExecutionResponse{MutableStateUpdateSessionStats: &persistence.MutableStateUpdateSessionStats{}}, nil).Once() + + _, err := s.mockHistoryEngine.RespondDecisionTaskCompleted(context.Background(), &types.HistoryRespondDecisionTaskCompletedRequest{ + DomainUUID: constants.TestDomainID, + CompleteRequest: &types.RespondDecisionTaskCompletedRequest{ + ForceCreateNewDecisionTask: true, + TaskToken: taskToken, + Decisions: decisions, + ExecutionContext: executionContext, + Identity: identity, + }, + }) + s.Nil(err) +} + +func (s *engineSuite) TestRespondDecisionTaskCompleted_DecisionHeartbeatNotTimeout_ZeroOrignalScheduledTime() { + + we := types.WorkflowExecution{ + WorkflowID: "wId", + RunID: constants.TestRunID, + } + tl := "testTaskList" + taskToken, _ := json.Marshal(&common.TaskToken{ + WorkflowID: we.WorkflowID, + RunID: we.RunID, + ScheduleID: 2, + }) + identity := "testIdentity" + executionContext := []byte("context") + + msBuilder := execution.NewMutableStateBuilderWithEventV2( + s.mockHistoryEngine.shard, + testlogger.New(s.Suite.T()), + we.GetRunID(), + constants.TestLocalDomainEntry, + ) + test.AddWorkflowExecutionStartedEvent(msBuilder, we, "wType", tl, []byte("input"), 100, 200, identity) + di := test.AddDecisionTaskScheduledEvent(msBuilder) + test.AddDecisionTaskStartedEvent(msBuilder, di.ScheduleID, tl, identity) + msBuilder.GetExecutionInfo().DecisionOriginalScheduledTimestamp = 0 + + decisions := []*types.Decision{} + + ms := execution.CreatePersistenceMutableState(msBuilder) + gwmsResponse := &persistence.GetWorkflowExecutionResponse{State: ms} + + s.mockExecutionMgr.On("GetWorkflowExecution", mock.Anything, mock.Anything).Return(gwmsResponse, nil).Once() + s.mockHistoryV2Mgr.On("AppendHistoryNodes", mock.Anything, mock.Anything).Return(&persistence.AppendHistoryNodesResponse{}, nil).Once() + s.mockExecutionMgr.On("UpdateWorkflowExecution", mock.Anything, mock.Anything).Return(&persistence.UpdateWorkflowExecutionResponse{MutableStateUpdateSessionStats: &persistence.MutableStateUpdateSessionStats{}}, nil).Once() + + _, err := s.mockHistoryEngine.RespondDecisionTaskCompleted(context.Background(), &types.HistoryRespondDecisionTaskCompletedRequest{ + DomainUUID: constants.TestDomainID, + CompleteRequest: &types.RespondDecisionTaskCompletedRequest{ + ForceCreateNewDecisionTask: true, + TaskToken: taskToken, + Decisions: decisions, + ExecutionContext: executionContext, + Identity: identity, + }, + }) + s.Nil(err) +} + +func (s *engineSuite) TestRespondDecisionTaskCompletedCompleteWorkflowSuccess() { + + we := types.WorkflowExecution{ + WorkflowID: "wId", + RunID: constants.TestRunID, + } + tl := "testTaskList" + taskToken, _ := json.Marshal(&common.TaskToken{ + WorkflowID: we.WorkflowID, + RunID: we.RunID, + ScheduleID: 2, + }) + identity := "testIdentity" + executionContext := []byte("context") + workflowResult := []byte("success") + + msBuilder := execution.NewMutableStateBuilderWithEventV2( + s.mockHistoryEngine.shard, + testlogger.New(s.Suite.T()), + we.GetRunID(), + constants.TestLocalDomainEntry, + ) + test.AddWorkflowExecutionStartedEvent(msBuilder, we, "wType", tl, []byte("input"), 100, 200, identity) + di := test.AddDecisionTaskScheduledEvent(msBuilder) + test.AddDecisionTaskStartedEvent(msBuilder, di.ScheduleID, tl, identity) + + decisions := []*types.Decision{{ + DecisionType: types.DecisionTypeCompleteWorkflowExecution.Ptr(), + CompleteWorkflowExecutionDecisionAttributes: &types.CompleteWorkflowExecutionDecisionAttributes{ + Result: workflowResult, + }, + }} + + ms := execution.CreatePersistenceMutableState(msBuilder) + gwmsResponse := &persistence.GetWorkflowExecutionResponse{State: ms} + + s.mockExecutionMgr.On("GetWorkflowExecution", mock.Anything, mock.Anything).Return(gwmsResponse, nil).Once() + s.mockHistoryV2Mgr.On("AppendHistoryNodes", mock.Anything, mock.Anything).Return(&persistence.AppendHistoryNodesResponse{}, nil).Once() + s.mockExecutionMgr.On("UpdateWorkflowExecution", mock.Anything, mock.Anything).Return(&persistence.UpdateWorkflowExecutionResponse{MutableStateUpdateSessionStats: &persistence.MutableStateUpdateSessionStats{}}, nil).Once() + + _, err := s.mockHistoryEngine.RespondDecisionTaskCompleted(context.Background(), &types.HistoryRespondDecisionTaskCompletedRequest{ + DomainUUID: constants.TestDomainID, + CompleteRequest: &types.RespondDecisionTaskCompletedRequest{ + TaskToken: taskToken, + Decisions: decisions, + ExecutionContext: executionContext, + Identity: identity, + }, + }) + s.Nil(err, s.printHistory(msBuilder)) + executionBuilder := s.getBuilder(constants.TestDomainID, we) + s.Equal(int64(6), executionBuilder.GetExecutionInfo().NextEventID) + s.Equal(int64(3), executionBuilder.GetExecutionInfo().LastProcessedEvent) + s.Equal(executionContext, executionBuilder.GetExecutionInfo().ExecutionContext) + s.Equal(persistence.WorkflowStateCompleted, executionBuilder.GetExecutionInfo().State) + s.False(executionBuilder.HasPendingDecision()) +} + +func (s *engineSuite) TestRespondDecisionTaskCompletedFailWorkflowSuccess() { + + we := types.WorkflowExecution{ + WorkflowID: "wId", + RunID: constants.TestRunID, + } + tl := "testTaskList" + taskToken, _ := json.Marshal(&common.TaskToken{ + WorkflowID: we.WorkflowID, + RunID: we.RunID, + ScheduleID: 2, + }) + identity := "testIdentity" + executionContext := []byte("context") + details := []byte("fail workflow details") + reason := "fail workflow reason" + + msBuilder := execution.NewMutableStateBuilderWithEventV2( + s.mockHistoryEngine.shard, + testlogger.New(s.Suite.T()), + we.GetRunID(), + constants.TestLocalDomainEntry, + ) + test.AddWorkflowExecutionStartedEvent(msBuilder, we, "wType", tl, []byte("input"), 100, 200, identity) + di := test.AddDecisionTaskScheduledEvent(msBuilder) + test.AddDecisionTaskStartedEvent(msBuilder, di.ScheduleID, tl, identity) + + decisions := []*types.Decision{{ + DecisionType: types.DecisionTypeFailWorkflowExecution.Ptr(), + FailWorkflowExecutionDecisionAttributes: &types.FailWorkflowExecutionDecisionAttributes{ + Reason: &reason, + Details: details, + }, + }} + + ms := execution.CreatePersistenceMutableState(msBuilder) + gwmsResponse := &persistence.GetWorkflowExecutionResponse{State: ms} + + s.mockExecutionMgr.On("GetWorkflowExecution", mock.Anything, mock.Anything).Return(gwmsResponse, nil).Once() + s.mockHistoryV2Mgr.On("AppendHistoryNodes", mock.Anything, mock.Anything).Return(&persistence.AppendHistoryNodesResponse{}, nil).Once() + s.mockExecutionMgr.On("UpdateWorkflowExecution", mock.Anything, mock.Anything).Return(&persistence.UpdateWorkflowExecutionResponse{MutableStateUpdateSessionStats: &persistence.MutableStateUpdateSessionStats{}}, nil).Once() + + _, err := s.mockHistoryEngine.RespondDecisionTaskCompleted(context.Background(), &types.HistoryRespondDecisionTaskCompletedRequest{ + DomainUUID: constants.TestDomainID, + CompleteRequest: &types.RespondDecisionTaskCompletedRequest{ + TaskToken: taskToken, + Decisions: decisions, + ExecutionContext: executionContext, + Identity: identity, + }, + }) + s.Nil(err, s.printHistory(msBuilder)) + executionBuilder := s.getBuilder(constants.TestDomainID, we) + s.Equal(int64(6), executionBuilder.GetExecutionInfo().NextEventID) + s.Equal(int64(3), executionBuilder.GetExecutionInfo().LastProcessedEvent) + s.Equal(executionContext, executionBuilder.GetExecutionInfo().ExecutionContext) + s.Equal(persistence.WorkflowStateCompleted, executionBuilder.GetExecutionInfo().State) + s.False(executionBuilder.HasPendingDecision()) +} + +func (s *engineSuite) TestRespondDecisionTaskCompletedSignalExternalWorkflowSuccess() { + + we := types.WorkflowExecution{ + WorkflowID: "wId", + RunID: constants.TestRunID, + } + tl := "testTaskList" + taskToken, _ := json.Marshal(&common.TaskToken{ + WorkflowID: we.WorkflowID, + RunID: we.RunID, + ScheduleID: 2, + }) + identity := "testIdentity" + executionContext := []byte("context") + + msBuilder := execution.NewMutableStateBuilderWithEventV2( + s.mockHistoryEngine.shard, + testlogger.New(s.Suite.T()), + we.GetRunID(), + constants.TestLocalDomainEntry, + ) + test.AddWorkflowExecutionStartedEvent(msBuilder, we, "wType", tl, []byte("input"), 100, 200, identity) + di := test.AddDecisionTaskScheduledEvent(msBuilder) + test.AddDecisionTaskStartedEvent(msBuilder, di.ScheduleID, tl, identity) + + decisions := []*types.Decision{{ + DecisionType: types.DecisionTypeSignalExternalWorkflowExecution.Ptr(), + SignalExternalWorkflowExecutionDecisionAttributes: &types.SignalExternalWorkflowExecutionDecisionAttributes{ + Domain: constants.TestDomainName, + Execution: &types.WorkflowExecution{ + WorkflowID: we.WorkflowID, + RunID: we.RunID, + }, + SignalName: "signal", + Input: []byte("test input"), + }, + }} + + ms := execution.CreatePersistenceMutableState(msBuilder) + gwmsResponse := &persistence.GetWorkflowExecutionResponse{State: ms} + + s.mockExecutionMgr.On("GetWorkflowExecution", mock.Anything, mock.Anything).Return(gwmsResponse, nil).Once() + s.mockHistoryV2Mgr.On("AppendHistoryNodes", mock.Anything, mock.Anything).Return(&persistence.AppendHistoryNodesResponse{}, nil).Once() + s.mockExecutionMgr.On("UpdateWorkflowExecution", mock.Anything, mock.Anything).Return(&persistence.UpdateWorkflowExecutionResponse{MutableStateUpdateSessionStats: &persistence.MutableStateUpdateSessionStats{}}, nil).Once() + + _, err := s.mockHistoryEngine.RespondDecisionTaskCompleted(context.Background(), &types.HistoryRespondDecisionTaskCompletedRequest{ + DomainUUID: constants.TestDomainID, + CompleteRequest: &types.RespondDecisionTaskCompletedRequest{ + TaskToken: taskToken, + Decisions: decisions, + ExecutionContext: executionContext, + Identity: identity, + }, + }) + s.Nil(err, s.printHistory(msBuilder)) + executionBuilder := s.getBuilder(constants.TestDomainID, we) + s.Equal(int64(6), executionBuilder.GetExecutionInfo().NextEventID) + s.Equal(int64(3), executionBuilder.GetExecutionInfo().LastProcessedEvent) + s.Equal(executionContext, executionBuilder.GetExecutionInfo().ExecutionContext) +} + +func (s *engineSuite) TestRespondDecisionTaskCompletedStartChildWorkflowWithAbandonPolicy() { + + we := types.WorkflowExecution{ + WorkflowID: "wId", + RunID: constants.TestRunID, + } + tl := "testTaskList" + taskToken, _ := json.Marshal(&common.TaskToken{ + WorkflowID: we.WorkflowID, + RunID: we.RunID, + ScheduleID: 2, + }) + identity := "testIdentity" + executionContext := []byte("context") + + msBuilder := execution.NewMutableStateBuilderWithEventV2( + s.mockHistoryEngine.shard, + testlogger.New(s.Suite.T()), + we.GetRunID(), + constants.TestLocalDomainEntry, + ) + test.AddWorkflowExecutionStartedEvent(msBuilder, we, "wType", tl, []byte("input"), 100, 200, identity) + di := test.AddDecisionTaskScheduledEvent(msBuilder) + test.AddDecisionTaskStartedEvent(msBuilder, di.ScheduleID, tl, identity) + + abandon := types.ParentClosePolicyAbandon + decisions := []*types.Decision{{ + DecisionType: types.DecisionTypeStartChildWorkflowExecution.Ptr(), + StartChildWorkflowExecutionDecisionAttributes: &types.StartChildWorkflowExecutionDecisionAttributes{ + Domain: constants.TestDomainName, + WorkflowID: "child-workflow-id", + WorkflowType: &types.WorkflowType{ + Name: "child-workflow-type", + }, + ParentClosePolicy: &abandon, + }, + }} + + ms := execution.CreatePersistenceMutableState(msBuilder) + gwmsResponse := &persistence.GetWorkflowExecutionResponse{State: ms} + + s.mockExecutionMgr.On("GetWorkflowExecution", mock.Anything, mock.Anything).Return(gwmsResponse, nil).Once() + s.mockHistoryV2Mgr.On("AppendHistoryNodes", mock.Anything, mock.Anything).Return(&persistence.AppendHistoryNodesResponse{}, nil).Once() + s.mockExecutionMgr.On("UpdateWorkflowExecution", mock.Anything, mock.Anything).Return(&persistence.UpdateWorkflowExecutionResponse{MutableStateUpdateSessionStats: &persistence.MutableStateUpdateSessionStats{}}, nil).Once() + + _, err := s.mockHistoryEngine.RespondDecisionTaskCompleted(context.Background(), &types.HistoryRespondDecisionTaskCompletedRequest{ + DomainUUID: constants.TestDomainID, + CompleteRequest: &types.RespondDecisionTaskCompletedRequest{ + TaskToken: taskToken, + Decisions: decisions, + ExecutionContext: executionContext, + Identity: identity, + }, + }) + s.Nil(err, s.printHistory(msBuilder)) + executionBuilder := s.getBuilder(constants.TestDomainID, we) + s.Equal(int64(6), executionBuilder.GetExecutionInfo().NextEventID) + s.Equal(int64(3), executionBuilder.GetExecutionInfo().LastProcessedEvent) + s.Equal(executionContext, executionBuilder.GetExecutionInfo().ExecutionContext) + s.Equal(int(1), len(executionBuilder.GetPendingChildExecutionInfos())) + var childID int64 + for c := range executionBuilder.GetPendingChildExecutionInfos() { + childID = c + break + } + s.Equal("child-workflow-id", executionBuilder.GetPendingChildExecutionInfos()[childID].StartedWorkflowID) + s.Equal(types.ParentClosePolicyAbandon, executionBuilder.GetPendingChildExecutionInfos()[childID].ParentClosePolicy) +} + +func (s *engineSuite) TestRespondDecisionTaskCompletedStartChildWorkflowWithTerminatePolicy() { + + we := types.WorkflowExecution{ + WorkflowID: "wId", + RunID: constants.TestRunID, + } + tl := "testTaskList" + taskToken, _ := json.Marshal(&common.TaskToken{ + WorkflowID: we.WorkflowID, + RunID: we.RunID, + ScheduleID: 2, + }) + identity := "testIdentity" + executionContext := []byte("context") + + msBuilder := execution.NewMutableStateBuilderWithEventV2( + s.mockHistoryEngine.shard, + testlogger.New(s.Suite.T()), + we.GetRunID(), + constants.TestLocalDomainEntry, + ) + test.AddWorkflowExecutionStartedEvent(msBuilder, we, "wType", tl, []byte("input"), 100, 200, identity) + di := test.AddDecisionTaskScheduledEvent(msBuilder) + test.AddDecisionTaskStartedEvent(msBuilder, di.ScheduleID, tl, identity) + + terminate := types.ParentClosePolicyTerminate + decisions := []*types.Decision{{ + DecisionType: types.DecisionTypeStartChildWorkflowExecution.Ptr(), + StartChildWorkflowExecutionDecisionAttributes: &types.StartChildWorkflowExecutionDecisionAttributes{ + Domain: constants.TestDomainName, + WorkflowID: "child-workflow-id", + WorkflowType: &types.WorkflowType{ + Name: "child-workflow-type", + }, + ParentClosePolicy: &terminate, + }, + }} + + ms := execution.CreatePersistenceMutableState(msBuilder) + gwmsResponse := &persistence.GetWorkflowExecutionResponse{State: ms} + + s.mockExecutionMgr.On("GetWorkflowExecution", mock.Anything, mock.Anything).Return(gwmsResponse, nil).Once() + s.mockHistoryV2Mgr.On("AppendHistoryNodes", mock.Anything, mock.Anything).Return(&persistence.AppendHistoryNodesResponse{}, nil).Once() + s.mockExecutionMgr.On("UpdateWorkflowExecution", mock.Anything, mock.Anything).Return(&persistence.UpdateWorkflowExecutionResponse{MutableStateUpdateSessionStats: &persistence.MutableStateUpdateSessionStats{}}, nil).Once() + + _, err := s.mockHistoryEngine.RespondDecisionTaskCompleted(context.Background(), &types.HistoryRespondDecisionTaskCompletedRequest{ + DomainUUID: constants.TestDomainID, + CompleteRequest: &types.RespondDecisionTaskCompletedRequest{ + TaskToken: taskToken, + Decisions: decisions, + ExecutionContext: executionContext, + Identity: identity, + }, + }) + s.Nil(err, s.printHistory(msBuilder)) + executionBuilder := s.getBuilder(constants.TestDomainID, we) + s.Equal(int64(6), executionBuilder.GetExecutionInfo().NextEventID) + s.Equal(int64(3), executionBuilder.GetExecutionInfo().LastProcessedEvent) + s.Equal(executionContext, executionBuilder.GetExecutionInfo().ExecutionContext) + s.Equal(int(1), len(executionBuilder.GetPendingChildExecutionInfos())) + var childID int64 + for c := range executionBuilder.GetPendingChildExecutionInfos() { + childID = c + break + } + s.Equal("child-workflow-id", executionBuilder.GetPendingChildExecutionInfos()[childID].StartedWorkflowID) + s.Equal(types.ParentClosePolicyTerminate, executionBuilder.GetPendingChildExecutionInfos()[childID].ParentClosePolicy) +} + +func (s *engineSuite) TestRespondDecisionTaskCompletedSignalExternalWorkflowFailed() { + + we := types.WorkflowExecution{ + WorkflowID: "wId", + RunID: "invalid run id", + } + tl := "testTaskList" + taskToken, _ := json.Marshal(&common.TaskToken{ + WorkflowID: we.GetWorkflowID(), + RunID: we.GetRunID(), + ScheduleID: 2, + }) + identity := "testIdentity" + executionContext := []byte("context") + + msBuilder := execution.NewMutableStateBuilderWithEventV2( + s.mockHistoryEngine.shard, + testlogger.New(s.Suite.T()), + we.GetRunID(), + constants.TestLocalDomainEntry, + ) + test.AddWorkflowExecutionStartedEvent(msBuilder, we, "wType", tl, []byte("input"), 100, 200, identity) + di := test.AddDecisionTaskScheduledEvent(msBuilder) + test.AddDecisionTaskStartedEvent(msBuilder, di.ScheduleID, tl, identity) + + decisions := []*types.Decision{{ + DecisionType: types.DecisionTypeSignalExternalWorkflowExecution.Ptr(), + SignalExternalWorkflowExecutionDecisionAttributes: &types.SignalExternalWorkflowExecutionDecisionAttributes{ + Domain: constants.TestDomainID, + Execution: &types.WorkflowExecution{ + WorkflowID: we.WorkflowID, + RunID: we.RunID, + }, + SignalName: "signal", + Input: []byte("test input"), + }, + }} + + _, err := s.mockHistoryEngine.RespondDecisionTaskCompleted(context.Background(), &types.HistoryRespondDecisionTaskCompletedRequest{ + DomainUUID: constants.TestDomainID, + CompleteRequest: &types.RespondDecisionTaskCompletedRequest{ + TaskToken: taskToken, + Decisions: decisions, + ExecutionContext: executionContext, + Identity: identity, + }, + }) + + s.EqualError(err, "RunID is not valid UUID.") +} + +func (s *engineSuite) TestRespondDecisionTaskCompletedSignalExternalWorkflowFailed_UnKnownDomain() { + + we := types.WorkflowExecution{ + WorkflowID: "wId", + RunID: constants.TestRunID, + } + tl := "testTaskList" + taskToken, _ := json.Marshal(&common.TaskToken{ + WorkflowID: we.WorkflowID, + RunID: we.RunID, + ScheduleID: 2, + }) + identity := "testIdentity" + executionContext := []byte("context") + foreignDomain := "unknown domain" + + msBuilder := execution.NewMutableStateBuilderWithEventV2( + s.mockHistoryEngine.shard, + testlogger.New(s.Suite.T()), + we.GetRunID(), + constants.TestLocalDomainEntry, + ) + test.AddWorkflowExecutionStartedEvent(msBuilder, we, "wType", tl, []byte("input"), 100, 200, identity) + di := test.AddDecisionTaskScheduledEvent(msBuilder) + test.AddDecisionTaskStartedEvent(msBuilder, di.ScheduleID, tl, identity) + + decisions := []*types.Decision{{ + DecisionType: types.DecisionTypeSignalExternalWorkflowExecution.Ptr(), + SignalExternalWorkflowExecutionDecisionAttributes: &types.SignalExternalWorkflowExecutionDecisionAttributes{ + Domain: foreignDomain, + Execution: &types.WorkflowExecution{ + WorkflowID: we.WorkflowID, + RunID: we.RunID, + }, + SignalName: "signal", + Input: []byte("test input"), + }, + }} + + ms := execution.CreatePersistenceMutableState(msBuilder) + gwmsResponse := &persistence.GetWorkflowExecutionResponse{State: ms} + + s.mockExecutionMgr.On("GetWorkflowExecution", mock.Anything, mock.Anything).Return(gwmsResponse, nil).Once() + s.mockDomainCache.EXPECT().GetDomain(foreignDomain).Return( + nil, errors.New("get foreign domain error"), + ).Times(1) + + _, err := s.mockHistoryEngine.RespondDecisionTaskCompleted(context.Background(), &types.HistoryRespondDecisionTaskCompletedRequest{ + DomainUUID: constants.TestDomainID, + CompleteRequest: &types.RespondDecisionTaskCompletedRequest{ + TaskToken: taskToken, + Decisions: decisions, + ExecutionContext: executionContext, + Identity: identity, + }, + }) + + s.NotNil(err) +} + +func (s *engineSuite) TestRespondActivityTaskCompletedInvalidToken() { + + invalidToken, _ := json.Marshal("bad token") + identity := "testIdentity" + + err := s.mockHistoryEngine.RespondActivityTaskCompleted(context.Background(), &types.HistoryRespondActivityTaskCompletedRequest{ + DomainUUID: constants.TestDomainID, + CompleteRequest: &types.RespondActivityTaskCompletedRequest{ + TaskToken: invalidToken, + Result: nil, + Identity: identity, + }, + }) + + s.NotNil(err) + s.IsType(&types.BadRequestError{}, err) +} + +func (s *engineSuite) TestRespondActivityTaskCompletedIfNoExecution() { + + taskToken, _ := json.Marshal(&common.TaskToken{ + WorkflowID: "wId", + RunID: constants.TestRunID, + ScheduleID: 2, + }) + identity := "testIdentity" + + s.mockExecutionMgr.On("GetWorkflowExecution", mock.Anything, mock.Anything).Return(nil, &types.EntityNotExistsError{}).Once() + + err := s.mockHistoryEngine.RespondActivityTaskCompleted(context.Background(), &types.HistoryRespondActivityTaskCompletedRequest{ + DomainUUID: constants.TestDomainID, + CompleteRequest: &types.RespondActivityTaskCompletedRequest{ + TaskToken: taskToken, + Identity: identity, + }, + }) + s.NotNil(err) + s.IsType(&types.EntityNotExistsError{}, err) +} + +func (s *engineSuite) TestRespondActivityTaskCompletedIfNoRunID() { + + taskToken, _ := json.Marshal(&common.TaskToken{ + WorkflowID: "wId", + ScheduleID: 2, + }) + identity := "testIdentity" + + s.mockExecutionMgr.On("GetCurrentExecution", mock.Anything, mock.Anything).Return(nil, &types.EntityNotExistsError{}).Once() + + err := s.mockHistoryEngine.RespondActivityTaskCompleted(context.Background(), &types.HistoryRespondActivityTaskCompletedRequest{ + DomainUUID: constants.TestDomainID, + CompleteRequest: &types.RespondActivityTaskCompletedRequest{ + TaskToken: taskToken, + Identity: identity, + }, + }) + s.NotNil(err) + s.IsType(&types.EntityNotExistsError{}, err) +} + +func (s *engineSuite) TestRespondActivityTaskCompletedIfGetExecutionFailed() { + + taskToken, _ := json.Marshal(&common.TaskToken{ + WorkflowID: "wId", + RunID: constants.TestRunID, + ScheduleID: 2, + }) + identity := "testIdentity" + + s.mockExecutionMgr.On("GetWorkflowExecution", mock.Anything, mock.Anything).Return(nil, errors.New("FAILED")).Once() + + err := s.mockHistoryEngine.RespondActivityTaskCompleted(context.Background(), &types.HistoryRespondActivityTaskCompletedRequest{ + DomainUUID: constants.TestDomainID, + CompleteRequest: &types.RespondActivityTaskCompletedRequest{ + TaskToken: taskToken, + Identity: identity, + }, + }) + s.EqualError(err, "FAILED") +} + +func (s *engineSuite) TestRespondActivityTaskCompletedIfNoAIdProvided() { + + workflowExecution := types.WorkflowExecution{ + WorkflowID: "wId", + RunID: constants.TestRunID, + } + tasklist := "testTaskList" + identity := "testIdentity" + taskToken, _ := json.Marshal(&common.TaskToken{ + WorkflowID: "wId", + ScheduleID: common.EmptyEventID, + }) + + msBuilder := execution.NewMutableStateBuilderWithEventV2( + s.mockHistoryEngine.shard, + testlogger.New(s.Suite.T()), + constants.TestRunID, + constants.TestLocalDomainEntry, + ) + test.AddWorkflowExecutionStartedEvent(msBuilder, workflowExecution, "wType", tasklist, []byte("input"), 100, 200, identity) + test.AddDecisionTaskScheduledEvent(msBuilder) + ms := execution.CreatePersistenceMutableState(msBuilder) + gwmsResponse := &persistence.GetWorkflowExecutionResponse{State: ms} + gceResponse := &persistence.GetCurrentExecutionResponse{RunID: constants.TestRunID} + + s.mockExecutionMgr.On("GetCurrentExecution", mock.Anything, mock.Anything).Return(gceResponse, nil).Once() + s.mockExecutionMgr.On("GetWorkflowExecution", mock.Anything, mock.Anything).Return(gwmsResponse, nil).Once() + + err := s.mockHistoryEngine.RespondActivityTaskCompleted(context.Background(), &types.HistoryRespondActivityTaskCompletedRequest{ + DomainUUID: constants.TestDomainID, + CompleteRequest: &types.RespondActivityTaskCompletedRequest{ + TaskToken: taskToken, + Identity: identity, + }, + }) + s.EqualError(err, "Neither ActivityID nor ScheduleID is provided") +} + +func (s *engineSuite) TestRespondActivityTaskCompletedIfNotFound() { + + taskToken, _ := json.Marshal(&common.TaskToken{ + WorkflowID: "wId", + ScheduleID: common.EmptyEventID, + ActivityID: "aid", + }) + workflowExecution := types.WorkflowExecution{ + WorkflowID: "wId", + RunID: constants.TestRunID, + } + tasklist := "testTaskList" + identity := "testIdentity" + + msBuilder := execution.NewMutableStateBuilderWithEventV2( + s.mockHistoryEngine.shard, + testlogger.New(s.Suite.T()), + constants.TestRunID, + constants.TestLocalDomainEntry, + ) + test.AddWorkflowExecutionStartedEvent(msBuilder, workflowExecution, "wType", tasklist, []byte("input"), 100, 200, identity) + test.AddDecisionTaskScheduledEvent(msBuilder) + ms := execution.CreatePersistenceMutableState(msBuilder) + gwmsResponse := &persistence.GetWorkflowExecutionResponse{State: ms} + gceResponse := &persistence.GetCurrentExecutionResponse{RunID: constants.TestRunID} + + s.mockExecutionMgr.On("GetCurrentExecution", mock.Anything, mock.Anything).Return(gceResponse, nil).Once() + s.mockExecutionMgr.On("GetWorkflowExecution", mock.Anything, mock.Anything).Return(gwmsResponse, nil).Once() + + err := s.mockHistoryEngine.RespondActivityTaskCompleted(context.Background(), &types.HistoryRespondActivityTaskCompletedRequest{ + DomainUUID: constants.TestDomainID, + CompleteRequest: &types.RespondActivityTaskCompletedRequest{ + TaskToken: taskToken, + Identity: identity, + }, + }) + s.Error(err) +} + +func (s *engineSuite) TestRespondActivityTaskCompletedUpdateExecutionFailed() { + + we := types.WorkflowExecution{ + WorkflowID: "wId", + RunID: constants.TestRunID, + } + tl := "testTaskList" + taskToken, _ := json.Marshal(&common.TaskToken{ + WorkflowID: we.WorkflowID, + RunID: we.RunID, + ScheduleID: 5, + }) + identity := "testIdentity" + activityID := "activity1_id" + activityType := "activity_type1" + activityInput := []byte("input1") + activityResult := []byte("activity result") + + msBuilder := execution.NewMutableStateBuilderWithEventV2( + s.mockHistoryEngine.shard, + testlogger.New(s.Suite.T()), + we.GetRunID(), + constants.TestLocalDomainEntry, + ) + test.AddWorkflowExecutionStartedEvent(msBuilder, we, "wType", tl, []byte("input"), 100, 200, identity) + di := test.AddDecisionTaskScheduledEvent(msBuilder) + decisionStartedEvent := test.AddDecisionTaskStartedEvent(msBuilder, di.ScheduleID, tl, identity) + decisionCompletedEvent := test.AddDecisionTaskCompletedEvent(msBuilder, di.ScheduleID, + decisionStartedEvent.ID, nil, identity) + activityScheduledEvent, _ := test.AddActivityTaskScheduledEvent(msBuilder, decisionCompletedEvent.ID, activityID, + activityType, tl, activityInput, 100, 10, 1, 5) + test.AddActivityTaskStartedEvent(msBuilder, activityScheduledEvent.ID, identity) + + ms := execution.CreatePersistenceMutableState(msBuilder) + gwmsResponse := &persistence.GetWorkflowExecutionResponse{State: ms} + + s.mockExecutionMgr.On("GetWorkflowExecution", mock.Anything, mock.Anything).Return(gwmsResponse, nil).Once() + s.mockHistoryV2Mgr.On("AppendHistoryNodes", mock.Anything, mock.Anything).Return(&persistence.AppendHistoryNodesResponse{}, nil).Once() + s.mockExecutionMgr.On("UpdateWorkflowExecution", mock.Anything, mock.Anything).Return(&persistence.UpdateWorkflowExecutionResponse{MutableStateUpdateSessionStats: &persistence.MutableStateUpdateSessionStats{}}, errors.New("FAILED")).Once() + s.mockShardManager.On("UpdateShard", mock.Anything, mock.Anything).Return(nil).Once() + + err := s.mockHistoryEngine.RespondActivityTaskCompleted(context.Background(), &types.HistoryRespondActivityTaskCompletedRequest{ + DomainUUID: constants.TestDomainID, + CompleteRequest: &types.RespondActivityTaskCompletedRequest{ + TaskToken: taskToken, + Result: activityResult, + Identity: identity, + }, + }) + s.EqualError(err, "FAILED") +} + +func (s *engineSuite) TestRespondActivityTaskCompletedIfTaskCompleted() { + + we := types.WorkflowExecution{ + WorkflowID: "wId", + RunID: constants.TestRunID, + } + tl := "testTaskList" + taskToken, _ := json.Marshal(&common.TaskToken{ + WorkflowID: we.WorkflowID, + RunID: we.RunID, + ScheduleID: 5, + }) + identity := "testIdentity" + activityID := "activity1_id" + activityType := "activity_type1" + activityInput := []byte("input1") + activityResult := []byte("activity result") + + msBuilder := execution.NewMutableStateBuilderWithEventV2( + s.mockHistoryEngine.shard, + testlogger.New(s.Suite.T()), + we.GetRunID(), + constants.TestLocalDomainEntry, + ) + test.AddWorkflowExecutionStartedEvent(msBuilder, we, "wType", tl, []byte("input"), 100, 200, identity) + di := test.AddDecisionTaskScheduledEvent(msBuilder) + decisionStartedEvent := test.AddDecisionTaskStartedEvent(msBuilder, di.ScheduleID, tl, identity) + decisionCompletedEvent := test.AddDecisionTaskCompletedEvent(msBuilder, di.ScheduleID, + decisionStartedEvent.ID, nil, identity) + activityScheduledEvent, _ := test.AddActivityTaskScheduledEvent(msBuilder, decisionCompletedEvent.ID, activityID, + activityType, tl, activityInput, 100, 10, 1, 5) + activityStartedEvent := test.AddActivityTaskStartedEvent(msBuilder, activityScheduledEvent.ID, identity) + test.AddActivityTaskCompletedEvent(msBuilder, activityScheduledEvent.ID, activityStartedEvent.ID, + activityResult, identity) + test.AddDecisionTaskScheduledEvent(msBuilder) + + ms := execution.CreatePersistenceMutableState(msBuilder) + gwmsResponse := &persistence.GetWorkflowExecutionResponse{State: ms} + + s.mockExecutionMgr.On("GetWorkflowExecution", mock.Anything, mock.Anything).Return(gwmsResponse, nil).Once() + + err := s.mockHistoryEngine.RespondActivityTaskCompleted(context.Background(), &types.HistoryRespondActivityTaskCompletedRequest{ + DomainUUID: constants.TestDomainID, + CompleteRequest: &types.RespondActivityTaskCompletedRequest{ + TaskToken: taskToken, + Result: activityResult, + Identity: identity, + }, + }) + s.NotNil(err) + s.IsType(&types.EntityNotExistsError{}, err) +} + +func (s *engineSuite) TestRespondActivityTaskCompletedIfTaskNotStarted() { + + we := types.WorkflowExecution{ + WorkflowID: "wId", + RunID: constants.TestRunID, + } + tl := "testTaskList" + taskToken, _ := json.Marshal(&common.TaskToken{ + WorkflowID: we.WorkflowID, + RunID: we.RunID, + ScheduleID: 5, + }) + identity := "testIdentity" + activityID := "activity1_id" + activityType := "activity_type1" + activityInput := []byte("input1") + activityResult := []byte("activity result") + + msBuilder := execution.NewMutableStateBuilderWithEventV2( + s.mockHistoryEngine.shard, + testlogger.New(s.Suite.T()), + we.GetRunID(), + constants.TestLocalDomainEntry, + ) + test.AddWorkflowExecutionStartedEvent(msBuilder, we, "wType", tl, []byte("input"), 100, 200, identity) + di := test.AddDecisionTaskScheduledEvent(msBuilder) + decisionStartedEvent := test.AddDecisionTaskStartedEvent(msBuilder, di.ScheduleID, tl, identity) + decisionCompletedEvent := test.AddDecisionTaskCompletedEvent(msBuilder, di.ScheduleID, + decisionStartedEvent.ID, nil, identity) + test.AddActivityTaskScheduledEvent(msBuilder, decisionCompletedEvent.ID, activityID, + activityType, tl, activityInput, 100, 10, 1, 5) + + ms := execution.CreatePersistenceMutableState(msBuilder) + gwmsResponse := &persistence.GetWorkflowExecutionResponse{State: ms} + + s.mockExecutionMgr.On("GetWorkflowExecution", mock.Anything, mock.Anything).Return(gwmsResponse, nil).Once() + + err := s.mockHistoryEngine.RespondActivityTaskCompleted(context.Background(), &types.HistoryRespondActivityTaskCompletedRequest{ + DomainUUID: constants.TestDomainID, + CompleteRequest: &types.RespondActivityTaskCompletedRequest{ + TaskToken: taskToken, + Result: activityResult, + Identity: identity, + }, + }) + s.NotNil(err) + s.IsType(&types.EntityNotExistsError{}, err) +} + +func (s *engineSuite) TestRespondActivityTaskCompletedConflictOnUpdate() { + + we := types.WorkflowExecution{ + WorkflowID: "wId", + RunID: constants.TestRunID, + } + tl := "testTaskList" + taskToken, _ := json.Marshal(&common.TaskToken{ + WorkflowID: we.WorkflowID, + RunID: we.RunID, + ScheduleID: 5, + }) + identity := "testIdentity" + activity1ID := "activity1" + activity1Type := "activity_type1" + activity1Input := []byte("input1") + activity1Result := []byte("activity1_result") + activity2ID := "activity2" + activity2Type := "activity_type2" + activity2Input := []byte("input2") + + msBuilder := execution.NewMutableStateBuilderWithEventV2( + s.mockHistoryEngine.shard, + testlogger.New(s.Suite.T()), + we.GetRunID(), + constants.TestLocalDomainEntry, + ) + test.AddWorkflowExecutionStartedEvent(msBuilder, we, "wType", tl, []byte("input"), 100, 100, identity) + di := test.AddDecisionTaskScheduledEvent(msBuilder) + decisionStartedEvent1 := test.AddDecisionTaskStartedEvent(msBuilder, di.ScheduleID, tl, identity) + decisionCompletedEvent1 := test.AddDecisionTaskCompletedEvent(msBuilder, di.ScheduleID, + decisionStartedEvent1.ID, nil, identity) + activity1ScheduledEvent, _ := test.AddActivityTaskScheduledEvent(msBuilder, decisionCompletedEvent1.ID, activity1ID, + activity1Type, tl, activity1Input, 100, 10, 1, 5) + activity2ScheduledEvent, _ := test.AddActivityTaskScheduledEvent(msBuilder, decisionCompletedEvent1.ID, activity2ID, + activity2Type, tl, activity2Input, 100, 10, 1, 5) + test.AddActivityTaskStartedEvent(msBuilder, activity1ScheduledEvent.ID, identity) + test.AddActivityTaskStartedEvent(msBuilder, activity2ScheduledEvent.ID, identity) + + ms1 := execution.CreatePersistenceMutableState(msBuilder) + gwmsResponse1 := &persistence.GetWorkflowExecutionResponse{State: ms1} + + ms2 := execution.CreatePersistenceMutableState(msBuilder) + gwmsResponse2 := &persistence.GetWorkflowExecutionResponse{State: ms2} + + s.mockExecutionMgr.On("GetWorkflowExecution", mock.Anything, mock.Anything).Return(gwmsResponse1, nil).Once() + s.mockHistoryV2Mgr.On("AppendHistoryNodes", mock.Anything, mock.Anything).Return(&persistence.AppendHistoryNodesResponse{}, nil).Once() + s.mockExecutionMgr.On("UpdateWorkflowExecution", mock.Anything, mock.Anything).Return(&persistence.UpdateWorkflowExecutionResponse{MutableStateUpdateSessionStats: &persistence.MutableStateUpdateSessionStats{}}, &persistence.ConditionFailedError{}).Once() + + s.mockExecutionMgr.On("GetWorkflowExecution", mock.Anything, mock.Anything).Return(gwmsResponse2, nil).Once() + s.mockHistoryV2Mgr.On("AppendHistoryNodes", mock.Anything, mock.Anything).Return(&persistence.AppendHistoryNodesResponse{}, nil).Once() + s.mockExecutionMgr.On("UpdateWorkflowExecution", mock.Anything, mock.Anything).Return(&persistence.UpdateWorkflowExecutionResponse{MutableStateUpdateSessionStats: &persistence.MutableStateUpdateSessionStats{}}, nil).Once() + + err := s.mockHistoryEngine.RespondActivityTaskCompleted(context.Background(), &types.HistoryRespondActivityTaskCompletedRequest{ + DomainUUID: constants.TestDomainID, + CompleteRequest: &types.RespondActivityTaskCompletedRequest{ + TaskToken: taskToken, + Result: activity1Result, + Identity: identity, + }, + }) + s.Nil(err, s.printHistory(msBuilder)) + executionBuilder := s.getBuilder(constants.TestDomainID, we) + s.Equal(int64(11), executionBuilder.GetExecutionInfo().NextEventID) + s.Equal(int64(3), executionBuilder.GetExecutionInfo().LastProcessedEvent) + s.Equal(persistence.WorkflowStateRunning, executionBuilder.GetExecutionInfo().State) + + s.True(executionBuilder.HasPendingDecision()) + di, ok := executionBuilder.GetDecisionInfo(int64(10)) + s.True(ok) + s.Equal(int32(100), di.DecisionTimeout) + s.Equal(int64(10), di.ScheduleID) + s.Equal(common.EmptyEventID, di.StartedID) +} + +func (s *engineSuite) TestRespondActivityTaskCompletedMaxAttemptsExceeded() { + + we := types.WorkflowExecution{ + WorkflowID: "wId", + RunID: constants.TestRunID, + } + tl := "testTaskList" + taskToken, _ := json.Marshal(&common.TaskToken{ + WorkflowID: we.WorkflowID, + RunID: we.RunID, + ScheduleID: 5, + }) + identity := "testIdentity" + activityID := "activity1_id" + activityType := "activity_type1" + activityInput := []byte("input1") + activityResult := []byte("activity result") + + msBuilder := execution.NewMutableStateBuilderWithEventV2( + s.mockHistoryEngine.shard, + testlogger.New(s.Suite.T()), + we.GetRunID(), + constants.TestLocalDomainEntry, + ) + test.AddWorkflowExecutionStartedEvent(msBuilder, we, "wType", tl, []byte("input"), 100, 100, identity) + di := test.AddDecisionTaskScheduledEvent(msBuilder) + decisionStartedEvent := test.AddDecisionTaskStartedEvent(msBuilder, di.ScheduleID, tl, identity) + decisionCompletedEvent := test.AddDecisionTaskCompletedEvent(msBuilder, di.ScheduleID, + decisionStartedEvent.ID, nil, identity) + activityScheduledEvent, _ := test.AddActivityTaskScheduledEvent(msBuilder, decisionCompletedEvent.ID, activityID, + activityType, tl, activityInput, 100, 10, 1, 5) + test.AddActivityTaskStartedEvent(msBuilder, activityScheduledEvent.ID, identity) + + for i := 0; i < workflow.ConditionalRetryCount; i++ { + ms := execution.CreatePersistenceMutableState(msBuilder) + gwmsResponse := &persistence.GetWorkflowExecutionResponse{State: ms} + + s.mockExecutionMgr.On("GetWorkflowExecution", mock.Anything, mock.Anything).Return(gwmsResponse, nil).Once() + s.mockHistoryV2Mgr.On("AppendHistoryNodes", mock.Anything, mock.Anything).Return(&persistence.AppendHistoryNodesResponse{}, nil).Once() + s.mockExecutionMgr.On("UpdateWorkflowExecution", mock.Anything, mock.Anything).Return(&persistence.UpdateWorkflowExecutionResponse{MutableStateUpdateSessionStats: &persistence.MutableStateUpdateSessionStats{}}, &persistence.ConditionFailedError{}).Once() + } + + err := s.mockHistoryEngine.RespondActivityTaskCompleted(context.Background(), &types.HistoryRespondActivityTaskCompletedRequest{ + DomainUUID: constants.TestDomainID, + CompleteRequest: &types.RespondActivityTaskCompletedRequest{ + TaskToken: taskToken, + Result: activityResult, + Identity: identity, + }, + }) + s.Equal(workflow.ErrMaxAttemptsExceeded, err) +} + +func (s *engineSuite) TestRespondActivityTaskCompletedSuccess() { + + we := types.WorkflowExecution{ + WorkflowID: "wId", + RunID: constants.TestRunID, + } + tl := "testTaskList" + taskToken, _ := json.Marshal(&common.TaskToken{ + WorkflowID: we.WorkflowID, + RunID: we.RunID, + ScheduleID: 5, + }) + identity := "testIdentity" + activityID := "activity1_id" + activityType := "activity_type1" + activityInput := []byte("input1") + activityResult := []byte("activity result") + + msBuilder := execution.NewMutableStateBuilderWithEventV2( + s.mockHistoryEngine.shard, + testlogger.New(s.Suite.T()), + we.GetRunID(), + constants.TestLocalDomainEntry, + ) + test.AddWorkflowExecutionStartedEvent(msBuilder, we, "wType", tl, []byte("input"), 100, 100, identity) + di := test.AddDecisionTaskScheduledEvent(msBuilder) + decisionStartedEvent := test.AddDecisionTaskStartedEvent(msBuilder, di.ScheduleID, tl, identity) + decisionCompletedEvent := test.AddDecisionTaskCompletedEvent(msBuilder, di.ScheduleID, + decisionStartedEvent.ID, nil, identity) + activityScheduledEvent, _ := test.AddActivityTaskScheduledEvent(msBuilder, decisionCompletedEvent.ID, activityID, + activityType, tl, activityInput, 100, 10, 1, 5) + test.AddActivityTaskStartedEvent(msBuilder, activityScheduledEvent.ID, identity) + + ms := execution.CreatePersistenceMutableState(msBuilder) + gwmsResponse := &persistence.GetWorkflowExecutionResponse{State: ms} + + s.mockExecutionMgr.On("GetWorkflowExecution", mock.Anything, mock.Anything).Return(gwmsResponse, nil).Once() + s.mockHistoryV2Mgr.On("AppendHistoryNodes", mock.Anything, mock.Anything).Return(&persistence.AppendHistoryNodesResponse{}, nil).Once() + s.mockExecutionMgr.On("UpdateWorkflowExecution", mock.Anything, mock.Anything).Return(&persistence.UpdateWorkflowExecutionResponse{MutableStateUpdateSessionStats: &persistence.MutableStateUpdateSessionStats{}}, nil).Once() + + err := s.mockHistoryEngine.RespondActivityTaskCompleted(context.Background(), &types.HistoryRespondActivityTaskCompletedRequest{ + DomainUUID: constants.TestDomainID, + CompleteRequest: &types.RespondActivityTaskCompletedRequest{ + TaskToken: taskToken, + Result: activityResult, + Identity: identity, + }, + }) + s.Nil(err, s.printHistory(msBuilder)) + executionBuilder := s.getBuilder(constants.TestDomainID, we) + s.Equal(int64(9), executionBuilder.GetExecutionInfo().NextEventID) + s.Equal(int64(3), executionBuilder.GetExecutionInfo().LastProcessedEvent) + s.Equal(persistence.WorkflowStateRunning, executionBuilder.GetExecutionInfo().State) + + s.True(executionBuilder.HasPendingDecision()) + di, ok := executionBuilder.GetDecisionInfo(int64(8)) + s.True(ok) + s.Equal(int32(100), di.DecisionTimeout) + s.Equal(int64(8), di.ScheduleID) + s.Equal(common.EmptyEventID, di.StartedID) +} + +func (s *engineSuite) TestRespondActivityTaskCompletedByIdSuccess() { + + we := types.WorkflowExecution{ + WorkflowID: "wId", + RunID: constants.TestRunID, + } + tl := "testTaskList" + + identity := "testIdentity" + activityID := "activity1_id" + activityType := "activity_type1" + activityInput := []byte("input1") + activityResult := []byte("activity result") + taskToken, _ := json.Marshal(&common.TaskToken{ + WorkflowID: we.WorkflowID, + ScheduleID: common.EmptyEventID, + ActivityID: activityID, + }) + + msBuilder := execution.NewMutableStateBuilderWithEventV2( + s.mockHistoryEngine.shard, + testlogger.New(s.Suite.T()), + we.GetRunID(), + constants.TestLocalDomainEntry, + ) + test.AddWorkflowExecutionStartedEvent(msBuilder, we, "wType", tl, []byte("input"), 100, 100, identity) + decisionScheduledEvent := test.AddDecisionTaskScheduledEvent(msBuilder) + decisionStartedEvent := test.AddDecisionTaskStartedEvent(msBuilder, decisionScheduledEvent.ScheduleID, tl, identity) + decisionCompletedEvent := test.AddDecisionTaskCompletedEvent(msBuilder, decisionScheduledEvent.ScheduleID, + decisionStartedEvent.ID, nil, identity) + activityScheduledEvent, _ := test.AddActivityTaskScheduledEvent(msBuilder, decisionCompletedEvent.ID, activityID, + activityType, tl, activityInput, 100, 10, 1, 5) + test.AddActivityTaskStartedEvent(msBuilder, activityScheduledEvent.ID, identity) + + ms := execution.CreatePersistenceMutableState(msBuilder) + gwmsResponse := &persistence.GetWorkflowExecutionResponse{State: ms} + gceResponse := &persistence.GetCurrentExecutionResponse{RunID: we.RunID} + + s.mockExecutionMgr.On("GetCurrentExecution", mock.Anything, mock.Anything).Return(gceResponse, nil).Once() + s.mockExecutionMgr.On("GetWorkflowExecution", mock.Anything, mock.Anything).Return(gwmsResponse, nil).Once() + s.mockHistoryV2Mgr.On("AppendHistoryNodes", mock.Anything, mock.Anything).Return(&persistence.AppendHistoryNodesResponse{}, nil).Once() + s.mockExecutionMgr.On("UpdateWorkflowExecution", mock.Anything, mock.Anything).Return(&persistence.UpdateWorkflowExecutionResponse{MutableStateUpdateSessionStats: &persistence.MutableStateUpdateSessionStats{}}, nil).Once() + + err := s.mockHistoryEngine.RespondActivityTaskCompleted(context.Background(), &types.HistoryRespondActivityTaskCompletedRequest{ + DomainUUID: constants.TestDomainID, + CompleteRequest: &types.RespondActivityTaskCompletedRequest{ + TaskToken: taskToken, + Result: activityResult, + Identity: identity, + }, + }) + s.Nil(err, s.printHistory(msBuilder)) + executionBuilder := s.getBuilder(constants.TestDomainID, we) + s.Equal(int64(9), executionBuilder.GetExecutionInfo().NextEventID) + s.Equal(int64(3), executionBuilder.GetExecutionInfo().LastProcessedEvent) + s.Equal(persistence.WorkflowStateRunning, executionBuilder.GetExecutionInfo().State) + + s.True(executionBuilder.HasPendingDecision()) + di, ok := executionBuilder.GetDecisionInfo(int64(8)) + s.True(ok) + s.Equal(int32(100), di.DecisionTimeout) + s.Equal(int64(8), di.ScheduleID) + s.Equal(common.EmptyEventID, di.StartedID) +} + +func (s *engineSuite) TestRespondActivityTaskFailedInvalidToken() { + + invalidToken, _ := json.Marshal("bad token") + identity := "testIdentity" + + err := s.mockHistoryEngine.RespondActivityTaskFailed(context.Background(), &types.HistoryRespondActivityTaskFailedRequest{ + DomainUUID: constants.TestDomainID, + FailedRequest: &types.RespondActivityTaskFailedRequest{ + TaskToken: invalidToken, + Identity: identity, + }, + }) + + s.NotNil(err) + s.IsType(&types.BadRequestError{}, err) +} + +func (s *engineSuite) TestRespondActivityTaskFailedIfNoExecution() { + + taskToken, _ := json.Marshal(&common.TaskToken{ + WorkflowID: "wId", + RunID: constants.TestRunID, + ScheduleID: 2, + }) + identity := "testIdentity" + + s.mockExecutionMgr.On("GetWorkflowExecution", mock.Anything, mock.Anything).Return(nil, + &types.EntityNotExistsError{}).Once() + + err := s.mockHistoryEngine.RespondActivityTaskFailed(context.Background(), &types.HistoryRespondActivityTaskFailedRequest{ + DomainUUID: constants.TestDomainID, + FailedRequest: &types.RespondActivityTaskFailedRequest{ + TaskToken: taskToken, + Identity: identity, + }, + }) + s.NotNil(err) + s.IsType(&types.EntityNotExistsError{}, err) +} + +func (s *engineSuite) TestRespondActivityTaskFailedIfNoRunID() { + + taskToken, _ := json.Marshal(&common.TaskToken{ + WorkflowID: "wId", + ScheduleID: 2, + }) + identity := "testIdentity" + + s.mockExecutionMgr.On("GetCurrentExecution", mock.Anything, mock.Anything).Return(nil, + &types.EntityNotExistsError{}).Once() + + err := s.mockHistoryEngine.RespondActivityTaskFailed(context.Background(), &types.HistoryRespondActivityTaskFailedRequest{ + DomainUUID: constants.TestDomainID, + FailedRequest: &types.RespondActivityTaskFailedRequest{ + TaskToken: taskToken, + Identity: identity, + }, + }) + s.NotNil(err) + s.IsType(&types.EntityNotExistsError{}, err) +} + +func (s *engineSuite) TestRespondActivityTaskFailedIfGetExecutionFailed() { + + taskToken, _ := json.Marshal(&common.TaskToken{ + WorkflowID: "wId", + RunID: constants.TestRunID, + ScheduleID: 2, + }) + identity := "testIdentity" + + s.mockExecutionMgr.On("GetWorkflowExecution", mock.Anything, mock.Anything).Return(nil, + errors.New("FAILED")).Once() + + err := s.mockHistoryEngine.RespondActivityTaskFailed(context.Background(), &types.HistoryRespondActivityTaskFailedRequest{ + DomainUUID: constants.TestDomainID, + FailedRequest: &types.RespondActivityTaskFailedRequest{ + TaskToken: taskToken, + Identity: identity, + }, + }) + s.EqualError(err, "FAILED") +} + +func (s *engineSuite) TestRespondActivityTaskFailededIfNoAIdProvided() { + + taskToken, _ := json.Marshal(&common.TaskToken{ + WorkflowID: "wId", + ScheduleID: common.EmptyEventID, + }) + workflowExecution := types.WorkflowExecution{ + WorkflowID: "wId", + RunID: constants.TestRunID, + } + tasklist := "testTaskList" + identity := "testIdentity" + + msBuilder := execution.NewMutableStateBuilderWithEventV2( + s.mockHistoryEngine.shard, + testlogger.New(s.Suite.T()), + constants.TestRunID, + constants.TestLocalDomainEntry, + ) + test.AddWorkflowExecutionStartedEvent(msBuilder, workflowExecution, "wType", tasklist, []byte("input"), 100, 200, identity) + test.AddDecisionTaskScheduledEvent(msBuilder) + ms := execution.CreatePersistenceMutableState(msBuilder) + gwmsResponse := &persistence.GetWorkflowExecutionResponse{State: ms} + gceResponse := &persistence.GetCurrentExecutionResponse{RunID: constants.TestRunID} + + s.mockExecutionMgr.On("GetCurrentExecution", mock.Anything, mock.Anything).Return(gceResponse, nil).Once() + s.mockExecutionMgr.On("GetWorkflowExecution", mock.Anything, mock.Anything).Return(gwmsResponse, nil).Once() + + err := s.mockHistoryEngine.RespondActivityTaskFailed(context.Background(), &types.HistoryRespondActivityTaskFailedRequest{ + DomainUUID: constants.TestDomainID, + FailedRequest: &types.RespondActivityTaskFailedRequest{ + TaskToken: taskToken, + Identity: identity, + }, + }) + s.EqualError(err, "Neither ActivityID nor ScheduleID is provided") +} + +func (s *engineSuite) TestRespondActivityTaskFailededIfNotFound() { + + taskToken, _ := json.Marshal(&common.TaskToken{ + WorkflowID: "wId", + ScheduleID: common.EmptyEventID, + ActivityID: "aid", + }) + workflowExecution := types.WorkflowExecution{ + WorkflowID: "wId", + RunID: constants.TestRunID, + } + tasklist := "testTaskList" + identity := "testIdentity" + + msBuilder := execution.NewMutableStateBuilderWithEventV2( + s.mockHistoryEngine.shard, + testlogger.New(s.Suite.T()), + constants.TestRunID, + constants.TestLocalDomainEntry, + ) + test.AddWorkflowExecutionStartedEvent(msBuilder, workflowExecution, "wType", tasklist, []byte("input"), 100, 200, identity) + test.AddDecisionTaskScheduledEvent(msBuilder) + ms := execution.CreatePersistenceMutableState(msBuilder) + gwmsResponse := &persistence.GetWorkflowExecutionResponse{State: ms} + gceResponse := &persistence.GetCurrentExecutionResponse{RunID: constants.TestRunID} + + s.mockExecutionMgr.On("GetCurrentExecution", mock.Anything, mock.Anything).Return(gceResponse, nil).Once() + s.mockExecutionMgr.On("GetWorkflowExecution", mock.Anything, mock.Anything).Return(gwmsResponse, nil).Once() + + err := s.mockHistoryEngine.RespondActivityTaskFailed(context.Background(), &types.HistoryRespondActivityTaskFailedRequest{ + DomainUUID: constants.TestDomainID, + FailedRequest: &types.RespondActivityTaskFailedRequest{ + TaskToken: taskToken, + Identity: identity, + }, + }) + s.Error(err) +} + +func (s *engineSuite) TestRespondActivityTaskFailedUpdateExecutionFailed() { + + we := types.WorkflowExecution{ + WorkflowID: "wId", + RunID: constants.TestRunID, + } + tl := "testTaskList" + taskToken, _ := json.Marshal(&common.TaskToken{ + WorkflowID: we.WorkflowID, + RunID: we.RunID, + ScheduleID: 5, + }) + identity := "testIdentity" + activityID := "activity1_id" + activityType := "activity_type1" + activityInput := []byte("input1") + + msBuilder := execution.NewMutableStateBuilderWithEventV2( + s.mockHistoryEngine.shard, + testlogger.New(s.Suite.T()), + we.GetRunID(), + constants.TestLocalDomainEntry, + ) + test.AddWorkflowExecutionStartedEvent(msBuilder, we, "wType", tl, []byte("input"), 100, 100, identity) + di := test.AddDecisionTaskScheduledEvent(msBuilder) + decisionStartedEvent := test.AddDecisionTaskStartedEvent(msBuilder, di.ScheduleID, tl, identity) + decisionCompletedEvent := test.AddDecisionTaskCompletedEvent(msBuilder, di.ScheduleID, + decisionStartedEvent.ID, nil, identity) + activityScheduledEvent, _ := test.AddActivityTaskScheduledEvent(msBuilder, decisionCompletedEvent.ID, activityID, + activityType, tl, activityInput, 100, 10, 1, 5) + test.AddActivityTaskStartedEvent(msBuilder, activityScheduledEvent.ID, identity) + + ms := execution.CreatePersistenceMutableState(msBuilder) + gwmsResponse := &persistence.GetWorkflowExecutionResponse{State: ms} + + s.mockExecutionMgr.On("GetWorkflowExecution", mock.Anything, mock.Anything).Return(gwmsResponse, nil).Once() + s.mockHistoryV2Mgr.On("AppendHistoryNodes", mock.Anything, mock.Anything).Return(&persistence.AppendHistoryNodesResponse{}, nil).Once() + s.mockExecutionMgr.On("UpdateWorkflowExecution", mock.Anything, mock.Anything).Return(&persistence.UpdateWorkflowExecutionResponse{MutableStateUpdateSessionStats: &persistence.MutableStateUpdateSessionStats{}}, errors.New("FAILED")).Once() + s.mockShardManager.On("UpdateShard", mock.Anything, mock.Anything).Return(nil).Once() + + err := s.mockHistoryEngine.RespondActivityTaskFailed(context.Background(), &types.HistoryRespondActivityTaskFailedRequest{ + DomainUUID: constants.TestDomainID, + FailedRequest: &types.RespondActivityTaskFailedRequest{ + TaskToken: taskToken, + Identity: identity, + }, + }) + s.EqualError(err, "FAILED") +} + +func (s *engineSuite) TestRespondActivityTaskFailedIfTaskCompleted() { + + we := types.WorkflowExecution{ + WorkflowID: "wId", + RunID: constants.TestRunID, + } + tl := "testTaskList" + taskToken, _ := json.Marshal(&common.TaskToken{ + WorkflowID: we.WorkflowID, + RunID: we.RunID, + ScheduleID: 5, + }) + identity := "testIdentity" + activityID := "activity1_id" + activityType := "activity_type1" + activityInput := []byte("input1") + failReason := "fail reason" + details := []byte("fail details") + + msBuilder := execution.NewMutableStateBuilderWithEventV2( + s.mockHistoryEngine.shard, + testlogger.New(s.Suite.T()), + we.GetRunID(), + constants.TestLocalDomainEntry, + ) + test.AddWorkflowExecutionStartedEvent(msBuilder, we, "wType", tl, []byte("input"), 100, 100, identity) + di := test.AddDecisionTaskScheduledEvent(msBuilder) + decisionStartedEvent := test.AddDecisionTaskStartedEvent(msBuilder, di.ScheduleID, tl, identity) + decisionCompletedEvent := test.AddDecisionTaskCompletedEvent(msBuilder, di.ScheduleID, + decisionStartedEvent.ID, nil, identity) + activityScheduledEvent, _ := test.AddActivityTaskScheduledEvent(msBuilder, decisionCompletedEvent.ID, activityID, + activityType, tl, activityInput, 100, 10, 1, 5) + activityStartedEvent := test.AddActivityTaskStartedEvent(msBuilder, activityScheduledEvent.ID, identity) + test.AddActivityTaskFailedEvent(msBuilder, activityScheduledEvent.ID, activityStartedEvent.ID, + failReason, details, identity) + test.AddDecisionTaskScheduledEvent(msBuilder) + + ms := execution.CreatePersistenceMutableState(msBuilder) + gwmsResponse := &persistence.GetWorkflowExecutionResponse{State: ms} + + s.mockExecutionMgr.On("GetWorkflowExecution", mock.Anything, mock.Anything).Return(gwmsResponse, nil).Once() + + err := s.mockHistoryEngine.RespondActivityTaskFailed(context.Background(), &types.HistoryRespondActivityTaskFailedRequest{ + DomainUUID: constants.TestDomainID, + FailedRequest: &types.RespondActivityTaskFailedRequest{ + TaskToken: taskToken, + Reason: &failReason, + Details: details, + Identity: identity, + }, + }) + s.NotNil(err) + s.IsType(&types.EntityNotExistsError{}, err) +} + +func (s *engineSuite) TestRespondActivityTaskFailedIfTaskNotStarted() { + + we := types.WorkflowExecution{ + WorkflowID: "wId", + RunID: constants.TestRunID, + } + tl := "testTaskList" + taskToken, _ := json.Marshal(&common.TaskToken{ + WorkflowID: we.WorkflowID, + RunID: we.RunID, + ScheduleID: 5, + }) + identity := "testIdentity" + activityID := "activity1_id" + activityType := "activity_type1" + activityInput := []byte("input1") + + msBuilder := execution.NewMutableStateBuilderWithEventV2( + s.mockHistoryEngine.shard, + testlogger.New(s.Suite.T()), + we.GetRunID(), + constants.TestLocalDomainEntry, + ) + test.AddWorkflowExecutionStartedEvent(msBuilder, we, "wType", tl, []byte("input"), 100, 100, identity) + di := test.AddDecisionTaskScheduledEvent(msBuilder) + decisionStartedEvent := test.AddDecisionTaskStartedEvent(msBuilder, di.ScheduleID, tl, identity) + decisionCompletedEvent := test.AddDecisionTaskCompletedEvent(msBuilder, di.ScheduleID, + decisionStartedEvent.ID, nil, identity) + test.AddActivityTaskScheduledEvent(msBuilder, decisionCompletedEvent.ID, activityID, + activityType, tl, activityInput, 100, 10, 1, 5) + + ms := execution.CreatePersistenceMutableState(msBuilder) + gwmsResponse := &persistence.GetWorkflowExecutionResponse{State: ms} + + s.mockExecutionMgr.On("GetWorkflowExecution", mock.Anything, mock.Anything).Return(gwmsResponse, nil).Once() + + err := s.mockHistoryEngine.RespondActivityTaskFailed(context.Background(), &types.HistoryRespondActivityTaskFailedRequest{ + DomainUUID: constants.TestDomainID, + FailedRequest: &types.RespondActivityTaskFailedRequest{ + TaskToken: taskToken, + Identity: identity, + }, + }) + s.NotNil(err) + s.IsType(&types.EntityNotExistsError{}, err) +} + +func (s *engineSuite) TestRespondActivityTaskFailedConflictOnUpdate() { + + we := types.WorkflowExecution{ + WorkflowID: "wId", + RunID: constants.TestRunID, + } + tl := "testTaskList" + taskToken, _ := json.Marshal(&common.TaskToken{ + WorkflowID: we.WorkflowID, + RunID: we.RunID, + ScheduleID: 5, + }) + identity := "testIdentity" + activity1ID := "activity1" + activity1Type := "activity_type1" + activity1Input := []byte("input1") + failReason := "fail reason" + details := []byte("fail details.") + activity2ID := "activity2" + activity2Type := "activity_type2" + activity2Input := []byte("input2") + activity2Result := []byte("activity2_result") + + msBuilder := execution.NewMutableStateBuilderWithEventV2( + s.mockHistoryEngine.shard, + testlogger.New(s.Suite.T()), + we.GetRunID(), + constants.TestLocalDomainEntry, + ) + test.AddWorkflowExecutionStartedEvent(msBuilder, we, "wType", tl, []byte("input"), 25, 25, identity) + di1 := test.AddDecisionTaskScheduledEvent(msBuilder) + decisionStartedEvent1 := test.AddDecisionTaskStartedEvent(msBuilder, di1.ScheduleID, tl, identity) + decisionCompletedEvent1 := test.AddDecisionTaskCompletedEvent(msBuilder, di1.ScheduleID, + decisionStartedEvent1.ID, nil, identity) + activity1ScheduledEvent, _ := test.AddActivityTaskScheduledEvent(msBuilder, decisionCompletedEvent1.ID, activity1ID, + activity1Type, tl, activity1Input, 100, 10, 1, 5) + activity2ScheduledEvent, _ := test.AddActivityTaskScheduledEvent(msBuilder, decisionCompletedEvent1.ID, activity2ID, + activity2Type, tl, activity2Input, 100, 10, 1, 5) + test.AddActivityTaskStartedEvent(msBuilder, activity1ScheduledEvent.ID, identity) + activity2StartedEvent := test.AddActivityTaskStartedEvent(msBuilder, activity2ScheduledEvent.ID, identity) + + ms1 := execution.CreatePersistenceMutableState(msBuilder) + gwmsResponse1 := &persistence.GetWorkflowExecutionResponse{State: ms1} + + test.AddActivityTaskCompletedEvent(msBuilder, activity2ScheduledEvent.ID, + activity2StartedEvent.ID, activity2Result, identity) + test.AddDecisionTaskScheduledEvent(msBuilder) + + ms2 := execution.CreatePersistenceMutableState(msBuilder) + gwmsResponse2 := &persistence.GetWorkflowExecutionResponse{State: ms2} + + s.mockExecutionMgr.On("GetWorkflowExecution", mock.Anything, mock.Anything).Return(gwmsResponse1, nil).Once() + s.mockHistoryV2Mgr.On("AppendHistoryNodes", mock.Anything, mock.Anything).Return(&persistence.AppendHistoryNodesResponse{}, nil).Once() + s.mockExecutionMgr.On("UpdateWorkflowExecution", mock.Anything, mock.Anything).Return(&persistence.UpdateWorkflowExecutionResponse{MutableStateUpdateSessionStats: &persistence.MutableStateUpdateSessionStats{}}, &persistence.ConditionFailedError{}).Once() + + s.mockExecutionMgr.On("GetWorkflowExecution", mock.Anything, mock.Anything).Return(gwmsResponse2, nil).Once() + s.mockHistoryV2Mgr.On("AppendHistoryNodes", mock.Anything, mock.Anything).Return(&persistence.AppendHistoryNodesResponse{}, nil).Once() + s.mockExecutionMgr.On("UpdateWorkflowExecution", mock.Anything, mock.Anything).Return(&persistence.UpdateWorkflowExecutionResponse{MutableStateUpdateSessionStats: &persistence.MutableStateUpdateSessionStats{}}, nil).Once() + + err := s.mockHistoryEngine.RespondActivityTaskFailed(context.Background(), &types.HistoryRespondActivityTaskFailedRequest{ + DomainUUID: constants.TestDomainID, + FailedRequest: &types.RespondActivityTaskFailedRequest{ + TaskToken: taskToken, + Reason: &failReason, + Details: details, + Identity: identity, + }, + }) + s.Nil(err, s.printHistory(msBuilder)) + executionBuilder := s.getBuilder(constants.TestDomainID, we) + s.Equal(int64(12), executionBuilder.GetExecutionInfo().NextEventID) + s.Equal(int64(3), executionBuilder.GetExecutionInfo().LastProcessedEvent) + s.Equal(persistence.WorkflowStateRunning, executionBuilder.GetExecutionInfo().State) + + s.True(executionBuilder.HasPendingDecision()) + di, ok := executionBuilder.GetDecisionInfo(int64(10)) + s.True(ok) + s.Equal(int32(25), di.DecisionTimeout) + s.Equal(int64(10), di.ScheduleID) + s.Equal(common.EmptyEventID, di.StartedID) +} + +func (s *engineSuite) TestRespondActivityTaskFailedMaxAttemptsExceeded() { + + we := types.WorkflowExecution{ + WorkflowID: "wId", + RunID: constants.TestRunID, + } + tl := "testTaskList" + taskToken, _ := json.Marshal(&common.TaskToken{ + WorkflowID: we.WorkflowID, + RunID: we.RunID, + ScheduleID: 5, + }) + identity := "testIdentity" + activityID := "activity1_id" + activityType := "activity_type1" + activityInput := []byte("input1") + + msBuilder := execution.NewMutableStateBuilderWithEventV2( + s.mockHistoryEngine.shard, + testlogger.New(s.Suite.T()), + we.GetRunID(), + constants.TestLocalDomainEntry, + ) + test.AddWorkflowExecutionStartedEvent(msBuilder, we, "wType", tl, []byte("input"), 100, 100, identity) + di := test.AddDecisionTaskScheduledEvent(msBuilder) + decisionStartedEvent := test.AddDecisionTaskStartedEvent(msBuilder, di.ScheduleID, tl, identity) + decisionCompletedEvent := test.AddDecisionTaskCompletedEvent(msBuilder, di.ScheduleID, + decisionStartedEvent.ID, nil, identity) + activityScheduledEvent, _ := test.AddActivityTaskScheduledEvent(msBuilder, decisionCompletedEvent.ID, activityID, + activityType, tl, activityInput, 100, 10, 1, 5) + test.AddActivityTaskStartedEvent(msBuilder, activityScheduledEvent.ID, identity) + + for i := 0; i < workflow.ConditionalRetryCount; i++ { + ms := execution.CreatePersistenceMutableState(msBuilder) + gwmsResponse := &persistence.GetWorkflowExecutionResponse{State: ms} + + s.mockExecutionMgr.On("GetWorkflowExecution", mock.Anything, mock.Anything).Return(gwmsResponse, nil).Once() + s.mockHistoryV2Mgr.On("AppendHistoryNodes", mock.Anything, mock.Anything).Return(&persistence.AppendHistoryNodesResponse{}, nil).Once() + s.mockExecutionMgr.On("UpdateWorkflowExecution", mock.Anything, mock.Anything).Return(&persistence.UpdateWorkflowExecutionResponse{MutableStateUpdateSessionStats: &persistence.MutableStateUpdateSessionStats{}}, &persistence.ConditionFailedError{}).Once() + } + + err := s.mockHistoryEngine.RespondActivityTaskFailed(context.Background(), &types.HistoryRespondActivityTaskFailedRequest{ + DomainUUID: constants.TestDomainID, + FailedRequest: &types.RespondActivityTaskFailedRequest{ + TaskToken: taskToken, + Identity: identity, + }, + }) + s.Equal(workflow.ErrMaxAttemptsExceeded, err) +} + +func (s *engineSuite) TestRespondActivityTaskFailedSuccess() { + + we := types.WorkflowExecution{ + WorkflowID: "wId", + RunID: constants.TestRunID, + } + tl := "testTaskList" + taskToken, _ := json.Marshal(&common.TaskToken{ + WorkflowID: we.WorkflowID, + RunID: we.RunID, + ScheduleID: 5, + }) + identity := "testIdentity" + activityID := "activity1_id" + activityType := "activity_type1" + activityInput := []byte("input1") + failReason := "failed" + failDetails := []byte("fail details.") + + msBuilder := execution.NewMutableStateBuilderWithEventV2( + s.mockHistoryEngine.shard, + testlogger.New(s.Suite.T()), + we.GetRunID(), + constants.TestLocalDomainEntry, + ) + test.AddWorkflowExecutionStartedEvent(msBuilder, we, "wType", tl, []byte("input"), 100, 100, identity) + di := test.AddDecisionTaskScheduledEvent(msBuilder) + decisionStartedEvent := test.AddDecisionTaskStartedEvent(msBuilder, di.ScheduleID, tl, identity) + decisionCompletedEvent := test.AddDecisionTaskCompletedEvent(msBuilder, di.ScheduleID, + decisionStartedEvent.ID, nil, identity) + activityScheduledEvent, _ := test.AddActivityTaskScheduledEvent(msBuilder, decisionCompletedEvent.ID, activityID, + activityType, tl, activityInput, 100, 10, 1, 5) + test.AddActivityTaskStartedEvent(msBuilder, activityScheduledEvent.ID, identity) + + ms := execution.CreatePersistenceMutableState(msBuilder) + gwmsResponse := &persistence.GetWorkflowExecutionResponse{State: ms} + + s.mockExecutionMgr.On("GetWorkflowExecution", mock.Anything, mock.Anything).Return(gwmsResponse, nil).Once() + s.mockHistoryV2Mgr.On("AppendHistoryNodes", mock.Anything, mock.Anything).Return(&persistence.AppendHistoryNodesResponse{}, nil).Once() + s.mockExecutionMgr.On("UpdateWorkflowExecution", mock.Anything, mock.Anything).Return(&persistence.UpdateWorkflowExecutionResponse{MutableStateUpdateSessionStats: &persistence.MutableStateUpdateSessionStats{}}, nil).Once() + + err := s.mockHistoryEngine.RespondActivityTaskFailed(context.Background(), &types.HistoryRespondActivityTaskFailedRequest{ + DomainUUID: constants.TestDomainID, + FailedRequest: &types.RespondActivityTaskFailedRequest{ + TaskToken: taskToken, + Reason: &failReason, + Details: failDetails, + Identity: identity, + }, + }) + s.Nil(err) + executionBuilder := s.getBuilder(constants.TestDomainID, we) + s.Equal(int64(9), executionBuilder.GetExecutionInfo().NextEventID) + s.Equal(int64(3), executionBuilder.GetExecutionInfo().LastProcessedEvent) + s.Equal(persistence.WorkflowStateRunning, executionBuilder.GetExecutionInfo().State) + + s.True(executionBuilder.HasPendingDecision()) + di, ok := executionBuilder.GetDecisionInfo(int64(8)) + s.True(ok) + s.Equal(int32(100), di.DecisionTimeout) + s.Equal(int64(8), di.ScheduleID) + s.Equal(common.EmptyEventID, di.StartedID) +} + +func (s *engineSuite) TestRespondActivityTaskFailedByIDSuccess() { + + we := types.WorkflowExecution{ + WorkflowID: "wId", + RunID: constants.TestRunID, + } + tl := "testTaskList" + + identity := "testIdentity" + activityID := "activity1_id" + activityType := "activity_type1" + activityInput := []byte("input1") + failReason := "failed" + failDetails := []byte("fail details.") + taskToken, _ := json.Marshal(&common.TaskToken{ + WorkflowID: we.WorkflowID, + ScheduleID: common.EmptyEventID, + ActivityID: activityID, + }) + + msBuilder := execution.NewMutableStateBuilderWithEventV2( + s.mockHistoryEngine.shard, + testlogger.New(s.Suite.T()), + we.GetRunID(), + constants.TestLocalDomainEntry, + ) + test.AddWorkflowExecutionStartedEvent(msBuilder, we, "wType", tl, []byte("input"), 100, 100, identity) + decisionScheduledEvent := test.AddDecisionTaskScheduledEvent(msBuilder) + decisionStartedEvent := test.AddDecisionTaskStartedEvent(msBuilder, decisionScheduledEvent.ScheduleID, tl, identity) + decisionCompletedEvent := test.AddDecisionTaskCompletedEvent(msBuilder, decisionScheduledEvent.ScheduleID, + decisionStartedEvent.ID, nil, identity) + activityScheduledEvent, _ := test.AddActivityTaskScheduledEvent(msBuilder, decisionCompletedEvent.ID, activityID, + activityType, tl, activityInput, 100, 10, 1, 5) + test.AddActivityTaskStartedEvent(msBuilder, activityScheduledEvent.ID, identity) + + ms := execution.CreatePersistenceMutableState(msBuilder) + gwmsResponse := &persistence.GetWorkflowExecutionResponse{State: ms} + gceResponse := &persistence.GetCurrentExecutionResponse{RunID: we.RunID} + + s.mockExecutionMgr.On("GetCurrentExecution", mock.Anything, mock.Anything).Return(gceResponse, nil).Once() + s.mockExecutionMgr.On("GetWorkflowExecution", mock.Anything, mock.Anything).Return(gwmsResponse, nil).Once() + s.mockHistoryV2Mgr.On("AppendHistoryNodes", mock.Anything, mock.Anything).Return(&persistence.AppendHistoryNodesResponse{}, nil).Once() + s.mockExecutionMgr.On("UpdateWorkflowExecution", mock.Anything, mock.Anything).Return(&persistence.UpdateWorkflowExecutionResponse{MutableStateUpdateSessionStats: &persistence.MutableStateUpdateSessionStats{}}, nil).Once() + + err := s.mockHistoryEngine.RespondActivityTaskFailed(context.Background(), &types.HistoryRespondActivityTaskFailedRequest{ + DomainUUID: constants.TestDomainID, + FailedRequest: &types.RespondActivityTaskFailedRequest{ + TaskToken: taskToken, + Reason: &failReason, + Details: failDetails, + Identity: identity, + }, + }) + s.Nil(err) + executionBuilder := s.getBuilder(constants.TestDomainID, we) + s.Equal(int64(9), executionBuilder.GetExecutionInfo().NextEventID) + s.Equal(int64(3), executionBuilder.GetExecutionInfo().LastProcessedEvent) + s.Equal(persistence.WorkflowStateRunning, executionBuilder.GetExecutionInfo().State) + + s.True(executionBuilder.HasPendingDecision()) + di, ok := executionBuilder.GetDecisionInfo(int64(8)) + s.True(ok) + s.Equal(int32(100), di.DecisionTimeout) + s.Equal(int64(8), di.ScheduleID) + s.Equal(common.EmptyEventID, di.StartedID) +} + +func (s *engineSuite) TestRecordActivityTaskHeartBeatSuccess_NoTimer() { + + we := types.WorkflowExecution{ + WorkflowID: "wId", + RunID: constants.TestRunID, + } + tl := "testTaskList" + taskToken, _ := json.Marshal(&common.TaskToken{ + WorkflowID: we.WorkflowID, + RunID: we.RunID, + ScheduleID: 5, + }) + identity := "testIdentity" + activityID := "activity1_id" + activityType := "activity_type1" + activityInput := []byte("input1") + + msBuilder := execution.NewMutableStateBuilderWithEventV2( + s.mockHistoryEngine.shard, + testlogger.New(s.Suite.T()), + we.GetRunID(), + constants.TestLocalDomainEntry, + ) + test.AddWorkflowExecutionStartedEvent(msBuilder, we, "wType", tl, []byte("input"), 100, 100, identity) + di := test.AddDecisionTaskScheduledEvent(msBuilder) + decisionStartedEvent := test.AddDecisionTaskStartedEvent(msBuilder, di.ScheduleID, tl, identity) + decisionCompletedEvent := test.AddDecisionTaskCompletedEvent(msBuilder, di.ScheduleID, + decisionStartedEvent.ID, nil, identity) + activityScheduledEvent, _ := test.AddActivityTaskScheduledEvent(msBuilder, decisionCompletedEvent.ID, activityID, + activityType, tl, activityInput, 100, 10, 1, 0) + test.AddActivityTaskStartedEvent(msBuilder, activityScheduledEvent.ID, identity) + + // No HeartBeat timer running. + ms := execution.CreatePersistenceMutableState(msBuilder) + gwmsResponse := &persistence.GetWorkflowExecutionResponse{State: ms} + s.mockExecutionMgr.On("GetWorkflowExecution", mock.Anything, mock.Anything).Return(gwmsResponse, nil).Once() + s.mockExecutionMgr.On("UpdateWorkflowExecution", mock.Anything, mock.Anything).Return(&persistence.UpdateWorkflowExecutionResponse{MutableStateUpdateSessionStats: &persistence.MutableStateUpdateSessionStats{}}, nil).Once() + + detais := []byte("details") + + _, err := s.mockHistoryEngine.RecordActivityTaskHeartbeat(context.Background(), &types.HistoryRecordActivityTaskHeartbeatRequest{ + DomainUUID: constants.TestDomainID, + HeartbeatRequest: &types.RecordActivityTaskHeartbeatRequest{ + TaskToken: taskToken, + Identity: identity, + Details: detais, + }, + }) + s.Nil(err) +} + +func (s *engineSuite) TestRecordActivityTaskHeartBeatSuccess_TimerRunning() { + + we := types.WorkflowExecution{ + WorkflowID: "wId", + RunID: constants.TestRunID, + } + tl := "testTaskList" + taskToken, _ := json.Marshal(&common.TaskToken{ + WorkflowID: we.WorkflowID, + RunID: we.RunID, + ScheduleID: 5, + }) + identity := "testIdentity" + activityID := "activity1_id" + activityType := "activity_type1" + activityInput := []byte("input1") + + msBuilder := execution.NewMutableStateBuilderWithEventV2( + s.mockHistoryEngine.shard, + testlogger.New(s.Suite.T()), + we.GetRunID(), + constants.TestLocalDomainEntry, + ) + test.AddWorkflowExecutionStartedEvent(msBuilder, we, "wType", tl, []byte("input"), 100, 100, identity) + di := test.AddDecisionTaskScheduledEvent(msBuilder) + decisionStartedEvent := test.AddDecisionTaskStartedEvent(msBuilder, di.ScheduleID, tl, identity) + decisionCompletedEvent := test.AddDecisionTaskCompletedEvent(msBuilder, di.ScheduleID, + decisionStartedEvent.ID, nil, identity) + activityScheduledEvent, _ := test.AddActivityTaskScheduledEvent(msBuilder, decisionCompletedEvent.ID, activityID, + activityType, tl, activityInput, 100, 10, 1, 1) + test.AddActivityTaskStartedEvent(msBuilder, activityScheduledEvent.ID, identity) + + ms := execution.CreatePersistenceMutableState(msBuilder) + gwmsResponse := &persistence.GetWorkflowExecutionResponse{State: ms} + + // HeartBeat timer running. + s.mockExecutionMgr.On("GetWorkflowExecution", mock.Anything, mock.Anything).Return(gwmsResponse, nil).Once() + s.mockExecutionMgr.On("UpdateWorkflowExecution", mock.Anything, mock.Anything).Return(&persistence.UpdateWorkflowExecutionResponse{MutableStateUpdateSessionStats: &persistence.MutableStateUpdateSessionStats{}}, nil).Once() + + detais := []byte("details") + + _, err := s.mockHistoryEngine.RecordActivityTaskHeartbeat(context.Background(), &types.HistoryRecordActivityTaskHeartbeatRequest{ + DomainUUID: constants.TestDomainID, + HeartbeatRequest: &types.RecordActivityTaskHeartbeatRequest{ + TaskToken: taskToken, + Identity: identity, + Details: detais, + }, + }) + s.Nil(err) + executionBuilder := s.getBuilder(constants.TestDomainID, we) + s.Equal(int64(7), executionBuilder.GetExecutionInfo().NextEventID) + s.Equal(int64(3), executionBuilder.GetExecutionInfo().LastProcessedEvent) + s.Equal(persistence.WorkflowStateRunning, executionBuilder.GetExecutionInfo().State) + s.False(executionBuilder.HasPendingDecision()) +} + +func (s *engineSuite) TestRecordActivityTaskHeartBeatByIDSuccess() { + + we := types.WorkflowExecution{ + WorkflowID: "wId", + RunID: constants.TestRunID, + } + tl := "testTaskList" + identity := "testIdentity" + activityID := "activity1_id" + activityType := "activity_type1" + activityInput := []byte("input1") + taskToken, _ := json.Marshal(&common.TaskToken{ + WorkflowID: we.WorkflowID, + RunID: we.RunID, + ScheduleID: common.EmptyEventID, + ActivityID: activityID, + }) + + msBuilder := execution.NewMutableStateBuilderWithEventV2( + s.mockHistoryEngine.shard, + testlogger.New(s.Suite.T()), + we.GetRunID(), + constants.TestLocalDomainEntry, + ) + test.AddWorkflowExecutionStartedEvent(msBuilder, we, "wType", tl, []byte("input"), 100, 100, identity) + di := test.AddDecisionTaskScheduledEvent(msBuilder) + decisionStartedEvent := test.AddDecisionTaskStartedEvent(msBuilder, di.ScheduleID, tl, identity) + decisionCompletedEvent := test.AddDecisionTaskCompletedEvent(msBuilder, di.ScheduleID, + decisionStartedEvent.ID, nil, identity) + activityScheduledEvent, _ := test.AddActivityTaskScheduledEvent(msBuilder, decisionCompletedEvent.ID, activityID, + activityType, tl, activityInput, 100, 10, 1, 0) + test.AddActivityTaskStartedEvent(msBuilder, activityScheduledEvent.ID, identity) + + // No HeartBeat timer running. + ms := execution.CreatePersistenceMutableState(msBuilder) + gwmsResponse := &persistence.GetWorkflowExecutionResponse{State: ms} + s.mockExecutionMgr.On("GetWorkflowExecution", mock.Anything, mock.Anything).Return(gwmsResponse, nil).Once() + s.mockExecutionMgr.On("UpdateWorkflowExecution", mock.Anything, mock.Anything).Return(&persistence.UpdateWorkflowExecutionResponse{MutableStateUpdateSessionStats: &persistence.MutableStateUpdateSessionStats{}}, nil).Once() + + detais := []byte("details") + + _, err := s.mockHistoryEngine.RecordActivityTaskHeartbeat(context.Background(), &types.HistoryRecordActivityTaskHeartbeatRequest{ + DomainUUID: constants.TestDomainID, + HeartbeatRequest: &types.RecordActivityTaskHeartbeatRequest{ + TaskToken: taskToken, + Identity: identity, + Details: detais, + }, + }) + s.Nil(err) +} + +func (s *engineSuite) TestRespondActivityTaskCanceled_Scheduled() { + + we := types.WorkflowExecution{ + WorkflowID: "wId", + RunID: constants.TestRunID, + } + tl := "testTaskList" + taskToken, _ := json.Marshal(&common.TaskToken{ + WorkflowID: we.WorkflowID, + RunID: we.RunID, + ScheduleID: 5, + }) + identity := "testIdentity" + activityID := "activity1_id" + activityType := "activity_type1" + activityInput := []byte("input1") + + msBuilder := execution.NewMutableStateBuilderWithEventV2( + s.mockHistoryEngine.shard, + testlogger.New(s.Suite.T()), + we.GetRunID(), + constants.TestLocalDomainEntry, + ) + test.AddWorkflowExecutionStartedEvent(msBuilder, we, "wType", tl, []byte("input"), 100, 100, identity) + di := test.AddDecisionTaskScheduledEvent(msBuilder) + decisionStartedEvent := test.AddDecisionTaskStartedEvent(msBuilder, di.ScheduleID, tl, identity) + decisionCompletedEvent := test.AddDecisionTaskCompletedEvent(msBuilder, di.ScheduleID, + decisionStartedEvent.ID, nil, identity) + test.AddActivityTaskScheduledEvent(msBuilder, decisionCompletedEvent.ID, activityID, + activityType, tl, activityInput, 100, 10, 1, 1) + + ms := execution.CreatePersistenceMutableState(msBuilder) + gwmsResponse := &persistence.GetWorkflowExecutionResponse{State: ms} + + s.mockExecutionMgr.On("GetWorkflowExecution", mock.Anything, mock.Anything).Return(gwmsResponse, nil).Once() + + err := s.mockHistoryEngine.RespondActivityTaskCanceled(context.Background(), &types.HistoryRespondActivityTaskCanceledRequest{ + DomainUUID: constants.TestDomainID, + CancelRequest: &types.RespondActivityTaskCanceledRequest{ + TaskToken: taskToken, + Identity: identity, + Details: []byte("details"), + }, + }) + s.NotNil(err) + s.IsType(&types.EntityNotExistsError{}, err) +} + +func (s *engineSuite) TestRespondActivityTaskCanceled_Started() { + + we := types.WorkflowExecution{ + WorkflowID: "wId", + RunID: constants.TestRunID, + } + tl := "testTaskList" + taskToken, _ := json.Marshal(&common.TaskToken{ + WorkflowID: we.WorkflowID, + RunID: we.RunID, + ScheduleID: 5, + }) + identity := "testIdentity" + activityID := "activity1_id" + activityType := "activity_type1" + activityInput := []byte("input1") + + msBuilder := execution.NewMutableStateBuilderWithEventV2( + s.mockHistoryEngine.shard, + testlogger.New(s.Suite.T()), + we.GetRunID(), + constants.TestLocalDomainEntry, + ) + test.AddWorkflowExecutionStartedEvent(msBuilder, we, "wType", tl, []byte("input"), 100, 100, identity) + di := test.AddDecisionTaskScheduledEvent(msBuilder) + decisionStartedEvent := test.AddDecisionTaskStartedEvent(msBuilder, di.ScheduleID, tl, identity) + decisionCompletedEvent := test.AddDecisionTaskCompletedEvent(msBuilder, di.ScheduleID, + decisionStartedEvent.ID, nil, identity) + activityScheduledEvent, _ := test.AddActivityTaskScheduledEvent(msBuilder, decisionCompletedEvent.ID, activityID, + activityType, tl, activityInput, 100, 10, 1, 1) + test.AddActivityTaskStartedEvent(msBuilder, activityScheduledEvent.ID, identity) + _, _, err := msBuilder.AddActivityTaskCancelRequestedEvent(decisionCompletedEvent.ID, activityID, identity) + s.Nil(err) + + ms := execution.CreatePersistenceMutableState(msBuilder) + gwmsResponse := &persistence.GetWorkflowExecutionResponse{State: ms} + + s.mockExecutionMgr.On("GetWorkflowExecution", mock.Anything, mock.Anything).Return(gwmsResponse, nil).Once() + s.mockHistoryV2Mgr.On("AppendHistoryNodes", mock.Anything, mock.Anything).Return(&persistence.AppendHistoryNodesResponse{}, nil).Once() + s.mockExecutionMgr.On("UpdateWorkflowExecution", mock.Anything, mock.Anything).Return(&persistence.UpdateWorkflowExecutionResponse{MutableStateUpdateSessionStats: &persistence.MutableStateUpdateSessionStats{}}, nil).Once() + + err = s.mockHistoryEngine.RespondActivityTaskCanceled(context.Background(), &types.HistoryRespondActivityTaskCanceledRequest{ + DomainUUID: constants.TestDomainID, + CancelRequest: &types.RespondActivityTaskCanceledRequest{ + TaskToken: taskToken, + Identity: identity, + Details: []byte("details"), + }, + }) + s.Nil(err) + executionBuilder := s.getBuilder(constants.TestDomainID, we) + s.Equal(int64(10), executionBuilder.GetExecutionInfo().NextEventID) + s.Equal(int64(3), executionBuilder.GetExecutionInfo().LastProcessedEvent) + s.Equal(persistence.WorkflowStateRunning, executionBuilder.GetExecutionInfo().State) + + s.True(executionBuilder.HasPendingDecision()) + di, ok := executionBuilder.GetDecisionInfo(int64(9)) + s.True(ok) + s.Equal(int32(100), di.DecisionTimeout) + s.Equal(int64(9), di.ScheduleID) + s.Equal(common.EmptyEventID, di.StartedID) +} + +func (s *engineSuite) TestRespondActivityTaskCanceledByID_Started() { + + we := types.WorkflowExecution{ + WorkflowID: "wId", + RunID: constants.TestRunID, + } + tl := "testTaskList" + identity := "testIdentity" + activityID := "activity1_id" + activityType := "activity_type1" + activityInput := []byte("input1") + taskToken, _ := json.Marshal(&common.TaskToken{ + WorkflowID: we.WorkflowID, + ScheduleID: common.EmptyEventID, + ActivityID: activityID, + }) + + msBuilder := execution.NewMutableStateBuilderWithEventV2( + s.mockHistoryEngine.shard, + testlogger.New(s.Suite.T()), + we.GetRunID(), + constants.TestLocalDomainEntry, + ) + test.AddWorkflowExecutionStartedEvent(msBuilder, we, "wType", tl, []byte("input"), 100, 100, identity) + decisionScheduledEvent := test.AddDecisionTaskScheduledEvent(msBuilder) + decisionStartedEvent := test.AddDecisionTaskStartedEvent(msBuilder, decisionScheduledEvent.ScheduleID, tl, identity) + decisionCompletedEvent := test.AddDecisionTaskCompletedEvent(msBuilder, decisionScheduledEvent.ScheduleID, + decisionStartedEvent.ID, nil, identity) + activityScheduledEvent, _ := test.AddActivityTaskScheduledEvent(msBuilder, decisionCompletedEvent.ID, activityID, + activityType, tl, activityInput, 100, 10, 1, 1) + test.AddActivityTaskStartedEvent(msBuilder, activityScheduledEvent.ID, identity) + _, _, err := msBuilder.AddActivityTaskCancelRequestedEvent(decisionCompletedEvent.ID, activityID, identity) + s.Nil(err) + + ms := execution.CreatePersistenceMutableState(msBuilder) + gwmsResponse := &persistence.GetWorkflowExecutionResponse{State: ms} + gceResponse := &persistence.GetCurrentExecutionResponse{RunID: we.RunID} + + s.mockExecutionMgr.On("GetCurrentExecution", mock.Anything, mock.Anything).Return(gceResponse, nil).Once() + s.mockExecutionMgr.On("GetWorkflowExecution", mock.Anything, mock.Anything).Return(gwmsResponse, nil).Once() + s.mockHistoryV2Mgr.On("AppendHistoryNodes", mock.Anything, mock.Anything).Return(&persistence.AppendHistoryNodesResponse{}, nil).Once() + s.mockExecutionMgr.On("UpdateWorkflowExecution", mock.Anything, mock.Anything).Return(&persistence.UpdateWorkflowExecutionResponse{MutableStateUpdateSessionStats: &persistence.MutableStateUpdateSessionStats{}}, nil).Once() + + err = s.mockHistoryEngine.RespondActivityTaskCanceled(context.Background(), &types.HistoryRespondActivityTaskCanceledRequest{ + DomainUUID: constants.TestDomainID, + CancelRequest: &types.RespondActivityTaskCanceledRequest{ + TaskToken: taskToken, + Identity: identity, + Details: []byte("details"), + }, + }) + s.Nil(err) + executionBuilder := s.getBuilder(constants.TestDomainID, we) + s.Equal(int64(10), executionBuilder.GetExecutionInfo().NextEventID) + s.Equal(int64(3), executionBuilder.GetExecutionInfo().LastProcessedEvent) + s.Equal(persistence.WorkflowStateRunning, executionBuilder.GetExecutionInfo().State) + + s.True(executionBuilder.HasPendingDecision()) + di, ok := executionBuilder.GetDecisionInfo(int64(9)) + s.True(ok) + s.Equal(int32(100), di.DecisionTimeout) + s.Equal(int64(9), di.ScheduleID) + s.Equal(common.EmptyEventID, di.StartedID) +} + +func (s *engineSuite) TestRespondActivityTaskCanceledIfNoRunID() { + + taskToken, _ := json.Marshal(&common.TaskToken{ + WorkflowID: "wId", + ScheduleID: 2, + }) + identity := "testIdentity" + + s.mockExecutionMgr.On("GetCurrentExecution", mock.Anything, mock.Anything).Return(nil, &types.EntityNotExistsError{}).Once() + + err := s.mockHistoryEngine.RespondActivityTaskCanceled(context.Background(), &types.HistoryRespondActivityTaskCanceledRequest{ + DomainUUID: constants.TestDomainID, + CancelRequest: &types.RespondActivityTaskCanceledRequest{ + TaskToken: taskToken, + Identity: identity, + }, + }) + s.NotNil(err) + s.IsType(&types.EntityNotExistsError{}, err) +} + +func (s *engineSuite) TestRespondActivityTaskCanceledIfNoAIdProvided() { + + taskToken, _ := json.Marshal(&common.TaskToken{ + WorkflowID: "wId", + ScheduleID: common.EmptyEventID, + }) + identity := "testIdentity" + + msBuilder := execution.NewMutableStateBuilderWithEventV2( + s.mockHistoryEngine.shard, + testlogger.New(s.Suite.T()), + constants.TestRunID, + constants.TestLocalDomainEntry, + ) + ms := execution.CreatePersistenceMutableState(msBuilder) + gwmsResponse := &persistence.GetWorkflowExecutionResponse{State: ms} + gceResponse := &persistence.GetCurrentExecutionResponse{RunID: constants.TestRunID} + + s.mockExecutionMgr.On("GetCurrentExecution", mock.Anything, mock.Anything).Return(gceResponse, nil).Once() + s.mockExecutionMgr.On("GetWorkflowExecution", mock.Anything, mock.Anything).Return(gwmsResponse, nil).Once() + + err := s.mockHistoryEngine.RespondActivityTaskCanceled(context.Background(), &types.HistoryRespondActivityTaskCanceledRequest{ + DomainUUID: constants.TestDomainID, + CancelRequest: &types.RespondActivityTaskCanceledRequest{ + TaskToken: taskToken, + Identity: identity, + }, + }) + s.EqualError(err, "Neither ActivityID nor ScheduleID is provided") +} + +func (s *engineSuite) TestRespondActivityTaskCanceledIfNotFound() { + + taskToken, _ := json.Marshal(&common.TaskToken{ + WorkflowID: "wId", + ScheduleID: common.EmptyEventID, + ActivityID: "aid", + }) + identity := "testIdentity" + + msBuilder := execution.NewMutableStateBuilderWithEventV2( + s.mockHistoryEngine.shard, + testlogger.New(s.Suite.T()), + constants.TestRunID, + constants.TestLocalDomainEntry, + ) + ms := execution.CreatePersistenceMutableState(msBuilder) + gwmsResponse := &persistence.GetWorkflowExecutionResponse{State: ms} + gceResponse := &persistence.GetCurrentExecutionResponse{RunID: constants.TestRunID} + + s.mockExecutionMgr.On("GetCurrentExecution", mock.Anything, mock.Anything).Return(gceResponse, nil).Once() + s.mockExecutionMgr.On("GetWorkflowExecution", mock.Anything, mock.Anything).Return(gwmsResponse, nil).Once() + + err := s.mockHistoryEngine.RespondActivityTaskCanceled(context.Background(), &types.HistoryRespondActivityTaskCanceledRequest{ + DomainUUID: constants.TestDomainID, + CancelRequest: &types.RespondActivityTaskCanceledRequest{ + TaskToken: taskToken, + Identity: identity, + }, + }) + s.Error(err) +} + +func (s *engineSuite) TestRequestCancel_RespondDecisionTaskCompleted_NotScheduled() { + + we := types.WorkflowExecution{ + WorkflowID: "wId", + RunID: constants.TestRunID, + } + tl := "testTaskList" + taskToken, _ := json.Marshal(&common.TaskToken{ + WorkflowID: we.WorkflowID, + RunID: we.RunID, + ScheduleID: 2, + }) + identity := "testIdentity" + activityID := "activity1_id" + + msBuilder := execution.NewMutableStateBuilderWithEventV2( + s.mockHistoryEngine.shard, + testlogger.New(s.Suite.T()), + we.GetRunID(), + constants.TestLocalDomainEntry, + ) + test.AddWorkflowExecutionStartedEvent(msBuilder, we, "wType", tl, []byte("input"), 100, 100, identity) + di := test.AddDecisionTaskScheduledEvent(msBuilder) + test.AddDecisionTaskStartedEvent(msBuilder, di.ScheduleID, tl, identity) + + decisions := []*types.Decision{{ + DecisionType: types.DecisionTypeRequestCancelActivityTask.Ptr(), + RequestCancelActivityTaskDecisionAttributes: &types.RequestCancelActivityTaskDecisionAttributes{ + ActivityID: activityID, + }, + }} + + ms := execution.CreatePersistenceMutableState(msBuilder) + gwmsResponse := &persistence.GetWorkflowExecutionResponse{State: ms} + + s.mockExecutionMgr.On("GetWorkflowExecution", mock.Anything, mock.Anything).Return(gwmsResponse, nil).Once() + s.mockHistoryV2Mgr.On("AppendHistoryNodes", mock.Anything, mock.Anything).Return(&persistence.AppendHistoryNodesResponse{}, nil).Once() + s.mockExecutionMgr.On("UpdateWorkflowExecution", mock.Anything, mock.Anything).Return(&persistence.UpdateWorkflowExecutionResponse{MutableStateUpdateSessionStats: &persistence.MutableStateUpdateSessionStats{}}, nil).Once() + + _, err := s.mockHistoryEngine.RespondDecisionTaskCompleted(context.Background(), &types.HistoryRespondDecisionTaskCompletedRequest{ + DomainUUID: constants.TestDomainID, + CompleteRequest: &types.RespondDecisionTaskCompletedRequest{ + TaskToken: taskToken, + Decisions: decisions, + ExecutionContext: []byte("context"), + Identity: identity, + }, + }) + s.Nil(err) + executionBuilder := s.getBuilder(constants.TestDomainID, we) + s.Equal(int64(7), executionBuilder.GetExecutionInfo().NextEventID) + s.Equal(int64(3), executionBuilder.GetExecutionInfo().LastProcessedEvent) + s.Equal(persistence.WorkflowStateRunning, executionBuilder.GetExecutionInfo().State) + s.False(executionBuilder.HasPendingDecision()) +} + +func (s *engineSuite) TestRequestCancel_RespondDecisionTaskCompleted_Scheduled() { + + we := types.WorkflowExecution{ + WorkflowID: "wId", + RunID: constants.TestRunID, + } + tl := "testTaskList" + taskToken, _ := json.Marshal(&common.TaskToken{ + WorkflowID: we.WorkflowID, + RunID: we.RunID, + ScheduleID: 6, + }) + identity := "testIdentity" + activityID := "activity1_id" + activityType := "activity_type1" + activityInput := []byte("input1") + + msBuilder := execution.NewMutableStateBuilderWithEventV2( + s.mockHistoryEngine.shard, + testlogger.New(s.Suite.T()), + we.GetRunID(), + constants.TestLocalDomainEntry, + ) + test.AddWorkflowExecutionStartedEvent(msBuilder, we, "wType", tl, []byte("input"), 100, 100, identity) + di := test.AddDecisionTaskScheduledEvent(msBuilder) + decisionStartedEvent := test.AddDecisionTaskStartedEvent(msBuilder, di.ScheduleID, tl, identity) + decisionCompletedEvent := test.AddDecisionTaskCompletedEvent(msBuilder, di.ScheduleID, + decisionStartedEvent.ID, nil, identity) + test.AddActivityTaskScheduledEvent(msBuilder, decisionCompletedEvent.ID, activityID, + activityType, tl, activityInput, 100, 10, 1, 1) + di2 := test.AddDecisionTaskScheduledEvent(msBuilder) + test.AddDecisionTaskStartedEvent(msBuilder, di2.ScheduleID, tl, identity) + + ms := execution.CreatePersistenceMutableState(msBuilder) + gwmsResponse := &persistence.GetWorkflowExecutionResponse{State: ms} + + decisions := []*types.Decision{{ + DecisionType: types.DecisionTypeRequestCancelActivityTask.Ptr(), + RequestCancelActivityTaskDecisionAttributes: &types.RequestCancelActivityTaskDecisionAttributes{ + ActivityID: activityID, + }, + }} + + s.mockExecutionMgr.On("GetWorkflowExecution", mock.Anything, mock.Anything).Return(gwmsResponse, nil).Once() + s.mockHistoryV2Mgr.On("AppendHistoryNodes", mock.Anything, mock.Anything).Return(&persistence.AppendHistoryNodesResponse{}, nil).Once() + s.mockExecutionMgr.On("UpdateWorkflowExecution", mock.Anything, mock.Anything).Return(&persistence.UpdateWorkflowExecutionResponse{MutableStateUpdateSessionStats: &persistence.MutableStateUpdateSessionStats{}}, nil).Once() + + _, err := s.mockHistoryEngine.RespondDecisionTaskCompleted(context.Background(), &types.HistoryRespondDecisionTaskCompletedRequest{ + DomainUUID: constants.TestDomainID, + CompleteRequest: &types.RespondDecisionTaskCompletedRequest{ + TaskToken: taskToken, + Decisions: decisions, + ExecutionContext: []byte("context"), + Identity: identity, + }, + }) + s.Nil(err) + + executionBuilder := s.getBuilder(constants.TestDomainID, we) + s.Equal(int64(12), executionBuilder.GetExecutionInfo().NextEventID) + s.Equal(int64(7), executionBuilder.GetExecutionInfo().LastProcessedEvent) + s.Equal(persistence.WorkflowStateRunning, executionBuilder.GetExecutionInfo().State) + s.True(executionBuilder.HasPendingDecision()) + di2, ok := executionBuilder.GetDecisionInfo(executionBuilder.GetExecutionInfo().NextEventID - 1) + s.True(ok) + s.Equal(executionBuilder.GetExecutionInfo().NextEventID-1, di2.ScheduleID) + s.Equal(int64(0), di2.Attempt) +} + +func (s *engineSuite) TestRequestCancel_RespondDecisionTaskCompleted_Started() { + + we := types.WorkflowExecution{ + WorkflowID: "wId", + RunID: constants.TestRunID, + } + tl := "testTaskList" + taskToken, _ := json.Marshal(&common.TaskToken{ + WorkflowID: we.WorkflowID, + RunID: we.RunID, + ScheduleID: 7, + }) + identity := "testIdentity" + activityID := "activity1_id" + activityType := "activity_type1" + activityInput := []byte("input1") + + msBuilder := execution.NewMutableStateBuilderWithEventV2( + s.mockHistoryEngine.shard, + testlogger.New(s.Suite.T()), + we.GetRunID(), + constants.TestLocalDomainEntry, + ) + test.AddWorkflowExecutionStartedEvent(msBuilder, we, "wType", tl, []byte("input"), 100, 100, identity) + di := test.AddDecisionTaskScheduledEvent(msBuilder) + decisionStartedEvent := test.AddDecisionTaskStartedEvent(msBuilder, di.ScheduleID, tl, identity) + decisionCompletedEvent := test.AddDecisionTaskCompletedEvent(msBuilder, di.ScheduleID, + decisionStartedEvent.ID, nil, identity) + activityScheduledEvent, _ := test.AddActivityTaskScheduledEvent(msBuilder, decisionCompletedEvent.ID, activityID, + activityType, tl, activityInput, 100, 10, 1, 0) + test.AddActivityTaskStartedEvent(msBuilder, activityScheduledEvent.ID, identity) + di2 := test.AddDecisionTaskScheduledEvent(msBuilder) + test.AddDecisionTaskStartedEvent(msBuilder, di2.ScheduleID, tl, identity) + + ms := execution.CreatePersistenceMutableState(msBuilder) + gwmsResponse := &persistence.GetWorkflowExecutionResponse{State: ms} + + decisions := []*types.Decision{{ + DecisionType: types.DecisionTypeRequestCancelActivityTask.Ptr(), + RequestCancelActivityTaskDecisionAttributes: &types.RequestCancelActivityTaskDecisionAttributes{ + ActivityID: activityID, + }, + }} + + s.mockExecutionMgr.On("GetWorkflowExecution", mock.Anything, mock.Anything).Return(gwmsResponse, nil).Once() + s.mockHistoryV2Mgr.On("AppendHistoryNodes", mock.Anything, mock.Anything).Return(&persistence.AppendHistoryNodesResponse{}, nil).Once() + s.mockExecutionMgr.On("UpdateWorkflowExecution", mock.Anything, mock.Anything).Return(&persistence.UpdateWorkflowExecutionResponse{MutableStateUpdateSessionStats: &persistence.MutableStateUpdateSessionStats{}}, nil).Once() + + _, err := s.mockHistoryEngine.RespondDecisionTaskCompleted(context.Background(), &types.HistoryRespondDecisionTaskCompletedRequest{ + DomainUUID: constants.TestDomainID, + CompleteRequest: &types.RespondDecisionTaskCompletedRequest{ + TaskToken: taskToken, + Decisions: decisions, + ExecutionContext: []byte("context"), + Identity: identity, + }, + }) + s.Nil(err) + + executionBuilder := s.getBuilder(constants.TestDomainID, we) + s.Equal(int64(11), executionBuilder.GetExecutionInfo().NextEventID) + s.Equal(int64(8), executionBuilder.GetExecutionInfo().LastProcessedEvent) + s.Equal(persistence.WorkflowStateRunning, executionBuilder.GetExecutionInfo().State) + s.False(executionBuilder.HasPendingDecision()) +} + +func (s *engineSuite) TestRequestCancel_RespondDecisionTaskCompleted_Completed() { + + we := types.WorkflowExecution{ + WorkflowID: "wId", + RunID: constants.TestRunID, + } + tl := "testTaskList" + taskToken, _ := json.Marshal(&common.TaskToken{ + WorkflowID: we.WorkflowID, + RunID: we.RunID, + ScheduleID: 6, + }) + identity := "testIdentity" + activityID := "activity1_id" + activityType := "activity_type1" + activityInput := []byte("input1") + workflowResult := []byte("workflow result") + + msBuilder := execution.NewMutableStateBuilderWithEventV2( + s.mockHistoryEngine.shard, + testlogger.New(s.Suite.T()), + we.GetRunID(), + constants.TestLocalDomainEntry, + ) + test.AddWorkflowExecutionStartedEvent(msBuilder, we, "wType", tl, []byte("input"), 100, 100, identity) + di := test.AddDecisionTaskScheduledEvent(msBuilder) + decisionStartedEvent := test.AddDecisionTaskStartedEvent(msBuilder, di.ScheduleID, tl, identity) + decisionCompletedEvent := test.AddDecisionTaskCompletedEvent(msBuilder, di.ScheduleID, + decisionStartedEvent.ID, nil, identity) + test.AddActivityTaskScheduledEvent(msBuilder, decisionCompletedEvent.ID, activityID, + activityType, tl, activityInput, 100, 10, 1, 0) + di2 := test.AddDecisionTaskScheduledEvent(msBuilder) + test.AddDecisionTaskStartedEvent(msBuilder, di2.ScheduleID, tl, identity) + + decisions := []*types.Decision{ + { + DecisionType: types.DecisionTypeRequestCancelActivityTask.Ptr(), + RequestCancelActivityTaskDecisionAttributes: &types.RequestCancelActivityTaskDecisionAttributes{ + ActivityID: activityID, + }, + }, + { + DecisionType: types.DecisionTypeCompleteWorkflowExecution.Ptr(), + CompleteWorkflowExecutionDecisionAttributes: &types.CompleteWorkflowExecutionDecisionAttributes{ + Result: workflowResult, + }, + }, + } + + ms := execution.CreatePersistenceMutableState(msBuilder) + gwmsResponse := &persistence.GetWorkflowExecutionResponse{State: ms} + s.mockExecutionMgr.On("GetWorkflowExecution", mock.Anything, mock.Anything).Return(gwmsResponse, nil).Once() + s.mockHistoryV2Mgr.On("AppendHistoryNodes", mock.Anything, mock.Anything).Return(&persistence.AppendHistoryNodesResponse{}, nil).Once() + s.mockExecutionMgr.On("UpdateWorkflowExecution", mock.Anything, mock.Anything).Return(&persistence.UpdateWorkflowExecutionResponse{MutableStateUpdateSessionStats: &persistence.MutableStateUpdateSessionStats{}}, nil).Once() + + _, err := s.mockHistoryEngine.RespondDecisionTaskCompleted(context.Background(), &types.HistoryRespondDecisionTaskCompletedRequest{ + DomainUUID: constants.TestDomainID, + CompleteRequest: &types.RespondDecisionTaskCompletedRequest{ + TaskToken: taskToken, + Decisions: decisions, + ExecutionContext: []byte("context"), + Identity: identity, + }, + }) + s.Nil(err) + + executionBuilder := s.getBuilder(constants.TestDomainID, we) + s.Equal(int64(11), executionBuilder.GetExecutionInfo().NextEventID) + s.Equal(int64(7), executionBuilder.GetExecutionInfo().LastProcessedEvent) + s.Equal(persistence.WorkflowStateCompleted, executionBuilder.GetExecutionInfo().State) + s.False(executionBuilder.HasPendingDecision()) +} + +func (s *engineSuite) TestRequestCancel_RespondDecisionTaskCompleted_NoHeartBeat() { + + we := types.WorkflowExecution{ + WorkflowID: "wId", + RunID: constants.TestRunID, + } + tl := "testTaskList" + taskToken, _ := json.Marshal(&common.TaskToken{ + WorkflowID: we.WorkflowID, + RunID: we.RunID, + ScheduleID: 7, + }) + identity := "testIdentity" + activityID := "activity1_id" + activityType := "activity_type1" + activityInput := []byte("input1") + + msBuilder := execution.NewMutableStateBuilderWithEventV2( + s.mockHistoryEngine.shard, + testlogger.New(s.Suite.T()), + we.GetRunID(), + constants.TestLocalDomainEntry, + ) + test.AddWorkflowExecutionStartedEvent(msBuilder, we, "wType", tl, []byte("input"), 100, 100, identity) + di := test.AddDecisionTaskScheduledEvent(msBuilder) + decisionStartedEvent := test.AddDecisionTaskStartedEvent(msBuilder, di.ScheduleID, tl, identity) + decisionCompletedEvent := test.AddDecisionTaskCompletedEvent(msBuilder, di.ScheduleID, + decisionStartedEvent.ID, nil, identity) + activityScheduledEvent, _ := test.AddActivityTaskScheduledEvent(msBuilder, decisionCompletedEvent.ID, activityID, + activityType, tl, activityInput, 100, 10, 1, 0) + test.AddActivityTaskStartedEvent(msBuilder, activityScheduledEvent.ID, identity) + di2 := test.AddDecisionTaskScheduledEvent(msBuilder) + test.AddDecisionTaskStartedEvent(msBuilder, di2.ScheduleID, tl, identity) + + ms := execution.CreatePersistenceMutableState(msBuilder) + gwmsResponse := &persistence.GetWorkflowExecutionResponse{State: ms} + + decisions := []*types.Decision{{ + DecisionType: types.DecisionTypeRequestCancelActivityTask.Ptr(), + RequestCancelActivityTaskDecisionAttributes: &types.RequestCancelActivityTaskDecisionAttributes{ + ActivityID: activityID, + }, + }} + + s.mockExecutionMgr.On("GetWorkflowExecution", mock.Anything, mock.Anything).Return(gwmsResponse, nil).Once() + s.mockHistoryV2Mgr.On("AppendHistoryNodes", mock.Anything, mock.Anything).Return(&persistence.AppendHistoryNodesResponse{}, nil).Once() + s.mockExecutionMgr.On("UpdateWorkflowExecution", mock.Anything, mock.Anything).Return(&persistence.UpdateWorkflowExecutionResponse{MutableStateUpdateSessionStats: &persistence.MutableStateUpdateSessionStats{}}, nil).Once() + + _, err := s.mockHistoryEngine.RespondDecisionTaskCompleted(context.Background(), &types.HistoryRespondDecisionTaskCompletedRequest{ + DomainUUID: constants.TestDomainID, + CompleteRequest: &types.RespondDecisionTaskCompletedRequest{ + TaskToken: taskToken, + Decisions: decisions, + ExecutionContext: []byte("context"), + Identity: identity, + }, + }) + s.Nil(err) + + executionBuilder := s.getBuilder(constants.TestDomainID, we) + s.Equal(int64(11), executionBuilder.GetExecutionInfo().NextEventID) + s.Equal(int64(8), executionBuilder.GetExecutionInfo().LastProcessedEvent) + s.Equal(persistence.WorkflowStateRunning, executionBuilder.GetExecutionInfo().State) + s.False(executionBuilder.HasPendingDecision()) + + // Try recording activity heartbeat + s.mockExecutionMgr.On("UpdateWorkflowExecution", mock.Anything, mock.Anything).Return(&persistence.UpdateWorkflowExecutionResponse{MutableStateUpdateSessionStats: &persistence.MutableStateUpdateSessionStats{}}, nil).Once() + + activityTaskToken, _ := json.Marshal(&common.TaskToken{ + WorkflowID: "wId", + RunID: we.GetRunID(), + ScheduleID: 5, + }) + + hbResponse, err := s.mockHistoryEngine.RecordActivityTaskHeartbeat(context.Background(), &types.HistoryRecordActivityTaskHeartbeatRequest{ + DomainUUID: constants.TestDomainID, + HeartbeatRequest: &types.RecordActivityTaskHeartbeatRequest{ + TaskToken: activityTaskToken, + Identity: identity, + Details: []byte("details"), + }, + }) + s.Nil(err) + s.NotNil(hbResponse) + s.True(hbResponse.CancelRequested) + + // Try cancelling the request. + s.mockHistoryV2Mgr.On("AppendHistoryNodes", mock.Anything, mock.Anything).Return(&persistence.AppendHistoryNodesResponse{}, nil).Once() + s.mockExecutionMgr.On("UpdateWorkflowExecution", mock.Anything, mock.Anything).Return(&persistence.UpdateWorkflowExecutionResponse{MutableStateUpdateSessionStats: &persistence.MutableStateUpdateSessionStats{}}, nil).Once() + + err = s.mockHistoryEngine.RespondActivityTaskCanceled(context.Background(), &types.HistoryRespondActivityTaskCanceledRequest{ + DomainUUID: constants.TestDomainID, + CancelRequest: &types.RespondActivityTaskCanceledRequest{ + TaskToken: activityTaskToken, + Identity: identity, + Details: []byte("details"), + }, + }) + s.Nil(err) + + executionBuilder = s.getBuilder(constants.TestDomainID, we) + s.Equal(int64(13), executionBuilder.GetExecutionInfo().NextEventID) + s.Equal(int64(8), executionBuilder.GetExecutionInfo().LastProcessedEvent) + s.Equal(persistence.WorkflowStateRunning, executionBuilder.GetExecutionInfo().State) + s.True(executionBuilder.HasPendingDecision()) +} + +func (s *engineSuite) TestRequestCancel_RespondDecisionTaskCompleted_Success() { + + we := types.WorkflowExecution{ + WorkflowID: "wId", + RunID: constants.TestRunID, + } + tl := "testTaskList" + taskToken, _ := json.Marshal(&common.TaskToken{ + WorkflowID: we.WorkflowID, + RunID: we.RunID, + ScheduleID: 7, + }) + identity := "testIdentity" + activityID := "activity1_id" + activityType := "activity_type1" + activityInput := []byte("input1") + + msBuilder := execution.NewMutableStateBuilderWithEventV2( + s.mockHistoryEngine.shard, + testlogger.New(s.Suite.T()), + we.GetRunID(), + constants.TestLocalDomainEntry, + ) + test.AddWorkflowExecutionStartedEvent(msBuilder, we, "wType", tl, []byte("input"), 100, 100, identity) + di := test.AddDecisionTaskScheduledEvent(msBuilder) + decisionStartedEvent := test.AddDecisionTaskStartedEvent(msBuilder, di.ScheduleID, tl, identity) + decisionCompletedEvent := test.AddDecisionTaskCompletedEvent(msBuilder, di.ScheduleID, + decisionStartedEvent.ID, nil, identity) + activityScheduledEvent, _ := test.AddActivityTaskScheduledEvent(msBuilder, decisionCompletedEvent.ID, activityID, + activityType, tl, activityInput, 100, 10, 1, 1) + test.AddActivityTaskStartedEvent(msBuilder, activityScheduledEvent.ID, identity) + di2 := test.AddDecisionTaskScheduledEvent(msBuilder) + test.AddDecisionTaskStartedEvent(msBuilder, di2.ScheduleID, tl, identity) + + ms := execution.CreatePersistenceMutableState(msBuilder) + gwmsResponse := &persistence.GetWorkflowExecutionResponse{State: ms} + + decisions := []*types.Decision{{ + DecisionType: types.DecisionTypeRequestCancelActivityTask.Ptr(), + RequestCancelActivityTaskDecisionAttributes: &types.RequestCancelActivityTaskDecisionAttributes{ + ActivityID: activityID, + }, + }} + + s.mockExecutionMgr.On("GetWorkflowExecution", mock.Anything, mock.Anything).Return(gwmsResponse, nil).Once() + s.mockHistoryV2Mgr.On("AppendHistoryNodes", mock.Anything, mock.Anything).Return(&persistence.AppendHistoryNodesResponse{}, nil).Once() + s.mockExecutionMgr.On("UpdateWorkflowExecution", mock.Anything, mock.Anything).Return(&persistence.UpdateWorkflowExecutionResponse{MutableStateUpdateSessionStats: &persistence.MutableStateUpdateSessionStats{}}, nil).Once() + + _, err := s.mockHistoryEngine.RespondDecisionTaskCompleted(context.Background(), &types.HistoryRespondDecisionTaskCompletedRequest{ + DomainUUID: constants.TestDomainID, + CompleteRequest: &types.RespondDecisionTaskCompletedRequest{ + TaskToken: taskToken, + Decisions: decisions, + ExecutionContext: []byte("context"), + Identity: identity, + }, + }) + s.Nil(err) + + executionBuilder := s.getBuilder(constants.TestDomainID, we) + s.Equal(int64(11), executionBuilder.GetExecutionInfo().NextEventID) + s.Equal(int64(8), executionBuilder.GetExecutionInfo().LastProcessedEvent) + s.Equal(persistence.WorkflowStateRunning, executionBuilder.GetExecutionInfo().State) + s.False(executionBuilder.HasPendingDecision()) + + // Try recording activity heartbeat + s.mockExecutionMgr.On("UpdateWorkflowExecution", mock.Anything, mock.Anything).Return(&persistence.UpdateWorkflowExecutionResponse{MutableStateUpdateSessionStats: &persistence.MutableStateUpdateSessionStats{}}, nil).Once() + + activityTaskToken, _ := json.Marshal(&common.TaskToken{ + WorkflowID: "wId", + RunID: we.GetRunID(), + ScheduleID: 5, + }) + + hbResponse, err := s.mockHistoryEngine.RecordActivityTaskHeartbeat(context.Background(), &types.HistoryRecordActivityTaskHeartbeatRequest{ + DomainUUID: constants.TestDomainID, + HeartbeatRequest: &types.RecordActivityTaskHeartbeatRequest{ + TaskToken: activityTaskToken, + Identity: identity, + Details: []byte("details"), + }, + }) + s.Nil(err) + s.NotNil(hbResponse) + s.True(hbResponse.CancelRequested) + + // Try cancelling the request. + s.mockHistoryV2Mgr.On("AppendHistoryNodes", mock.Anything, mock.Anything).Return(&persistence.AppendHistoryNodesResponse{}, nil).Once() + s.mockExecutionMgr.On("UpdateWorkflowExecution", mock.Anything, mock.Anything).Return(&persistence.UpdateWorkflowExecutionResponse{MutableStateUpdateSessionStats: &persistence.MutableStateUpdateSessionStats{}}, nil).Once() + + err = s.mockHistoryEngine.RespondActivityTaskCanceled(context.Background(), &types.HistoryRespondActivityTaskCanceledRequest{ + DomainUUID: constants.TestDomainID, + CancelRequest: &types.RespondActivityTaskCanceledRequest{ + TaskToken: activityTaskToken, + Identity: identity, + Details: []byte("details"), + }, + }) + s.Nil(err) + + executionBuilder = s.getBuilder(constants.TestDomainID, we) + s.Equal(int64(13), executionBuilder.GetExecutionInfo().NextEventID) + s.Equal(int64(8), executionBuilder.GetExecutionInfo().LastProcessedEvent) + s.Equal(persistence.WorkflowStateRunning, executionBuilder.GetExecutionInfo().State) + s.True(executionBuilder.HasPendingDecision()) +} + +func (s *engineSuite) TestRequestCancel_RespondDecisionTaskCompleted_SuccessWithQueries() { + we := types.WorkflowExecution{ + WorkflowID: "wId", + RunID: constants.TestRunID, + } + tl := "testTaskList" + taskToken, _ := json.Marshal(&common.TaskToken{ + WorkflowID: we.WorkflowID, + RunID: we.RunID, + ScheduleID: 7, + }) + identity := "testIdentity" + activityID := "activity1_id" + activityType := "activity_type1" + activityInput := []byte("input1") + + msBuilder := execution.NewMutableStateBuilderWithEventV2( + s.mockHistoryEngine.shard, + testlogger.New(s.Suite.T()), + we.GetRunID(), + constants.TestLocalDomainEntry, + ) + test.AddWorkflowExecutionStartedEvent(msBuilder, we, "wType", tl, []byte("input"), 100, 100, identity) + di := test.AddDecisionTaskScheduledEvent(msBuilder) + decisionStartedEvent := test.AddDecisionTaskStartedEvent(msBuilder, di.ScheduleID, tl, identity) + decisionCompletedEvent := test.AddDecisionTaskCompletedEvent(msBuilder, di.ScheduleID, + decisionStartedEvent.ID, nil, identity) + activityScheduledEvent, _ := test.AddActivityTaskScheduledEvent(msBuilder, decisionCompletedEvent.ID, activityID, + activityType, tl, activityInput, 100, 10, 1, 1) + test.AddActivityTaskStartedEvent(msBuilder, activityScheduledEvent.ID, identity) + di2 := test.AddDecisionTaskScheduledEvent(msBuilder) + test.AddDecisionTaskStartedEvent(msBuilder, di2.ScheduleID, tl, identity) + + ms := execution.CreatePersistenceMutableState(msBuilder) + gwmsResponse := &persistence.GetWorkflowExecutionResponse{State: ms} + + decisions := []*types.Decision{{ + DecisionType: types.DecisionTypeRequestCancelActivityTask.Ptr(), + RequestCancelActivityTaskDecisionAttributes: &types.RequestCancelActivityTaskDecisionAttributes{ + ActivityID: activityID, + }, + }} + + s.mockExecutionMgr.On("GetWorkflowExecution", mock.Anything, mock.Anything).Return(gwmsResponse, nil).Once() + s.mockHistoryV2Mgr.On("AppendHistoryNodes", mock.Anything, mock.Anything).Return(&persistence.AppendHistoryNodesResponse{}, nil).Once() + s.mockExecutionMgr.On("UpdateWorkflowExecution", mock.Anything, mock.Anything).Return(&persistence.UpdateWorkflowExecutionResponse{MutableStateUpdateSessionStats: &persistence.MutableStateUpdateSessionStats{}}, nil).Once() + + // load mutable state such that it already exists in memory when respond decision task is called + // this enables us to set query registry on it + ctx, release, err := s.mockHistoryEngine.executionCache.GetOrCreateWorkflowExecutionForBackground(constants.TestDomainID, we) + s.NoError(err) + loadedMS, err := ctx.LoadWorkflowExecution(context.Background()) + s.NoError(err) + qr := query.NewRegistry() + id1, _ := qr.BufferQuery(&types.WorkflowQuery{}) + id2, _ := qr.BufferQuery(&types.WorkflowQuery{}) + id3, _ := qr.BufferQuery(&types.WorkflowQuery{}) + loadedMS.SetQueryRegistry(qr) + release(nil) + result1 := &types.WorkflowQueryResult{ + ResultType: types.QueryResultTypeAnswered.Ptr(), + Answer: []byte{1, 2, 3}, + } + result2 := &types.WorkflowQueryResult{ + ResultType: types.QueryResultTypeFailed.Ptr(), + ErrorMessage: "error reason", + } + queryResults := map[string]*types.WorkflowQueryResult{ + id1: result1, + id2: result2, + } + _, err = s.mockHistoryEngine.RespondDecisionTaskCompleted(s.constructCallContext(cc.GoWorkerConsistentQueryVersion), &types.HistoryRespondDecisionTaskCompletedRequest{ + DomainUUID: constants.TestDomainID, + CompleteRequest: &types.RespondDecisionTaskCompletedRequest{ + TaskToken: taskToken, + Decisions: decisions, + ExecutionContext: []byte("context"), + Identity: identity, + QueryResults: queryResults, + }, + }) + s.Nil(err) + + executionBuilder := s.getBuilder(constants.TestDomainID, we) + s.Equal(int64(11), executionBuilder.GetExecutionInfo().NextEventID) + s.Equal(int64(8), executionBuilder.GetExecutionInfo().LastProcessedEvent) + s.Equal(persistence.WorkflowStateRunning, executionBuilder.GetExecutionInfo().State) + s.False(executionBuilder.HasPendingDecision()) + s.Len(qr.GetCompletedIDs(), 2) + completed1, err := qr.GetTerminationState(id1) + s.NoError(err) + s.Equal(result1, completed1.QueryResult) + s.Equal(query.TerminationTypeCompleted, completed1.TerminationType) + completed2, err := qr.GetTerminationState(id2) + s.NoError(err) + s.Equal(result2, completed2.QueryResult) + s.Equal(query.TerminationTypeCompleted, completed2.TerminationType) + s.Len(qr.GetBufferedIDs(), 0) + s.Len(qr.GetFailedIDs(), 0) + s.Len(qr.GetUnblockedIDs(), 1) + unblocked1, err := qr.GetTerminationState(id3) + s.NoError(err) + s.Nil(unblocked1.QueryResult) + s.Equal(query.TerminationTypeUnblocked, unblocked1.TerminationType) + + // Try recording activity heartbeat + s.mockExecutionMgr.On("UpdateWorkflowExecution", mock.Anything, mock.Anything).Return(&persistence.UpdateWorkflowExecutionResponse{MutableStateUpdateSessionStats: &persistence.MutableStateUpdateSessionStats{}}, nil).Once() + + activityTaskToken, _ := json.Marshal(&common.TaskToken{ + WorkflowID: "wId", + RunID: we.GetRunID(), + ScheduleID: 5, + }) + + hbResponse, err := s.mockHistoryEngine.RecordActivityTaskHeartbeat(context.Background(), &types.HistoryRecordActivityTaskHeartbeatRequest{ + DomainUUID: constants.TestDomainID, + HeartbeatRequest: &types.RecordActivityTaskHeartbeatRequest{ + TaskToken: activityTaskToken, + Identity: identity, + Details: []byte("details"), + }, + }) + s.Nil(err) + s.NotNil(hbResponse) + s.True(hbResponse.CancelRequested) + + // Try cancelling the request. + s.mockHistoryV2Mgr.On("AppendHistoryNodes", mock.Anything, mock.Anything).Return(&persistence.AppendHistoryNodesResponse{}, nil).Once() + s.mockExecutionMgr.On("UpdateWorkflowExecution", mock.Anything, mock.Anything).Return(&persistence.UpdateWorkflowExecutionResponse{MutableStateUpdateSessionStats: &persistence.MutableStateUpdateSessionStats{}}, nil).Once() + + err = s.mockHistoryEngine.RespondActivityTaskCanceled(context.Background(), &types.HistoryRespondActivityTaskCanceledRequest{ + DomainUUID: constants.TestDomainID, + CancelRequest: &types.RespondActivityTaskCanceledRequest{ + TaskToken: activityTaskToken, + Identity: identity, + Details: []byte("details"), + }, + }) + s.Nil(err) + + executionBuilder = s.getBuilder(constants.TestDomainID, we) + s.Equal(int64(13), executionBuilder.GetExecutionInfo().NextEventID) + s.Equal(int64(8), executionBuilder.GetExecutionInfo().LastProcessedEvent) + s.Equal(persistence.WorkflowStateRunning, executionBuilder.GetExecutionInfo().State) + s.True(executionBuilder.HasPendingDecision()) +} + +func (s *engineSuite) TestRequestCancel_RespondDecisionTaskCompleted_SuccessWithConsistentQueriesUnsupported() { + we := types.WorkflowExecution{ + WorkflowID: "wId", + RunID: constants.TestRunID, + } + tl := "testTaskList" + taskToken, _ := json.Marshal(&common.TaskToken{ + WorkflowID: we.WorkflowID, + RunID: we.RunID, + ScheduleID: 7, + }) + identity := "testIdentity" + activityID := "activity1_id" + activityType := "activity_type1" + activityInput := []byte("input1") + + msBuilder := execution.NewMutableStateBuilderWithEventV2( + s.mockHistoryEngine.shard, + testlogger.New(s.Suite.T()), + we.GetRunID(), + constants.TestLocalDomainEntry, + ) + test.AddWorkflowExecutionStartedEvent(msBuilder, we, "wType", tl, []byte("input"), 100, 100, identity) + di := test.AddDecisionTaskScheduledEvent(msBuilder) + decisionStartedEvent := test.AddDecisionTaskStartedEvent(msBuilder, di.ScheduleID, tl, identity) + decisionCompletedEvent := test.AddDecisionTaskCompletedEvent(msBuilder, di.ScheduleID, + decisionStartedEvent.ID, nil, identity) + activityScheduledEvent, _ := test.AddActivityTaskScheduledEvent(msBuilder, decisionCompletedEvent.ID, activityID, + activityType, tl, activityInput, 100, 10, 1, 1) + test.AddActivityTaskStartedEvent(msBuilder, activityScheduledEvent.ID, identity) + di2 := test.AddDecisionTaskScheduledEvent(msBuilder) + test.AddDecisionTaskStartedEvent(msBuilder, di2.ScheduleID, tl, identity) + + ms := execution.CreatePersistenceMutableState(msBuilder) + gwmsResponse := &persistence.GetWorkflowExecutionResponse{State: ms} + + decisions := []*types.Decision{{ + DecisionType: types.DecisionTypeRequestCancelActivityTask.Ptr(), + RequestCancelActivityTaskDecisionAttributes: &types.RequestCancelActivityTaskDecisionAttributes{ + ActivityID: activityID, + }, + }} + + s.mockExecutionMgr.On("GetWorkflowExecution", mock.Anything, mock.Anything).Return(gwmsResponse, nil).Once() + s.mockHistoryV2Mgr.On("AppendHistoryNodes", mock.Anything, mock.Anything).Return(&persistence.AppendHistoryNodesResponse{}, nil).Once() + s.mockExecutionMgr.On("UpdateWorkflowExecution", mock.Anything, mock.Anything).Return(&persistence.UpdateWorkflowExecutionResponse{MutableStateUpdateSessionStats: &persistence.MutableStateUpdateSessionStats{}}, nil).Once() + + // load mutable state such that it already exists in memory when respond decision task is called + // this enables us to set query registry on it + ctx, release, err := s.mockHistoryEngine.executionCache.GetOrCreateWorkflowExecutionForBackground(constants.TestDomainID, we) + s.NoError(err) + loadedMS, err := ctx.LoadWorkflowExecution(context.Background()) + s.NoError(err) + qr := query.NewRegistry() + qr.BufferQuery(&types.WorkflowQuery{}) + qr.BufferQuery(&types.WorkflowQuery{}) + qr.BufferQuery(&types.WorkflowQuery{}) + loadedMS.SetQueryRegistry(qr) + release(nil) + _, err = s.mockHistoryEngine.RespondDecisionTaskCompleted(s.constructCallContext("0.0.0"), &types.HistoryRespondDecisionTaskCompletedRequest{ + DomainUUID: constants.TestDomainID, + CompleteRequest: &types.RespondDecisionTaskCompletedRequest{ + TaskToken: taskToken, + Decisions: decisions, + ExecutionContext: []byte("context"), + Identity: identity, + }, + }) + s.Nil(err) + + executionBuilder := s.getBuilder(constants.TestDomainID, we) + s.Equal(int64(11), executionBuilder.GetExecutionInfo().NextEventID) + s.Equal(int64(8), executionBuilder.GetExecutionInfo().LastProcessedEvent) + s.Equal(persistence.WorkflowStateRunning, executionBuilder.GetExecutionInfo().State) + s.False(executionBuilder.HasPendingDecision()) + s.Len(qr.GetBufferedIDs(), 0) + s.Len(qr.GetCompletedIDs(), 0) + s.Len(qr.GetUnblockedIDs(), 0) + s.Len(qr.GetFailedIDs(), 3) +} + +func (s *engineSuite) constructCallContext(featureVersion string) context.Context { + ctx := context.Background() + ctx, call := encoding.NewInboundCall(ctx) + err := call.ReadFromRequest(&transport.Request{ + Headers: transport.NewHeaders().With(common.ClientImplHeaderName, cc.GoSDK).With(common.FeatureVersionHeaderName, featureVersion), + }) + s.NoError(err) + return ctx +} + +func (s *engineSuite) TestStarTimer_DuplicateTimerID() { + + we := types.WorkflowExecution{ + WorkflowID: "wId", + RunID: constants.TestRunID, + } + tl := "testTaskList" + taskToken, _ := json.Marshal(&common.TaskToken{ + WorkflowID: we.WorkflowID, + RunID: we.RunID, + ScheduleID: 2, + }) + identity := "testIdentity" + timerID := "t1" + + msBuilder := execution.NewMutableStateBuilderWithEventV2( + s.mockHistoryEngine.shard, + testlogger.New(s.Suite.T()), + we.GetRunID(), + constants.TestLocalDomainEntry, + ) + + test.AddWorkflowExecutionStartedEvent(msBuilder, we, "wType", tl, []byte("input"), 100, 100, identity) + di := test.AddDecisionTaskScheduledEvent(msBuilder) + test.AddDecisionTaskStartedEvent(msBuilder, di.ScheduleID, tl, identity) + + ms := execution.CreatePersistenceMutableState(msBuilder) + gwmsResponse := &persistence.GetWorkflowExecutionResponse{State: ms} + + decisions := []*types.Decision{{ + DecisionType: types.DecisionTypeStartTimer.Ptr(), + StartTimerDecisionAttributes: &types.StartTimerDecisionAttributes{ + TimerID: timerID, + StartToFireTimeoutSeconds: common.Int64Ptr(1), + }, + }} + + s.mockExecutionMgr.On("GetWorkflowExecution", mock.Anything, mock.Anything).Return(gwmsResponse, nil).Once() + s.mockHistoryV2Mgr.On("AppendHistoryNodes", mock.Anything, mock.Anything).Return(&persistence.AppendHistoryNodesResponse{}, nil).Once() + s.mockExecutionMgr.On("UpdateWorkflowExecution", mock.Anything, mock.Anything).Return(&persistence.UpdateWorkflowExecutionResponse{MutableStateUpdateSessionStats: &persistence.MutableStateUpdateSessionStats{}}, nil).Once() + + _, err := s.mockHistoryEngine.RespondDecisionTaskCompleted(context.Background(), &types.HistoryRespondDecisionTaskCompletedRequest{ + DomainUUID: constants.TestDomainID, + CompleteRequest: &types.RespondDecisionTaskCompletedRequest{ + TaskToken: taskToken, + Decisions: decisions, + ExecutionContext: []byte("context"), + Identity: identity, + }, + }) + s.Nil(err) + + executionBuilder := s.getBuilder(constants.TestDomainID, we) + s.Equal(persistence.WorkflowStateRunning, executionBuilder.GetExecutionInfo().State) + + // Try to add the same timer ID again. + di2 := test.AddDecisionTaskScheduledEvent(executionBuilder) + test.AddDecisionTaskStartedEvent(executionBuilder, di2.ScheduleID, tl, identity) + taskToken2, _ := json.Marshal(&common.TaskToken{ + WorkflowID: we.WorkflowID, + RunID: we.RunID, + ScheduleID: di2.ScheduleID, + }) + + ms2 := execution.CreatePersistenceMutableState(executionBuilder) + gwmsResponse2 := &persistence.GetWorkflowExecutionResponse{State: ms2} + + decisionFailedEvent := false + s.mockExecutionMgr.On("GetWorkflowExecution", mock.Anything, mock.Anything).Return(gwmsResponse2, nil).Once() + s.mockHistoryV2Mgr.On("AppendHistoryNodes", mock.Anything, mock.Anything).Return(&persistence.AppendHistoryNodesResponse{}, nil).Run(func(arguments mock.Arguments) { + req := arguments.Get(1).(*persistence.AppendHistoryNodesRequest) + decTaskIndex := len(req.Events) - 1 + if decTaskIndex >= 0 && *req.Events[decTaskIndex].EventType == types.EventTypeDecisionTaskFailed { + decisionFailedEvent = true + } + }).Once() + s.mockExecutionMgr.On("UpdateWorkflowExecution", mock.Anything, mock.Anything).Return(&persistence.UpdateWorkflowExecutionResponse{MutableStateUpdateSessionStats: &persistence.MutableStateUpdateSessionStats{}}, nil).Once() + + _, err = s.mockHistoryEngine.RespondDecisionTaskCompleted(context.Background(), &types.HistoryRespondDecisionTaskCompletedRequest{ + DomainUUID: constants.TestDomainID, + CompleteRequest: &types.RespondDecisionTaskCompletedRequest{ + TaskToken: taskToken2, + Decisions: decisions, + ExecutionContext: []byte("context"), + Identity: identity, + }, + }) + s.Nil(err) + + s.True(decisionFailedEvent) + executionBuilder = s.getBuilder(constants.TestDomainID, we) + s.Equal(persistence.WorkflowStateRunning, executionBuilder.GetExecutionInfo().State) + s.True(executionBuilder.HasPendingDecision()) + di3, ok := executionBuilder.GetDecisionInfo(executionBuilder.GetExecutionInfo().NextEventID) + s.True(ok, "DI.ScheduleID: %v, ScheduleID: %v, StartedID: %v", di2.ScheduleID, + executionBuilder.GetExecutionInfo().DecisionScheduleID, executionBuilder.GetExecutionInfo().DecisionStartedID) + s.Equal(executionBuilder.GetExecutionInfo().NextEventID, di3.ScheduleID) + s.Equal(int64(1), di3.Attempt) +} + +func (s *engineSuite) TestUserTimer_RespondDecisionTaskCompleted() { + + we := types.WorkflowExecution{ + WorkflowID: "wId", + RunID: constants.TestRunID, + } + tl := "testTaskList" + taskToken, _ := json.Marshal(&common.TaskToken{ + WorkflowID: we.WorkflowID, + RunID: we.RunID, + ScheduleID: 6, + }) + identity := "testIdentity" + timerID := "t1" + + msBuilder := execution.NewMutableStateBuilderWithEventV2( + s.mockHistoryEngine.shard, + testlogger.New(s.Suite.T()), + we.GetRunID(), + constants.TestLocalDomainEntry, + ) + // Verify cancel timer with a start event. + test.AddWorkflowExecutionStartedEvent(msBuilder, we, "wType", tl, []byte("input"), 100, 100, identity) + di := test.AddDecisionTaskScheduledEvent(msBuilder) + decisionStartedEvent := test.AddDecisionTaskStartedEvent(msBuilder, di.ScheduleID, tl, identity) + decisionCompletedEvent := test.AddDecisionTaskCompletedEvent(msBuilder, di.ScheduleID, + decisionStartedEvent.ID, nil, identity) + test.AddTimerStartedEvent(msBuilder, decisionCompletedEvent.ID, timerID, 10) + di2 := test.AddDecisionTaskScheduledEvent(msBuilder) + test.AddDecisionTaskStartedEvent(msBuilder, di2.ScheduleID, tl, identity) + + ms := execution.CreatePersistenceMutableState(msBuilder) + gwmsResponse := &persistence.GetWorkflowExecutionResponse{State: ms} + + decisions := []*types.Decision{{ + DecisionType: types.DecisionTypeCancelTimer.Ptr(), + CancelTimerDecisionAttributes: &types.CancelTimerDecisionAttributes{ + TimerID: timerID, + }, + }} + + s.mockExecutionMgr.On("GetWorkflowExecution", mock.Anything, mock.Anything).Return(gwmsResponse, nil).Once() + s.mockHistoryV2Mgr.On("AppendHistoryNodes", mock.Anything, mock.Anything).Return(&persistence.AppendHistoryNodesResponse{}, nil).Once() + s.mockExecutionMgr.On("UpdateWorkflowExecution", mock.Anything, mock.Anything).Return(&persistence.UpdateWorkflowExecutionResponse{MutableStateUpdateSessionStats: &persistence.MutableStateUpdateSessionStats{}}, nil).Once() + + _, err := s.mockHistoryEngine.RespondDecisionTaskCompleted(context.Background(), &types.HistoryRespondDecisionTaskCompletedRequest{ + DomainUUID: constants.TestDomainID, + CompleteRequest: &types.RespondDecisionTaskCompletedRequest{ + TaskToken: taskToken, + Decisions: decisions, + ExecutionContext: []byte("context"), + Identity: identity, + }, + }) + s.Nil(err) + + executionBuilder := s.getBuilder(constants.TestDomainID, we) + s.Equal(int64(10), executionBuilder.GetExecutionInfo().NextEventID) + s.Equal(int64(7), executionBuilder.GetExecutionInfo().LastProcessedEvent) + s.Equal(persistence.WorkflowStateRunning, executionBuilder.GetExecutionInfo().State) + s.False(executionBuilder.HasPendingDecision()) +} + +func (s *engineSuite) TestCancelTimer_RespondDecisionTaskCompleted_NoStartTimer() { + + we := types.WorkflowExecution{ + WorkflowID: "wId", + RunID: constants.TestRunID, + } + tl := "testTaskList" + taskToken, _ := json.Marshal(&common.TaskToken{ + WorkflowID: we.WorkflowID, + RunID: we.RunID, + ScheduleID: 2, + }) + identity := "testIdentity" + timerID := "t1" + + msBuilder := execution.NewMutableStateBuilderWithEventV2( + s.mockHistoryEngine.shard, + testlogger.New(s.Suite.T()), + we.GetRunID(), + constants.TestLocalDomainEntry, + ) + // Verify cancel timer with a start event. + test.AddWorkflowExecutionStartedEvent(msBuilder, we, "wType", tl, []byte("input"), 100, 100, identity) + di := test.AddDecisionTaskScheduledEvent(msBuilder) + test.AddDecisionTaskStartedEvent(msBuilder, di.ScheduleID, tl, identity) + + ms := execution.CreatePersistenceMutableState(msBuilder) + gwmsResponse := &persistence.GetWorkflowExecutionResponse{State: ms} + + decisions := []*types.Decision{{ + DecisionType: types.DecisionTypeCancelTimer.Ptr(), + CancelTimerDecisionAttributes: &types.CancelTimerDecisionAttributes{ + TimerID: timerID, + }, + }} + + s.mockExecutionMgr.On("GetWorkflowExecution", mock.Anything, mock.Anything).Return(gwmsResponse, nil).Once() + s.mockHistoryV2Mgr.On("AppendHistoryNodes", mock.Anything, mock.Anything).Return(&persistence.AppendHistoryNodesResponse{}, nil).Once() + s.mockExecutionMgr.On("UpdateWorkflowExecution", mock.Anything, mock.Anything).Return(&persistence.UpdateWorkflowExecutionResponse{MutableStateUpdateSessionStats: &persistence.MutableStateUpdateSessionStats{}}, nil).Once() + + _, err := s.mockHistoryEngine.RespondDecisionTaskCompleted(context.Background(), &types.HistoryRespondDecisionTaskCompletedRequest{ + DomainUUID: constants.TestDomainID, + CompleteRequest: &types.RespondDecisionTaskCompletedRequest{ + TaskToken: taskToken, + Decisions: decisions, + ExecutionContext: []byte("context"), + Identity: identity, + }, + }) + s.Nil(err) + + executionBuilder := s.getBuilder(constants.TestDomainID, we) + s.Equal(int64(6), executionBuilder.GetExecutionInfo().NextEventID) + s.Equal(int64(3), executionBuilder.GetExecutionInfo().LastProcessedEvent) + s.Equal(persistence.WorkflowStateRunning, executionBuilder.GetExecutionInfo().State) + s.False(executionBuilder.HasPendingDecision()) +} + +func (s *engineSuite) TestCancelTimer_RespondDecisionTaskCompleted_TimerFired() { + + we := types.WorkflowExecution{ + WorkflowID: "wId", + RunID: constants.TestRunID, + } + tl := "testTaskList" + taskToken, _ := json.Marshal(&common.TaskToken{ + WorkflowID: we.WorkflowID, + RunID: we.RunID, + ScheduleID: 6, + }) + identity := "testIdentity" + timerID := "t1" + + msBuilder := execution.NewMutableStateBuilderWithEventV2( + s.mockHistoryEngine.shard, + testlogger.New(s.Suite.T()), + we.GetRunID(), + constants.TestLocalDomainEntry, + ) + // Verify cancel timer with a start event. + test.AddWorkflowExecutionStartedEvent(msBuilder, we, "wType", tl, []byte("input"), 100, 100, identity) + di := test.AddDecisionTaskScheduledEvent(msBuilder) + decisionStartedEvent := test.AddDecisionTaskStartedEvent(msBuilder, di.ScheduleID, tl, identity) + decisionCompletedEvent := test.AddDecisionTaskCompletedEvent(msBuilder, di.ScheduleID, + decisionStartedEvent.ID, nil, identity) + test.AddTimerStartedEvent(msBuilder, decisionCompletedEvent.ID, timerID, 10) + di2 := test.AddDecisionTaskScheduledEvent(msBuilder) + test.AddDecisionTaskStartedEvent(msBuilder, di2.ScheduleID, tl, identity) + test.AddTimerFiredEvent(msBuilder, timerID) + _, _, err := msBuilder.CloseTransactionAsMutation(time.Now(), execution.TransactionPolicyActive) + s.Nil(err) + + ms := execution.CreatePersistenceMutableState(msBuilder) + gwmsResponse := &persistence.GetWorkflowExecutionResponse{State: ms} + s.True(len(gwmsResponse.State.BufferedEvents) > 0) + + decisions := []*types.Decision{{ + DecisionType: types.DecisionTypeCancelTimer.Ptr(), + CancelTimerDecisionAttributes: &types.CancelTimerDecisionAttributes{ + TimerID: timerID, + }, + }} + + s.mockExecutionMgr.On("GetWorkflowExecution", mock.Anything, mock.Anything).Return(gwmsResponse, nil).Once() + s.mockHistoryV2Mgr.On("AppendHistoryNodes", mock.Anything, mock.Anything).Return(&persistence.AppendHistoryNodesResponse{}, nil).Once() + s.mockExecutionMgr.On("UpdateWorkflowExecution", mock.Anything, mock.MatchedBy(func(input *persistence.UpdateWorkflowExecutionRequest) bool { + // need to check whether the buffered events are cleared + s.True(input.UpdateWorkflowMutation.ClearBufferedEvents) + return true + })).Return(&persistence.UpdateWorkflowExecutionResponse{MutableStateUpdateSessionStats: &persistence.MutableStateUpdateSessionStats{}}, nil).Once() + + _, err = s.mockHistoryEngine.RespondDecisionTaskCompleted(context.Background(), &types.HistoryRespondDecisionTaskCompletedRequest{ + DomainUUID: constants.TestDomainID, + CompleteRequest: &types.RespondDecisionTaskCompletedRequest{ + TaskToken: taskToken, + Decisions: decisions, + ExecutionContext: []byte("context"), + Identity: identity, + }, + }) + s.Nil(err) + + executionBuilder := s.getBuilder(constants.TestDomainID, we) + s.Equal(int64(10), executionBuilder.GetExecutionInfo().NextEventID) + s.Equal(int64(7), executionBuilder.GetExecutionInfo().LastProcessedEvent) + s.Equal(persistence.WorkflowStateRunning, executionBuilder.GetExecutionInfo().State) + s.False(executionBuilder.HasPendingDecision()) + s.False(executionBuilder.HasBufferedEvents()) +} + +func (s *engineSuite) TestSignalWorkflowExecution_InvalidRequest() { + signalRequest := &types.HistorySignalWorkflowExecutionRequest{} + err := s.mockHistoryEngine.SignalWorkflowExecution(context.Background(), signalRequest) + s.Error(err) +} + +func (s *engineSuite) TestSignalWorkflowExecution() { + we := types.WorkflowExecution{ + WorkflowID: constants.TestWorkflowID, + RunID: constants.TestRunID, + } + tasklist := "testTaskList" + identity := "testIdentity" + signalName := "my signal name" + input := []byte("test input") + signalRequest := &types.HistorySignalWorkflowExecutionRequest{ + DomainUUID: constants.TestDomainID, + SignalRequest: &types.SignalWorkflowExecutionRequest{ + Domain: constants.TestDomainID, + WorkflowExecution: &we, + Identity: identity, + SignalName: signalName, + Input: input, + }, + } + + msBuilder := execution.NewMutableStateBuilderWithEventV2( + s.mockHistoryEngine.shard, + testlogger.New(s.Suite.T()), + we.GetRunID(), + constants.TestLocalDomainEntry, + ) + test.AddWorkflowExecutionStartedEvent(msBuilder, we, "wType", tasklist, []byte("input"), 100, 200, identity) + test.AddDecisionTaskScheduledEvent(msBuilder) + ms := execution.CreatePersistenceMutableState(msBuilder) + ms.ExecutionInfo.DomainID = constants.TestDomainID + gwmsResponse := &persistence.GetWorkflowExecutionResponse{State: ms} + + s.mockExecutionMgr.On("GetWorkflowExecution", mock.Anything, mock.Anything).Return(gwmsResponse, nil).Once() + s.mockHistoryV2Mgr.On("AppendHistoryNodes", mock.Anything, mock.Anything).Return(&persistence.AppendHistoryNodesResponse{}, nil).Once() + s.mockExecutionMgr.On("UpdateWorkflowExecution", mock.Anything, mock.Anything).Return(&persistence.UpdateWorkflowExecutionResponse{MutableStateUpdateSessionStats: &persistence.MutableStateUpdateSessionStats{}}, nil).Once() + + err := s.mockHistoryEngine.SignalWorkflowExecution(context.Background(), signalRequest) + s.Nil(err) +} + +// Test signal decision by adding request ID +func (s *engineSuite) TestSignalWorkflowExecution_DuplicateRequest_WorkflowOpen() { + we := types.WorkflowExecution{ + WorkflowID: constants.TestWorkflowID, + RunID: constants.TestRunID, + } + tasklist := "testTaskList" + identity := "testIdentity" + signalName := "my signal name 2" + input := []byte("test input 2") + requestID := uuid.New() + signalRequest := &types.HistorySignalWorkflowExecutionRequest{ + DomainUUID: constants.TestDomainID, + SignalRequest: &types.SignalWorkflowExecutionRequest{ + Domain: constants.TestDomainID, + WorkflowExecution: &we, + Identity: identity, + SignalName: signalName, + Input: input, + RequestID: requestID, + }, + } + + msBuilder := execution.NewMutableStateBuilderWithEventV2( + s.mockHistoryEngine.shard, + testlogger.New(s.Suite.T()), + we.GetRunID(), + constants.TestLocalDomainEntry, + ) + test.AddWorkflowExecutionStartedEvent(msBuilder, we, "wType", tasklist, []byte("input"), 100, 200, identity) + test.AddDecisionTaskScheduledEvent(msBuilder) + ms := execution.CreatePersistenceMutableState(msBuilder) + // assume duplicate request id + ms.SignalRequestedIDs = make(map[string]struct{}) + ms.SignalRequestedIDs[requestID] = struct{}{} + ms.ExecutionInfo.DomainID = constants.TestDomainID + gwmsResponse := &persistence.GetWorkflowExecutionResponse{State: ms} + + s.mockExecutionMgr.On("GetWorkflowExecution", mock.Anything, mock.Anything).Return(gwmsResponse, nil).Once() + + err := s.mockHistoryEngine.SignalWorkflowExecution(context.Background(), signalRequest) + s.Nil(err) +} + +func (s *engineSuite) TestSignalWorkflowExecution_DuplicateRequest_WorkflowCompleted() { + we := types.WorkflowExecution{ + WorkflowID: constants.TestWorkflowID, + RunID: constants.TestRunID, + } + tasklist := "testTaskList" + identity := "testIdentity" + signalName := "my signal name 2" + input := []byte("test input 2") + requestID := uuid.New() + signalRequest := &types.HistorySignalWorkflowExecutionRequest{ + DomainUUID: constants.TestDomainID, + SignalRequest: &types.SignalWorkflowExecutionRequest{ + Domain: constants.TestDomainID, + WorkflowExecution: &we, + Identity: identity, + SignalName: signalName, + Input: input, + RequestID: requestID, + }, + } + + msBuilder := execution.NewMutableStateBuilderWithEventV2( + s.mockHistoryEngine.shard, + testlogger.New(s.Suite.T()), + we.GetRunID(), + constants.TestLocalDomainEntry, + ) + test.AddWorkflowExecutionStartedEvent(msBuilder, we, "wType", tasklist, []byte("input"), 100, 200, identity) + test.AddDecisionTaskScheduledEvent(msBuilder) + ms := execution.CreatePersistenceMutableState(msBuilder) + // assume duplicate request id + ms.SignalRequestedIDs = make(map[string]struct{}) + ms.SignalRequestedIDs[requestID] = struct{}{} + ms.ExecutionInfo.DomainID = constants.TestDomainID + ms.ExecutionInfo.State = persistence.WorkflowStateCompleted + gwmsResponse := &persistence.GetWorkflowExecutionResponse{State: ms} + + s.mockExecutionMgr.On("GetWorkflowExecution", mock.Anything, mock.Anything).Return(gwmsResponse, nil).Once() + + err := s.mockHistoryEngine.SignalWorkflowExecution(context.Background(), signalRequest) + s.Nil(err) +} + +func (s *engineSuite) TestSignalWorkflowExecution_WorkflowCompleted() { + we := &types.WorkflowExecution{ + WorkflowID: constants.TestWorkflowID, + RunID: constants.TestRunID, + } + tasklist := "testTaskList" + identity := "testIdentity" + signalName := "my signal name" + input := []byte("test input") + signalRequest := &types.HistorySignalWorkflowExecutionRequest{ + DomainUUID: constants.TestDomainID, + SignalRequest: &types.SignalWorkflowExecutionRequest{ + Domain: constants.TestDomainID, + WorkflowExecution: we, + Identity: identity, + SignalName: signalName, + Input: input, + }, + } + + msBuilder := execution.NewMutableStateBuilderWithEventV2( + s.mockHistoryEngine.shard, + testlogger.New(s.Suite.T()), + we.GetRunID(), + constants.TestLocalDomainEntry, + ) + test.AddWorkflowExecutionStartedEvent(msBuilder, *we, "wType", tasklist, []byte("input"), 100, 200, identity) + test.AddDecisionTaskScheduledEvent(msBuilder) + ms := execution.CreatePersistenceMutableState(msBuilder) + ms.ExecutionInfo.State = persistence.WorkflowStateCompleted + gwmsResponse := &persistence.GetWorkflowExecutionResponse{State: ms} + + s.mockExecutionMgr.On("GetWorkflowExecution", mock.Anything, mock.Anything).Return(gwmsResponse, nil).Once() + + err := s.mockHistoryEngine.SignalWorkflowExecution(context.Background(), signalRequest) + s.EqualError(err, "workflow execution already completed") +} + +func (s *engineSuite) TestRemoveSignalMutableState() { + removeRequest := &types.RemoveSignalMutableStateRequest{} + err := s.mockHistoryEngine.RemoveSignalMutableState(context.Background(), removeRequest) + s.Error(err) + + workflowExecution := types.WorkflowExecution{ + WorkflowID: "wId", + RunID: constants.TestRunID, + } + tasklist := "testTaskList" + identity := "testIdentity" + requestID := uuid.New() + removeRequest = &types.RemoveSignalMutableStateRequest{ + DomainUUID: constants.TestDomainID, + WorkflowExecution: &workflowExecution, + RequestID: requestID, + } + + msBuilder := execution.NewMutableStateBuilderWithEventV2( + s.mockHistoryEngine.shard, + testlogger.New(s.Suite.T()), + constants.TestRunID, + constants.TestLocalDomainEntry, + ) + test.AddWorkflowExecutionStartedEvent(msBuilder, workflowExecution, "wType", tasklist, []byte("input"), 100, 200, identity) + test.AddDecisionTaskScheduledEvent(msBuilder) + ms := execution.CreatePersistenceMutableState(msBuilder) + ms.ExecutionInfo.DomainID = constants.TestDomainID + gwmsResponse := &persistence.GetWorkflowExecutionResponse{State: ms} + + s.mockExecutionMgr.On("GetWorkflowExecution", mock.Anything, mock.Anything).Return(gwmsResponse, nil).Once() + s.mockExecutionMgr.On("UpdateWorkflowExecution", mock.Anything, mock.Anything).Return(&persistence.UpdateWorkflowExecutionResponse{MutableStateUpdateSessionStats: &persistence.MutableStateUpdateSessionStats{}}, nil).Once() + + err = s.mockHistoryEngine.RemoveSignalMutableState(context.Background(), removeRequest) + s.Nil(err) +} + +func (s *engineSuite) TestReapplyEvents_ReturnSuccess() { + workflowExecution := types.WorkflowExecution{ + WorkflowID: "test-reapply", + RunID: constants.TestRunID, + } + history := []*types.HistoryEvent{ + { + ID: 1, + EventType: types.EventTypeWorkflowExecutionSignaled.Ptr(), + Version: 1, + }, + } + msBuilder := execution.NewMutableStateBuilderWithEventV2( + s.mockHistoryEngine.shard, + testlogger.New(s.Suite.T()), + workflowExecution.GetRunID(), + constants.TestLocalDomainEntry, + ) + ms := execution.CreatePersistenceMutableState(msBuilder) + gwmsResponse := &persistence.GetWorkflowExecutionResponse{State: ms} + gceResponse := &persistence.GetCurrentExecutionResponse{RunID: constants.TestRunID} + s.mockExecutionMgr.On("GetCurrentExecution", mock.Anything, mock.Anything).Return(gceResponse, nil).Once() + s.mockExecutionMgr.On("GetWorkflowExecution", mock.Anything, mock.Anything).Return(gwmsResponse, nil).Once() + s.mockEventsReapplier.EXPECT().ReapplyEvents(gomock.Any(), gomock.Any(), gomock.Any(), gomock.Any()).Times(1) + + err := s.mockHistoryEngine.ReapplyEvents( + context.Background(), + constants.TestDomainID, + workflowExecution.WorkflowID, + workflowExecution.RunID, + history, + ) + s.NoError(err) +} + +func (s *engineSuite) TestReapplyEvents_IgnoreSameVersionEvents() { + workflowExecution := types.WorkflowExecution{ + WorkflowID: "test-reapply-same-version", + RunID: constants.TestRunID, + } + history := []*types.HistoryEvent{ + { + ID: 1, + EventType: types.EventTypeTimerStarted.Ptr(), + Version: common.EmptyVersion, + }, + } + msBuilder := execution.NewMutableStateBuilderWithEventV2( + s.mockHistoryEngine.shard, + testlogger.New(s.Suite.T()), + workflowExecution.GetRunID(), + constants.TestLocalDomainEntry, + ) + + ms := execution.CreatePersistenceMutableState(msBuilder) + gwmsResponse := &persistence.GetWorkflowExecutionResponse{State: ms} + gceResponse := &persistence.GetCurrentExecutionResponse{RunID: constants.TestRunID} + s.mockExecutionMgr.On("GetCurrentExecution", mock.Anything, mock.Anything).Return(gceResponse, nil).Once() + s.mockExecutionMgr.On("GetWorkflowExecution", mock.Anything, mock.Anything).Return(gwmsResponse, nil).Once() + s.mockEventsReapplier.EXPECT().ReapplyEvents(gomock.Any(), gomock.Any(), gomock.Any(), gomock.Any()).Times(0) + + err := s.mockHistoryEngine.ReapplyEvents( + context.Background(), + constants.TestDomainID, + workflowExecution.WorkflowID, + workflowExecution.RunID, + history, + ) + s.NoError(err) +} + +func (s *engineSuite) TestReapplyEvents_ResetWorkflow() { + workflowExecution := types.WorkflowExecution{ + WorkflowID: "test-reapply-reset-workflow", + RunID: constants.TestRunID, + } + history := []*types.HistoryEvent{ + { + ID: 1, + EventType: types.EventTypeWorkflowExecutionSignaled.Ptr(), + Version: 100, + }, + } + msBuilder := execution.NewMutableStateBuilderWithEventV2( + s.mockHistoryEngine.shard, + testlogger.New(s.Suite.T()), + workflowExecution.GetRunID(), + constants.TestLocalDomainEntry, + ) + ms := execution.CreatePersistenceMutableState(msBuilder) + ms.ExecutionInfo.State = persistence.WorkflowStateCompleted + ms.ExecutionInfo.LastProcessedEvent = 1 + token, err := msBuilder.GetCurrentBranchToken() + s.NoError(err) + item := persistence.NewVersionHistoryItem(1, 1) + versionHistory := persistence.NewVersionHistory(token, []*persistence.VersionHistoryItem{item}) + ms.VersionHistories = persistence.NewVersionHistories(versionHistory) + gwmsResponse := &persistence.GetWorkflowExecutionResponse{State: ms} + gceResponse := &persistence.GetCurrentExecutionResponse{RunID: constants.TestRunID} + s.mockExecutionMgr.On("GetCurrentExecution", mock.Anything, mock.Anything).Return(gceResponse, nil).Once() + s.mockExecutionMgr.On("GetWorkflowExecution", mock.Anything, mock.Anything).Return(gwmsResponse, nil).Once() + s.mockEventsReapplier.EXPECT().ReapplyEvents(gomock.Any(), gomock.Any(), gomock.Any(), gomock.Any()).Times(0) + s.mockWorkflowResetter.EXPECT().ResetWorkflow(gomock.Any(), gomock.Any(), gomock.Any(), gomock.Any(), gomock.Any(), + gomock.Any(), gomock.Any(), gomock.Any(), gomock.Any(), gomock.Any(), gomock.Any(), gomock.Any(), gomock.Any(), + gomock.Any(), + ).Return(nil).Times(1) + err = s.mockHistoryEngine.ReapplyEvents( + context.Background(), + constants.TestDomainID, + workflowExecution.WorkflowID, + workflowExecution.RunID, + history, + ) + s.NoError(err) +} + +func (s *engineSuite) getBuilder(testDomainID string, we types.WorkflowExecution) execution.MutableState { + context, release, err := s.mockHistoryEngine.executionCache.GetOrCreateWorkflowExecutionForBackground(testDomainID, we) + if err != nil { + return nil + } + defer release(nil) + + return context.GetWorkflowExecution() +} + +func (s *engineSuite) getActivityScheduledEvent( + msBuilder execution.MutableState, + scheduleID int64, +) *types.HistoryEvent { + event, _ := msBuilder.GetActivityScheduledEvent(context.Background(), scheduleID) + return event +} + +func (s *engineSuite) printHistory(builder execution.MutableState) string { + return thrift.FromHistory(builder.GetHistoryBuilder().GetHistory()).String() +} + +func TestRecordChildExecutionCompleted(t *testing.T) { + testCases := []struct { + name string + request *types.RecordChildExecutionCompletedRequest + mockSetup func(*execution.MockMutableState) + wantErr bool + assertErr func(t *testing.T, err error) + }{ + { + name: "workflow not running", + request: &types.RecordChildExecutionCompletedRequest{ + DomainUUID: "58f7998e-9c00-4827-bbd3-6a891b3ca0ca", + InitiatedID: 1, + WorkflowExecution: &types.WorkflowExecution{ + WorkflowID: "wid", + RunID: "4353ddce-ca34-4c78-9785-dc0b83af4bbc", + }, + CompletedExecution: &types.WorkflowExecution{ + WorkflowID: "wid1", + RunID: "312b2440-2859-4e50-a59f-d92a300a072d", + }, + }, + mockSetup: func(ms *execution.MockMutableState) { + ms.EXPECT().IsWorkflowExecutionRunning().Return(false) + }, + wantErr: true, + assertErr: func(t *testing.T, err error) { + assert.Equal(t, workflow.ErrNotExists, err) + }, + }, + { + name: "stale mutable state - not containing initiated event", + request: &types.RecordChildExecutionCompletedRequest{ + DomainUUID: "58f7998e-9c00-4827-bbd3-6a891b3ca0ca", + InitiatedID: 10, + WorkflowExecution: &types.WorkflowExecution{ + WorkflowID: "wid", + RunID: "4353ddce-ca34-4c78-9785-dc0b83af4bbc", + }, + CompletedExecution: &types.WorkflowExecution{ + WorkflowID: "wid1", + RunID: "312b2440-2859-4e50-a59f-d92a300a072d", + }, + }, + mockSetup: func(ms *execution.MockMutableState) { + ms.EXPECT().IsWorkflowExecutionRunning().Return(true) + ms.EXPECT().GetChildExecutionInfo(int64(10)).Return(nil, false) + ms.EXPECT().GetNextEventID().Return(int64(10)).Times(2) + }, + wantErr: true, + assertErr: func(t *testing.T, err error) { + assert.Equal(t, workflow.ErrStaleState, err) + }, + }, + { + name: "pending child execution not found", + request: &types.RecordChildExecutionCompletedRequest{ + DomainUUID: "58f7998e-9c00-4827-bbd3-6a891b3ca0ca", + InitiatedID: 10, + WorkflowExecution: &types.WorkflowExecution{ + WorkflowID: "wid", + RunID: "4353ddce-ca34-4c78-9785-dc0b83af4bbc", + }, + CompletedExecution: &types.WorkflowExecution{ + WorkflowID: "wid1", + RunID: "312b2440-2859-4e50-a59f-d92a300a072d", + }, + }, + mockSetup: func(ms *execution.MockMutableState) { + ms.EXPECT().IsWorkflowExecutionRunning().Return(true) + ms.EXPECT().GetChildExecutionInfo(int64(10)).Return(nil, false) + ms.EXPECT().GetNextEventID().Return(int64(11)).Times(1) + }, + wantErr: true, + assertErr: func(t *testing.T, err error) { + assert.Equal(t, &types.EntityNotExistsError{Message: "Pending child execution not found."}, err) + }, + }, + { + name: "stale mutable state - not containing started event", + request: &types.RecordChildExecutionCompletedRequest{ + DomainUUID: "58f7998e-9c00-4827-bbd3-6a891b3ca0ca", + InitiatedID: 10, + WorkflowExecution: &types.WorkflowExecution{ + WorkflowID: "wid", + RunID: "4353ddce-ca34-4c78-9785-dc0b83af4bbc", + }, + CompletedExecution: &types.WorkflowExecution{ + WorkflowID: "wid1", + RunID: "312b2440-2859-4e50-a59f-d92a300a072d", + }, + StartedID: 11, + }, + mockSetup: func(ms *execution.MockMutableState) { + ms.EXPECT().IsWorkflowExecutionRunning().Return(true) + ms.EXPECT().GetChildExecutionInfo(int64(10)).Return(&persistence.ChildExecutionInfo{StartedID: common.EmptyEventID}, true) + ms.EXPECT().GetNextEventID().Return(int64(11)).Times(2) + }, + wantErr: true, + assertErr: func(t *testing.T, err error) { + assert.Equal(t, workflow.ErrStaleState, err) + }, + }, + { + name: "pending child execution not started", + request: &types.RecordChildExecutionCompletedRequest{ + DomainUUID: "58f7998e-9c00-4827-bbd3-6a891b3ca0ca", + InitiatedID: 10, + WorkflowExecution: &types.WorkflowExecution{ + WorkflowID: "wid", + RunID: "4353ddce-ca34-4c78-9785-dc0b83af4bbc", + }, + CompletedExecution: &types.WorkflowExecution{ + WorkflowID: "wid1", + RunID: "312b2440-2859-4e50-a59f-d92a300a072d", + }, + StartedID: 11, + }, + mockSetup: func(ms *execution.MockMutableState) { + ms.EXPECT().IsWorkflowExecutionRunning().Return(true) + ms.EXPECT().GetChildExecutionInfo(int64(10)).Return(&persistence.ChildExecutionInfo{StartedID: common.EmptyEventID}, true) + ms.EXPECT().GetNextEventID().Return(int64(12)).Times(1) + }, + wantErr: true, + assertErr: func(t *testing.T, err error) { + assert.Equal(t, &types.EntityNotExistsError{Message: "Pending child execution not started."}, err) + }, + }, + { + name: "pending child execution workflowID mismatch", + request: &types.RecordChildExecutionCompletedRequest{ + DomainUUID: "58f7998e-9c00-4827-bbd3-6a891b3ca0ca", + InitiatedID: 10, + WorkflowExecution: &types.WorkflowExecution{ + WorkflowID: "wid", + RunID: "4353ddce-ca34-4c78-9785-dc0b83af4bbc", + }, + CompletedExecution: &types.WorkflowExecution{ + WorkflowID: "wid1", + RunID: "312b2440-2859-4e50-a59f-d92a300a072d", + }, + StartedID: 11, + }, + mockSetup: func(ms *execution.MockMutableState) { + ms.EXPECT().IsWorkflowExecutionRunning().Return(true) + ms.EXPECT().GetChildExecutionInfo(int64(10)).Return(&persistence.ChildExecutionInfo{StartedID: 11, StartedWorkflowID: "wid0"}, true) + }, + wantErr: true, + assertErr: func(t *testing.T, err error) { + assert.Equal(t, &types.EntityNotExistsError{Message: "Pending child execution workflowID mismatch."}, err) + }, + }, + { + name: "success - child workflow completed", + request: &types.RecordChildExecutionCompletedRequest{ + DomainUUID: "58f7998e-9c00-4827-bbd3-6a891b3ca0ca", + InitiatedID: 10, + WorkflowExecution: &types.WorkflowExecution{ + WorkflowID: "wid", + RunID: "4353ddce-ca34-4c78-9785-dc0b83af4bbc", + }, + CompletedExecution: &types.WorkflowExecution{ + WorkflowID: "wid1", + RunID: "312b2440-2859-4e50-a59f-d92a300a072d", + }, + CompletionEvent: &types.HistoryEvent{ + EventType: types.EventTypeWorkflowExecutionCompleted.Ptr(), + WorkflowExecutionCompletedEventAttributes: &types.WorkflowExecutionCompletedEventAttributes{ + Result: []byte("success"), + }, + }, + StartedID: 11, + }, + mockSetup: func(ms *execution.MockMutableState) { + ms.EXPECT().IsWorkflowExecutionRunning().Return(true) + ms.EXPECT().GetChildExecutionInfo(int64(10)).Return(&persistence.ChildExecutionInfo{StartedID: 11, StartedWorkflowID: "wid1"}, true) + ms.EXPECT().AddChildWorkflowExecutionCompletedEvent(int64(10), gomock.Any(), gomock.Any()).Return(nil, nil) + }, + wantErr: false, + }, + } + + for _, tc := range testCases { + t.Run(tc.name, func(t *testing.T) { + ctrl := gomock.NewController(t) + mockShard := shard.NewTestContext(t, ctrl, &persistence.ShardInfo{}, config.NewForTest()) + mockDomainCache := mockShard.Resource.DomainCache + testDomainEntry := cache.NewLocalDomainCacheEntryForTest( + &persistence.DomainInfo{ID: constants.TestDomainID}, &persistence.DomainConfig{}, "", + ) + mockDomainCache.EXPECT().GetDomainByID(gomock.Any()).Return(testDomainEntry, nil).AnyTimes() + mockDomainCache.EXPECT().GetDomainName(gomock.Any()).Return(constants.TestDomainID, nil).AnyTimes() + ms := execution.NewMockMutableState(ctrl) + tc.mockSetup(ms) + + historyEngine := &historyEngineImpl{ + shard: mockShard, + clusterMetadata: mockShard.GetClusterMetadata(), + timeSource: mockShard.GetTimeSource(), + metricsClient: metrics.NewClient(tally.NoopScope, metrics.History), + logger: mockShard.GetLogger(), + updateWithActionFn: func(_ context.Context, _ *execution.Cache, _ string, _ types.WorkflowExecution, _ bool, _ time.Time, actionFn func(wfContext execution.Context, mutableState execution.MutableState) error) error { + return actionFn(nil, ms) + }, + } + + err := historyEngine.RecordChildExecutionCompleted(context.Background(), tc.request) + if tc.wantErr { + tc.assertErr(t, err) + } else { + assert.NoError(t, err) + } + }) + } +} diff --git a/service/history/engine/engineimpl/history_engine_test.go b/service/history/engine/engineimpl/history_engine_test.go index aed2550367f..3e26cd68234 100644 --- a/service/history/engine/engineimpl/history_engine_test.go +++ b/service/history/engine/engineimpl/history_engine_test.go @@ -22,5445 +22,15 @@ package engineimpl import ( - "context" - "encoding/json" - "errors" - "sync" "testing" - "time" - "github.com/golang/mock/gomock" - "github.com/pborman/uuid" - "github.com/stretchr/testify/assert" - "github.com/stretchr/testify/mock" - "github.com/stretchr/testify/require" - "github.com/stretchr/testify/suite" - "github.com/uber-go/tally" - "go.uber.org/yarpc/api/encoding" - "go.uber.org/yarpc/api/transport" - - hclient "github.com/uber/cadence/client/history" - "github.com/uber/cadence/client/matching" - "github.com/uber/cadence/common" - "github.com/uber/cadence/common/cache" - cc "github.com/uber/cadence/common/client" - "github.com/uber/cadence/common/clock" - "github.com/uber/cadence/common/cluster" - "github.com/uber/cadence/common/dynamicconfig" - "github.com/uber/cadence/common/log/testlogger" - "github.com/uber/cadence/common/metrics" - "github.com/uber/cadence/common/mocks" - "github.com/uber/cadence/common/persistence" - "github.com/uber/cadence/common/types" - "github.com/uber/cadence/common/types/mapper/thrift" - "github.com/uber/cadence/service/history/config" - "github.com/uber/cadence/service/history/constants" - "github.com/uber/cadence/service/history/decision" - "github.com/uber/cadence/service/history/events" - "github.com/uber/cadence/service/history/execution" - "github.com/uber/cadence/service/history/ndc" - "github.com/uber/cadence/service/history/query" - "github.com/uber/cadence/service/history/queue" - "github.com/uber/cadence/service/history/reset" - "github.com/uber/cadence/service/history/shard" - test "github.com/uber/cadence/service/history/testing" - "github.com/uber/cadence/service/history/workflow" -) - -type ( - engineSuite struct { - suite.Suite - *require.Assertions - - controller *gomock.Controller - mockShard *shard.TestContext - mockTxProcessor *queue.MockProcessor - mockTimerProcessor *queue.MockProcessor - mockDomainCache *cache.MockDomainCache - mockHistoryClient *hclient.MockClient - mockMatchingClient *matching.MockClient - mockEventsReapplier *ndc.MockEventsReapplier - mockWorkflowResetter *reset.MockWorkflowResetter - - mockHistoryEngine *historyEngineImpl - mockExecutionMgr *mocks.ExecutionManager - mockHistoryV2Mgr *mocks.HistoryV2Manager - mockShardManager *mocks.ShardManager - - eventsCache events.Cache - config *config.Config - } + "github.com/uber/cadence/service/history/engine/testdata" ) -func TestEngineSuite(t *testing.T) { - s := new(engineSuite) - suite.Run(t, s) -} - -func (s *engineSuite) SetupSuite() { - s.config = config.NewForTest() -} - -func (s *engineSuite) TearDownSuite() { -} - -func (s *engineSuite) SetupTest() { - s.Assertions = require.New(s.T()) - - s.controller = gomock.NewController(s.T()) - s.mockTxProcessor = queue.NewMockProcessor(s.controller) - s.mockTimerProcessor = queue.NewMockProcessor(s.controller) - s.mockEventsReapplier = ndc.NewMockEventsReapplier(s.controller) - s.mockWorkflowResetter = reset.NewMockWorkflowResetter(s.controller) - s.mockTxProcessor.EXPECT().NotifyNewTask(gomock.Any(), gomock.Any()).AnyTimes() - s.mockTimerProcessor.EXPECT().NotifyNewTask(gomock.Any(), gomock.Any()).AnyTimes() - - s.mockShard = shard.NewTestContext( - s.T(), - s.controller, - &persistence.ShardInfo{ - RangeID: 1, - TransferAckLevel: 0, - }, - s.config, - ) - s.eventsCache = events.NewCache( - s.mockShard.GetShardID(), - s.mockShard.GetHistoryManager(), - s.config, - s.mockShard.GetLogger(), - s.mockShard.GetMetricsClient(), - s.mockDomainCache, - ) - s.mockShard.SetEventsCache(s.eventsCache) - - s.mockMatchingClient = s.mockShard.Resource.MatchingClient - s.mockHistoryClient = s.mockShard.Resource.HistoryClient - s.mockExecutionMgr = s.mockShard.Resource.ExecutionMgr - s.mockHistoryV2Mgr = s.mockShard.Resource.HistoryMgr - s.mockShardManager = s.mockShard.Resource.ShardMgr - s.mockDomainCache = s.mockShard.Resource.DomainCache - s.mockDomainCache.EXPECT().GetDomainByID(constants.TestDomainID).Return(constants.TestLocalDomainEntry, nil).AnyTimes() - s.mockDomainCache.EXPECT().GetDomainName(constants.TestDomainID).Return(constants.TestDomainName, nil).AnyTimes() - s.mockDomainCache.EXPECT().GetDomain(constants.TestDomainName).Return(constants.TestLocalDomainEntry, nil).AnyTimes() - s.mockDomainCache.EXPECT().GetDomainID(constants.TestDomainName).Return(constants.TestDomainID, nil).AnyTimes() - - historyEventNotifier := events.NewNotifier( - clock.NewRealTimeSource(), - s.mockShard.Resource.MetricsClient, - func(workflowID string) int { - return len(workflowID) - }, - ) - - h := &historyEngineImpl{ - currentClusterName: s.mockShard.GetClusterMetadata().GetCurrentClusterName(), - shard: s.mockShard, - timeSource: s.mockShard.GetTimeSource(), - clusterMetadata: s.mockShard.Resource.ClusterMetadata, - executionManager: s.mockExecutionMgr, - historyV2Mgr: s.mockHistoryV2Mgr, - executionCache: execution.NewCache(s.mockShard), - logger: s.mockShard.GetLogger(), - metricsClient: s.mockShard.GetMetricsClient(), - tokenSerializer: common.NewJSONTaskTokenSerializer(), - historyEventNotifier: historyEventNotifier, - config: config.NewForTest(), - txProcessor: s.mockTxProcessor, - timerProcessor: s.mockTimerProcessor, - clientChecker: cc.NewVersionChecker(), - eventsReapplier: s.mockEventsReapplier, - workflowResetter: s.mockWorkflowResetter, - } - s.mockShard.SetEngine(h) - h.decisionHandler = decision.NewHandler(s.mockShard, h.executionCache, h.tokenSerializer) - - h.historyEventNotifier.Start() - - s.mockHistoryEngine = h -} - -func (s *engineSuite) TearDownTest() { - s.controller.Finish() - s.mockShard.Finish(s.T()) - s.mockHistoryEngine.historyEventNotifier.Stop() -} - -func (s *engineSuite) TestGetMutableStateSync() { - ctx := context.Background() - - workflowExecution := types.WorkflowExecution{ - WorkflowID: "test-get-workflow-execution-event-id", - RunID: constants.TestRunID, - } - tasklist := "testTaskList" - identity := "testIdentity" - - msBuilder := execution.NewMutableStateBuilderWithEventV2( - s.mockHistoryEngine.shard, - testlogger.New(s.Suite.T()), - workflowExecution.GetRunID(), - constants.TestLocalDomainEntry, - ) - test.AddWorkflowExecutionStartedEvent(msBuilder, workflowExecution, "wType", tasklist, []byte("input"), 100, 200, identity) - di := test.AddDecisionTaskScheduledEvent(msBuilder) - test.AddDecisionTaskStartedEvent(msBuilder, di.ScheduleID, tasklist, identity) - ms := execution.CreatePersistenceMutableState(msBuilder) - gweResponse := &persistence.GetWorkflowExecutionResponse{State: ms} - // right now the next event ID is 4 - s.mockExecutionMgr.On("GetWorkflowExecution", mock.Anything, mock.Anything).Return(gweResponse, nil).Once() - - // test get the next event ID instantly - response, err := s.mockHistoryEngine.GetMutableState(ctx, &types.GetMutableStateRequest{ - DomainUUID: constants.TestDomainID, - Execution: &workflowExecution, - }) - s.Nil(err) - s.Equal(int64(4), response.GetNextEventID()) -} - -func (s *engineSuite) TestGetMutableState_IntestRunID() { - ctx := context.Background() - - execution := types.WorkflowExecution{ - WorkflowID: "test-get-workflow-execution-event-id", - RunID: "run-id-not-valid-uuid", - } - - _, err := s.mockHistoryEngine.GetMutableState(ctx, &types.GetMutableStateRequest{ - DomainUUID: constants.TestDomainID, - Execution: &execution, - }) - s.Equal(constants.ErrRunIDNotValid, err) -} - -func (s *engineSuite) TestGetMutableState_EmptyRunID() { - ctx := context.Background() - - execution := types.WorkflowExecution{ - WorkflowID: "test-get-workflow-execution-event-id", - } - - s.mockExecutionMgr.On("GetCurrentExecution", mock.Anything, mock.Anything).Return(nil, &types.EntityNotExistsError{}).Once() - - _, err := s.mockHistoryEngine.GetMutableState(ctx, &types.GetMutableStateRequest{ - DomainUUID: constants.TestDomainID, - Execution: &execution, - }) - s.Equal(&types.EntityNotExistsError{}, err) -} - -func (s *engineSuite) TestGetMutableStateLongPoll() { - ctx := context.Background() - - workflowExecution := types.WorkflowExecution{ - WorkflowID: "test-get-workflow-execution-event-id", - RunID: constants.TestRunID, - } - tasklist := "testTaskList" - identity := "testIdentity" - - msBuilder := execution.NewMutableStateBuilderWithEventV2( - s.mockHistoryEngine.shard, - testlogger.New(s.Suite.T()), - workflowExecution.GetRunID(), - constants.TestLocalDomainEntry, - ) - test.AddWorkflowExecutionStartedEvent(msBuilder, workflowExecution, "wType", tasklist, []byte("input"), 100, 200, identity) - di := test.AddDecisionTaskScheduledEvent(msBuilder) - test.AddDecisionTaskStartedEvent(msBuilder, di.ScheduleID, tasklist, identity) - ms := execution.CreatePersistenceMutableState(msBuilder) - gweResponse := &persistence.GetWorkflowExecutionResponse{State: ms} - // right now the next event ID is 4 - s.mockExecutionMgr.On("GetWorkflowExecution", mock.Anything, mock.Anything).Return(gweResponse, nil).Once() - - // test long poll on next event ID change - waitGroup := &sync.WaitGroup{} - waitGroup.Add(1) - asycWorkflowUpdate := func(delay time.Duration) { - taskToken, _ := json.Marshal(&common.TaskToken{ - WorkflowID: workflowExecution.WorkflowID, - RunID: workflowExecution.RunID, - ScheduleID: 2, - }) - s.mockHistoryV2Mgr.On("AppendHistoryNodes", mock.Anything, mock.Anything).Return(&persistence.AppendHistoryNodesResponse{}, nil).Once() - s.mockExecutionMgr.On("UpdateWorkflowExecution", mock.Anything, mock.Anything).Return(&persistence.UpdateWorkflowExecutionResponse{MutableStateUpdateSessionStats: &persistence.MutableStateUpdateSessionStats{}}, nil).Once() - - timer := time.NewTimer(delay) - - <-timer.C - _, err := s.mockHistoryEngine.RespondDecisionTaskCompleted(context.Background(), &types.HistoryRespondDecisionTaskCompletedRequest{ - DomainUUID: constants.TestDomainID, - CompleteRequest: &types.RespondDecisionTaskCompletedRequest{ - TaskToken: taskToken, - Identity: identity, - }, - }) - s.Nil(err) - waitGroup.Done() - // right now the next event ID is 5 - } - - // return immediately, since the expected next event ID appears - response, err := s.mockHistoryEngine.GetMutableState(ctx, &types.GetMutableStateRequest{ - DomainUUID: constants.TestDomainID, - Execution: &workflowExecution, - ExpectedNextEventID: 3, - }) - s.Nil(err) - s.Equal(int64(4), response.NextEventID) - - // long poll, new event happen before long poll timeout - go asycWorkflowUpdate(time.Second * 2) - start := time.Now() - pollResponse, err := s.mockHistoryEngine.PollMutableState(ctx, &types.PollMutableStateRequest{ - DomainUUID: constants.TestDomainID, - Execution: &workflowExecution, - ExpectedNextEventID: 4, - }) - s.True(time.Now().After(start.Add(time.Second * 1))) - s.Nil(err) - s.Equal(int64(5), pollResponse.GetNextEventID()) - waitGroup.Wait() -} - -func (s *engineSuite) TestGetMutableStateLongPoll_CurrentBranchChanged() { - ctx := context.Background() - - workflowExecution := types.WorkflowExecution{ - WorkflowID: "test-get-workflow-execution-event-id", - RunID: constants.TestRunID, - } - tasklist := "testTaskList" - identity := "testIdentity" - - msBuilder := execution.NewMutableStateBuilderWithEventV2( - s.mockHistoryEngine.shard, - testlogger.New(s.Suite.T()), - workflowExecution.GetRunID(), - constants.TestLocalDomainEntry, - ) - test.AddWorkflowExecutionStartedEvent(msBuilder, workflowExecution, "wType", tasklist, []byte("input"), 100, 200, identity) - di := test.AddDecisionTaskScheduledEvent(msBuilder) - test.AddDecisionTaskStartedEvent(msBuilder, di.ScheduleID, tasklist, identity) - ms := execution.CreatePersistenceMutableState(msBuilder) - gweResponse := &persistence.GetWorkflowExecutionResponse{State: ms} - // right now the next event ID is 4 - s.mockExecutionMgr.On("GetWorkflowExecution", mock.Anything, mock.Anything).Return(gweResponse, nil).Once() - - // test long poll on next event ID change - asyncBranchTokenUpdate := func(delay time.Duration) { - timer := time.NewTimer(delay) - <-timer.C - newExecution := &types.WorkflowExecution{ - WorkflowID: workflowExecution.WorkflowID, - RunID: workflowExecution.RunID, - } - s.mockHistoryEngine.historyEventNotifier.NotifyNewHistoryEvent(events.NewNotification( - "constants.TestDomainID", - newExecution, - int64(1), - int64(4), - int64(1), - []byte{1}, - persistence.WorkflowStateCreated, - persistence.WorkflowCloseStatusNone)) - } - - // return immediately, since the expected next event ID appears - response0, err := s.mockHistoryEngine.GetMutableState(ctx, &types.GetMutableStateRequest{ - DomainUUID: constants.TestDomainID, - Execution: &workflowExecution, - ExpectedNextEventID: 3, - }) - s.Nil(err) - s.Equal(int64(4), response0.GetNextEventID()) - - // long poll, new event happen before long poll timeout - go asyncBranchTokenUpdate(time.Second * 2) - start := time.Now() - response1, err := s.mockHistoryEngine.GetMutableState(ctx, &types.GetMutableStateRequest{ - DomainUUID: constants.TestDomainID, - Execution: &workflowExecution, - ExpectedNextEventID: 10, - }) - s.True(time.Now().After(start.Add(time.Second * 1))) - s.Nil(err) - s.Equal(response0.GetCurrentBranchToken(), response1.GetCurrentBranchToken()) -} - -func (s *engineSuite) TestGetMutableStateLongPollTimeout() { - ctx := context.Background() - - workflowExecution := types.WorkflowExecution{ - WorkflowID: "test-get-workflow-execution-event-id", - RunID: constants.TestRunID, - } - tasklist := "testTaskList" - identity := "testIdentity" - - msBuilder := execution.NewMutableStateBuilderWithEventV2( - s.mockHistoryEngine.shard, - testlogger.New(s.Suite.T()), - workflowExecution.GetRunID(), - constants.TestLocalDomainEntry, - ) - test.AddWorkflowExecutionStartedEvent(msBuilder, workflowExecution, "wType", tasklist, []byte("input"), 100, 200, identity) - di := test.AddDecisionTaskScheduledEvent(msBuilder) - test.AddDecisionTaskStartedEvent(msBuilder, di.ScheduleID, tasklist, identity) - ms := execution.CreatePersistenceMutableState(msBuilder) - gweResponse := &persistence.GetWorkflowExecutionResponse{State: ms} - // right now the next event ID is 4 - s.mockExecutionMgr.On("GetWorkflowExecution", mock.Anything, mock.Anything).Return(gweResponse, nil).Once() - - // long poll, no event happen after long poll timeout - response, err := s.mockHistoryEngine.GetMutableState(ctx, &types.GetMutableStateRequest{ - DomainUUID: constants.TestDomainID, - Execution: &workflowExecution, - ExpectedNextEventID: 4, - }) - s.Nil(err) - s.Equal(int64(4), response.GetNextEventID()) -} - -func (s *engineSuite) TestQueryWorkflow_RejectBasedOnNotEnabled() { - s.mockHistoryEngine.config.EnableConsistentQueryByDomain = dynamicconfig.GetBoolPropertyFnFilteredByDomain(false) - request := &types.HistoryQueryWorkflowRequest{ - DomainUUID: constants.TestDomainID, - Request: &types.QueryWorkflowRequest{ - QueryConsistencyLevel: types.QueryConsistencyLevelStrong.Ptr(), - }, - } - resp, err := s.mockHistoryEngine.QueryWorkflow(context.Background(), request) - s.Nil(resp) - s.Equal(workflow.ErrConsistentQueryNotEnabled, err) - - s.mockHistoryEngine.config.EnableConsistentQueryByDomain = dynamicconfig.GetBoolPropertyFnFilteredByDomain(true) - s.mockHistoryEngine.config.EnableConsistentQuery = dynamicconfig.GetBoolPropertyFn(false) - resp, err = s.mockHistoryEngine.QueryWorkflow(context.Background(), request) - s.Nil(resp) - s.Equal(workflow.ErrConsistentQueryNotEnabled, err) -} - -func (s *engineSuite) TestQueryWorkflow_RejectBasedOnCompleted() { - workflowExecution := types.WorkflowExecution{ - WorkflowID: "TestQueryWorkflow_RejectBasedOnCompleted", - RunID: constants.TestRunID, - } - tasklist := "testTaskList" - identity := "testIdentity" - - msBuilder := execution.NewMutableStateBuilderWithEventV2( - s.mockHistoryEngine.shard, - testlogger.New(s.Suite.T()), - workflowExecution.GetRunID(), - constants.TestLocalDomainEntry, - ) - test.AddWorkflowExecutionStartedEvent(msBuilder, workflowExecution, "wType", tasklist, []byte("input"), 100, 200, identity) - di := test.AddDecisionTaskScheduledEvent(msBuilder) - event := test.AddDecisionTaskStartedEvent(msBuilder, di.ScheduleID, tasklist, identity) - di.StartedID = event.ID - event = test.AddDecisionTaskCompletedEvent(msBuilder, di.ScheduleID, di.StartedID, nil, "some random identity") - test.AddCompleteWorkflowEvent(msBuilder, event.ID, nil) - ms := execution.CreatePersistenceMutableState(msBuilder) - gweResponse := &persistence.GetWorkflowExecutionResponse{State: ms} - s.mockExecutionMgr.On("GetWorkflowExecution", mock.Anything, mock.Anything).Return(gweResponse, nil).Once() - - request := &types.HistoryQueryWorkflowRequest{ - DomainUUID: constants.TestDomainID, - Request: &types.QueryWorkflowRequest{ - Execution: &workflowExecution, - Query: &types.WorkflowQuery{}, - QueryRejectCondition: types.QueryRejectConditionNotOpen.Ptr(), - }, - } - resp, err := s.mockHistoryEngine.QueryWorkflow(context.Background(), request) - s.NoError(err) - s.Nil(resp.GetResponse().QueryResult) - s.NotNil(resp.GetResponse().QueryRejected) - s.Equal(types.WorkflowExecutionCloseStatusCompleted.Ptr(), resp.GetResponse().GetQueryRejected().CloseStatus) -} - -func (s *engineSuite) TestQueryWorkflow_RejectBasedOnFailed() { - workflowExecution := types.WorkflowExecution{ - WorkflowID: "TestQueryWorkflow_RejectBasedOnFailed", - RunID: constants.TestRunID, - } - tasklist := "testTaskList" - identity := "testIdentity" - - msBuilder := execution.NewMutableStateBuilderWithEventV2( - s.mockHistoryEngine.shard, - testlogger.New(s.Suite.T()), - workflowExecution.GetRunID(), - constants.TestLocalDomainEntry, - ) - test.AddWorkflowExecutionStartedEvent(msBuilder, workflowExecution, "wType", tasklist, []byte("input"), 100, 200, identity) - di := test.AddDecisionTaskScheduledEvent(msBuilder) - event := test.AddDecisionTaskStartedEvent(msBuilder, di.ScheduleID, tasklist, identity) - di.StartedID = event.ID - event = test.AddDecisionTaskCompletedEvent(msBuilder, di.ScheduleID, di.StartedID, nil, "some random identity") - test.AddFailWorkflowEvent(msBuilder, event.ID, "failure reason", []byte{1, 2, 3}) - ms := execution.CreatePersistenceMutableState(msBuilder) - gweResponse := &persistence.GetWorkflowExecutionResponse{State: ms} - s.mockExecutionMgr.On("GetWorkflowExecution", mock.Anything, mock.Anything).Return(gweResponse, nil).Once() - - request := &types.HistoryQueryWorkflowRequest{ - DomainUUID: constants.TestDomainID, - Request: &types.QueryWorkflowRequest{ - Execution: &workflowExecution, - Query: &types.WorkflowQuery{}, - QueryRejectCondition: types.QueryRejectConditionNotOpen.Ptr(), - }, - } - resp, err := s.mockHistoryEngine.QueryWorkflow(context.Background(), request) - s.NoError(err) - s.Nil(resp.GetResponse().QueryResult) - s.NotNil(resp.GetResponse().QueryRejected) - s.Equal(types.WorkflowExecutionCloseStatusFailed.Ptr(), resp.GetResponse().GetQueryRejected().CloseStatus) - - request = &types.HistoryQueryWorkflowRequest{ - DomainUUID: constants.TestDomainID, - Request: &types.QueryWorkflowRequest{ - Execution: &workflowExecution, - Query: &types.WorkflowQuery{}, - QueryRejectCondition: types.QueryRejectConditionNotCompletedCleanly.Ptr(), - }, - } - resp, err = s.mockHistoryEngine.QueryWorkflow(context.Background(), request) - s.NoError(err) - s.Nil(resp.GetResponse().QueryResult) - s.NotNil(resp.GetResponse().QueryRejected) - s.Equal(types.WorkflowExecutionCloseStatusFailed.Ptr(), resp.GetResponse().GetQueryRejected().CloseStatus) -} - -func (s *engineSuite) TestQueryWorkflow_FirstDecisionNotCompleted() { - workflowExecution := types.WorkflowExecution{ - WorkflowID: "TestQueryWorkflow_FirstDecisionNotCompleted", - RunID: constants.TestRunID, - } - tasklist := "testTaskList" - identity := "testIdentity" - - msBuilder := execution.NewMutableStateBuilderWithEventV2( - s.mockHistoryEngine.shard, - testlogger.New(s.Suite.T()), - workflowExecution.GetRunID(), - constants.TestLocalDomainEntry, - ) - test.AddWorkflowExecutionStartedEvent(msBuilder, workflowExecution, "wType", tasklist, []byte("input"), 100, 200, identity) - di := test.AddDecisionTaskScheduledEvent(msBuilder) - test.AddDecisionTaskStartedEvent(msBuilder, di.ScheduleID, tasklist, identity) - ms := execution.CreatePersistenceMutableState(msBuilder) - gweResponse := &persistence.GetWorkflowExecutionResponse{State: ms} - s.mockExecutionMgr.On("GetWorkflowExecution", mock.Anything, mock.Anything).Return(gweResponse, nil).Once() - - request := &types.HistoryQueryWorkflowRequest{ - DomainUUID: constants.TestDomainID, - Request: &types.QueryWorkflowRequest{ - Execution: &workflowExecution, - Query: &types.WorkflowQuery{}, - }, - } - resp, err := s.mockHistoryEngine.QueryWorkflow(context.Background(), request) - s.Equal(workflow.ErrQueryWorkflowBeforeFirstDecision, err) - s.Nil(resp) -} - -func (s *engineSuite) TestQueryWorkflow_DirectlyThroughMatching() { - workflowExecution := types.WorkflowExecution{ - WorkflowID: "TestQueryWorkflow_DirectlyThroughMatching", - RunID: constants.TestRunID, - } - tasklist := "testTaskList" - identity := "testIdentity" - - msBuilder := execution.NewMutableStateBuilderWithEventV2( - s.mockHistoryEngine.shard, - testlogger.New(s.Suite.T()), - workflowExecution.GetRunID(), - constants.TestLocalDomainEntry, - ) - test.AddWorkflowExecutionStartedEvent(msBuilder, workflowExecution, "wType", tasklist, []byte("input"), 100, 200, identity) - di := test.AddDecisionTaskScheduledEvent(msBuilder) - startedEvent := test.AddDecisionTaskStartedEvent(msBuilder, di.ScheduleID, tasklist, identity) - test.AddDecisionTaskCompletedEvent(msBuilder, di.ScheduleID, startedEvent.ID, nil, identity) - di = test.AddDecisionTaskScheduledEvent(msBuilder) - test.AddDecisionTaskStartedEvent(msBuilder, di.ScheduleID, tasklist, identity) - - ms := execution.CreatePersistenceMutableState(msBuilder) - gweResponse := &persistence.GetWorkflowExecutionResponse{State: ms} - s.mockExecutionMgr.On("GetWorkflowExecution", mock.Anything, mock.Anything).Return(gweResponse, nil).Once() - s.mockMatchingClient.EXPECT().QueryWorkflow(gomock.Any(), gomock.Any()).Return(&types.QueryWorkflowResponse{QueryResult: []byte{1, 2, 3}}, nil) - s.mockHistoryEngine.matchingClient = s.mockMatchingClient - request := &types.HistoryQueryWorkflowRequest{ - DomainUUID: constants.TestDomainID, - Request: &types.QueryWorkflowRequest{ - Execution: &workflowExecution, - Query: &types.WorkflowQuery{}, - // since workflow is open this filter does not reject query - QueryRejectCondition: types.QueryRejectConditionNotOpen.Ptr(), - QueryConsistencyLevel: types.QueryConsistencyLevelEventual.Ptr(), - }, - } - resp, err := s.mockHistoryEngine.QueryWorkflow(context.Background(), request) - s.NoError(err) - s.NotNil(resp.GetResponse().QueryResult) - s.Nil(resp.GetResponse().QueryRejected) - s.Equal([]byte{1, 2, 3}, resp.GetResponse().GetQueryResult()) -} - -func (s *engineSuite) TestQueryWorkflow_DecisionTaskDispatch_Timeout() { - workflowExecution := types.WorkflowExecution{ - WorkflowID: "TestQueryWorkflow_DecisionTaskDispatch_Timeout", - RunID: constants.TestRunID, - } - tasklist := "testTaskList" - identity := "testIdentity" - msBuilder := execution.NewMutableStateBuilderWithEventV2( - s.mockHistoryEngine.shard, - testlogger.New(s.Suite.T()), - workflowExecution.GetRunID(), - constants.TestLocalDomainEntry, - ) - test.AddWorkflowExecutionStartedEvent(msBuilder, workflowExecution, "wType", tasklist, []byte("input"), 100, 200, identity) - di := test.AddDecisionTaskScheduledEvent(msBuilder) - startedEvent := test.AddDecisionTaskStartedEvent(msBuilder, di.ScheduleID, tasklist, identity) - test.AddDecisionTaskCompletedEvent(msBuilder, di.ScheduleID, startedEvent.ID, nil, identity) - di = test.AddDecisionTaskScheduledEvent(msBuilder) - test.AddDecisionTaskStartedEvent(msBuilder, di.ScheduleID, tasklist, identity) - - ms := execution.CreatePersistenceMutableState(msBuilder) - gweResponse := &persistence.GetWorkflowExecutionResponse{State: ms} - s.mockExecutionMgr.On("GetWorkflowExecution", mock.Anything, mock.Anything).Return(gweResponse, nil).Once() - request := &types.HistoryQueryWorkflowRequest{ - DomainUUID: constants.TestDomainID, - Request: &types.QueryWorkflowRequest{ - Execution: &workflowExecution, - Query: &types.WorkflowQuery{}, - // since workflow is open this filter does not reject query - QueryRejectCondition: types.QueryRejectConditionNotOpen.Ptr(), - QueryConsistencyLevel: types.QueryConsistencyLevelStrong.Ptr(), - }, - } - - wg := &sync.WaitGroup{} - wg.Add(1) - go func() { - ctx, cancel := context.WithTimeout(context.Background(), time.Second*2) - defer cancel() - resp, err := s.mockHistoryEngine.QueryWorkflow(ctx, request) - s.Error(err) - s.Nil(resp) - wg.Done() - }() - - <-time.After(time.Second) - builder := s.getBuilder(constants.TestDomainID, workflowExecution) - s.NotNil(builder) - qr := builder.GetQueryRegistry() - s.True(qr.HasBufferedQuery()) - s.False(qr.HasCompletedQuery()) - s.False(qr.HasUnblockedQuery()) - s.False(qr.HasFailedQuery()) - wg.Wait() - s.False(qr.HasBufferedQuery()) - s.False(qr.HasCompletedQuery()) - s.False(qr.HasUnblockedQuery()) - s.False(qr.HasFailedQuery()) -} - -func (s *engineSuite) TestQueryWorkflow_ConsistentQueryBufferFull() { - workflowExecution := types.WorkflowExecution{ - WorkflowID: "TestQueryWorkflow_ConsistentQueryBufferFull", - RunID: constants.TestRunID, - } - tasklist := "testTaskList" - identity := "testIdentity" - msBuilder := execution.NewMutableStateBuilderWithEventV2( - s.mockHistoryEngine.shard, - testlogger.New(s.Suite.T()), - workflowExecution.GetRunID(), - constants.TestLocalDomainEntry, - ) - test.AddWorkflowExecutionStartedEvent(msBuilder, workflowExecution, "wType", tasklist, []byte("input"), 100, 200, identity) - di := test.AddDecisionTaskScheduledEvent(msBuilder) - startedEvent := test.AddDecisionTaskStartedEvent(msBuilder, di.ScheduleID, tasklist, identity) - test.AddDecisionTaskCompletedEvent(msBuilder, di.ScheduleID, startedEvent.ID, nil, identity) - di = test.AddDecisionTaskScheduledEvent(msBuilder) - test.AddDecisionTaskStartedEvent(msBuilder, di.ScheduleID, tasklist, identity) - - ms := execution.CreatePersistenceMutableState(msBuilder) - gweResponse := &persistence.GetWorkflowExecutionResponse{State: ms} - s.mockExecutionMgr.On("GetWorkflowExecution", mock.Anything, mock.Anything).Return(gweResponse, nil).Once() - - // buffer query so that when types.QueryWorkflow is called buffer is already full - ctx, release, err := s.mockHistoryEngine.executionCache.GetOrCreateWorkflowExecutionForBackground(constants.TestDomainID, workflowExecution) - s.NoError(err) - loadedMS, err := ctx.LoadWorkflowExecution(context.Background()) - s.NoError(err) - qr := query.NewRegistry() - qr.BufferQuery(&types.WorkflowQuery{}) - loadedMS.SetQueryRegistry(qr) - release(nil) - - request := &types.HistoryQueryWorkflowRequest{ - DomainUUID: constants.TestDomainID, - Request: &types.QueryWorkflowRequest{ - Execution: &workflowExecution, - Query: &types.WorkflowQuery{}, - QueryConsistencyLevel: types.QueryConsistencyLevelStrong.Ptr(), - }, - } - resp, err := s.mockHistoryEngine.QueryWorkflow(context.Background(), request) - s.Nil(resp) - s.Equal(workflow.ErrConsistentQueryBufferExceeded, err) -} - -func (s *engineSuite) TestQueryWorkflow_DecisionTaskDispatch_Complete() { - workflowExecution := types.WorkflowExecution{ - WorkflowID: "TestQueryWorkflow_DecisionTaskDispatch_Complete", - RunID: constants.TestRunID, - } - tasklist := "testTaskList" - identity := "testIdentity" - msBuilder := execution.NewMutableStateBuilderWithEventV2( - s.mockHistoryEngine.shard, - testlogger.New(s.Suite.T()), - workflowExecution.GetRunID(), - constants.TestLocalDomainEntry, - ) - test.AddWorkflowExecutionStartedEvent(msBuilder, workflowExecution, "wType", tasklist, []byte("input"), 100, 200, identity) - di := test.AddDecisionTaskScheduledEvent(msBuilder) - startedEvent := test.AddDecisionTaskStartedEvent(msBuilder, di.ScheduleID, tasklist, identity) - test.AddDecisionTaskCompletedEvent(msBuilder, di.ScheduleID, startedEvent.ID, nil, identity) - di = test.AddDecisionTaskScheduledEvent(msBuilder) - test.AddDecisionTaskStartedEvent(msBuilder, di.ScheduleID, tasklist, identity) - - ms := execution.CreatePersistenceMutableState(msBuilder) - gweResponse := &persistence.GetWorkflowExecutionResponse{State: ms} - s.mockExecutionMgr.On("GetWorkflowExecution", mock.Anything, mock.Anything).Return(gweResponse, nil).Once() - - waitGroup := &sync.WaitGroup{} - waitGroup.Add(1) - asyncQueryUpdate := func(delay time.Duration, answer []byte) { - defer waitGroup.Done() - <-time.After(delay) - builder := s.getBuilder(constants.TestDomainID, workflowExecution) - s.NotNil(builder) - qr := builder.GetQueryRegistry() - buffered := qr.GetBufferedIDs() - for _, id := range buffered { - resultType := types.QueryResultTypeAnswered - completedTerminationState := &query.TerminationState{ - TerminationType: query.TerminationTypeCompleted, - QueryResult: &types.WorkflowQueryResult{ - ResultType: &resultType, - Answer: answer, - }, - } - err := qr.SetTerminationState(id, completedTerminationState) - s.NoError(err) - state, err := qr.GetTerminationState(id) - s.NoError(err) - s.Equal(query.TerminationTypeCompleted, state.TerminationType) - } - } - - request := &types.HistoryQueryWorkflowRequest{ - DomainUUID: constants.TestDomainID, - Request: &types.QueryWorkflowRequest{ - Execution: &workflowExecution, - Query: &types.WorkflowQuery{}, - QueryConsistencyLevel: types.QueryConsistencyLevelStrong.Ptr(), - }, - } - go asyncQueryUpdate(time.Second*2, []byte{1, 2, 3}) - start := time.Now() - resp, err := s.mockHistoryEngine.QueryWorkflow(context.Background(), request) - s.True(time.Now().After(start.Add(time.Second))) - s.NoError(err) - s.Equal([]byte{1, 2, 3}, resp.GetResponse().GetQueryResult()) - builder := s.getBuilder(constants.TestDomainID, workflowExecution) - s.NotNil(builder) - qr := builder.GetQueryRegistry() - s.False(qr.HasBufferedQuery()) - s.False(qr.HasCompletedQuery()) - waitGroup.Wait() -} - -func (s *engineSuite) TestQueryWorkflow_DecisionTaskDispatch_Unblocked() { - workflowExecution := types.WorkflowExecution{ - WorkflowID: "TestQueryWorkflow_DecisionTaskDispatch_Unblocked", - RunID: constants.TestRunID, - } - tasklist := "testTaskList" - identity := "testIdentity" - msBuilder := execution.NewMutableStateBuilderWithEventV2( - s.mockHistoryEngine.shard, - testlogger.New(s.Suite.T()), - workflowExecution.GetRunID(), - constants.TestLocalDomainEntry, - ) - test.AddWorkflowExecutionStartedEvent(msBuilder, workflowExecution, "wType", tasklist, []byte("input"), 100, 200, identity) - di := test.AddDecisionTaskScheduledEvent(msBuilder) - startedEvent := test.AddDecisionTaskStartedEvent(msBuilder, di.ScheduleID, tasklist, identity) - test.AddDecisionTaskCompletedEvent(msBuilder, di.ScheduleID, startedEvent.ID, nil, identity) - di = test.AddDecisionTaskScheduledEvent(msBuilder) - test.AddDecisionTaskStartedEvent(msBuilder, di.ScheduleID, tasklist, identity) - - ms := execution.CreatePersistenceMutableState(msBuilder) - gweResponse := &persistence.GetWorkflowExecutionResponse{State: ms} - s.mockExecutionMgr.On("GetWorkflowExecution", mock.Anything, mock.Anything).Return(gweResponse, nil).Once() - s.mockMatchingClient.EXPECT().QueryWorkflow(gomock.Any(), gomock.Any()).Return(&types.QueryWorkflowResponse{QueryResult: []byte{1, 2, 3}}, nil) - s.mockHistoryEngine.matchingClient = s.mockMatchingClient - waitGroup := &sync.WaitGroup{} - waitGroup.Add(1) - asyncQueryUpdate := func(delay time.Duration, answer []byte) { - defer waitGroup.Done() - <-time.After(delay) - builder := s.getBuilder(constants.TestDomainID, workflowExecution) - s.NotNil(builder) - qr := builder.GetQueryRegistry() - buffered := qr.GetBufferedIDs() - for _, id := range buffered { - s.NoError(qr.SetTerminationState(id, &query.TerminationState{TerminationType: query.TerminationTypeUnblocked})) - state, err := qr.GetTerminationState(id) - s.NoError(err) - s.Equal(query.TerminationTypeUnblocked, state.TerminationType) - } - } - - request := &types.HistoryQueryWorkflowRequest{ - DomainUUID: constants.TestDomainID, - Request: &types.QueryWorkflowRequest{ - Execution: &workflowExecution, - Query: &types.WorkflowQuery{}, - QueryConsistencyLevel: types.QueryConsistencyLevelStrong.Ptr(), - }, - } - go asyncQueryUpdate(time.Second*2, []byte{1, 2, 3}) - start := time.Now() - resp, err := s.mockHistoryEngine.QueryWorkflow(context.Background(), request) - s.True(time.Now().After(start.Add(time.Second))) - s.NoError(err) - s.Equal([]byte{1, 2, 3}, resp.GetResponse().GetQueryResult()) - builder := s.getBuilder(constants.TestDomainID, workflowExecution) - s.NotNil(builder) - qr := builder.GetQueryRegistry() - s.False(qr.HasBufferedQuery()) - s.False(qr.HasCompletedQuery()) - s.False(qr.HasUnblockedQuery()) - waitGroup.Wait() -} - -func (s *engineSuite) TestRespondDecisionTaskCompletedInvalidToken() { - - invalidToken, _ := json.Marshal("bad token") - identity := "testIdentity" - - _, err := s.mockHistoryEngine.RespondDecisionTaskCompleted(context.Background(), &types.HistoryRespondDecisionTaskCompletedRequest{ - DomainUUID: constants.TestDomainID, - CompleteRequest: &types.RespondDecisionTaskCompletedRequest{ - TaskToken: invalidToken, - Decisions: nil, - ExecutionContext: nil, - Identity: identity, - }, - }) - - s.NotNil(err) - s.IsType(&types.BadRequestError{}, err) -} - -func (s *engineSuite) TestRespondDecisionTaskCompletedIfNoExecution() { - - taskToken, _ := json.Marshal(&common.TaskToken{ - WorkflowID: "wId", - RunID: constants.TestRunID, - ScheduleID: 2, - }) - identity := "testIdentity" - - s.mockExecutionMgr.On("GetWorkflowExecution", mock.Anything, mock.Anything).Return(nil, &types.EntityNotExistsError{}).Once() - - _, err := s.mockHistoryEngine.RespondDecisionTaskCompleted(context.Background(), &types.HistoryRespondDecisionTaskCompletedRequest{ - DomainUUID: constants.TestDomainID, - CompleteRequest: &types.RespondDecisionTaskCompletedRequest{ - TaskToken: taskToken, - Identity: identity, - }, - }) - s.NotNil(err) - s.IsType(&types.EntityNotExistsError{}, err) -} - -func (s *engineSuite) TestRespondDecisionTaskCompletedIfGetExecutionFailed() { - - taskToken, _ := json.Marshal(&common.TaskToken{ - WorkflowID: "wId", - RunID: constants.TestRunID, - ScheduleID: 2, - }) - identity := "testIdentity" - - s.mockExecutionMgr.On("GetWorkflowExecution", mock.Anything, mock.Anything).Return(nil, errors.New("FAILED")).Once() - - _, err := s.mockHistoryEngine.RespondDecisionTaskCompleted(context.Background(), &types.HistoryRespondDecisionTaskCompletedRequest{ - DomainUUID: constants.TestDomainID, - CompleteRequest: &types.RespondDecisionTaskCompletedRequest{ - TaskToken: taskToken, - Identity: identity, - }, - }) - s.EqualError(err, "FAILED") -} - -func (s *engineSuite) TestRespondDecisionTaskCompletedUpdateExecutionFailed() { - - we := types.WorkflowExecution{ - WorkflowID: "wId", - RunID: constants.TestRunID, - } - tl := "testTaskList" - - taskToken, _ := json.Marshal(&common.TaskToken{ - WorkflowID: we.WorkflowID, - RunID: we.RunID, - ScheduleID: 2, - }) - identity := "testIdentity" - - msBuilder := execution.NewMutableStateBuilderWithEventV2( - s.mockHistoryEngine.shard, - testlogger.New(s.Suite.T()), - we.GetRunID(), - constants.TestLocalDomainEntry, - ) - test.AddWorkflowExecutionStartedEvent(msBuilder, we, "wType", tl, []byte("input"), 100, 200, identity) - di := test.AddDecisionTaskScheduledEvent(msBuilder) - test.AddDecisionTaskStartedEvent(msBuilder, di.ScheduleID, tl, identity) - - ms := execution.CreatePersistenceMutableState(msBuilder) - gwmsResponse := &persistence.GetWorkflowExecutionResponse{State: ms} - - s.mockExecutionMgr.On("GetWorkflowExecution", mock.Anything, mock.Anything).Return(gwmsResponse, nil).Once() - s.mockHistoryV2Mgr.On("AppendHistoryNodes", mock.Anything, mock.Anything).Return(&persistence.AppendHistoryNodesResponse{}, nil).Once() - s.mockExecutionMgr.On("UpdateWorkflowExecution", mock.Anything, mock.Anything).Return(&persistence.UpdateWorkflowExecutionResponse{MutableStateUpdateSessionStats: &persistence.MutableStateUpdateSessionStats{}}, errors.New("FAILED")).Once() - s.mockShardManager.On("UpdateShard", mock.Anything, mock.Anything).Return(nil).Once() - - _, err := s.mockHistoryEngine.RespondDecisionTaskCompleted(context.Background(), &types.HistoryRespondDecisionTaskCompletedRequest{ - DomainUUID: constants.TestDomainID, - CompleteRequest: &types.RespondDecisionTaskCompletedRequest{ - TaskToken: taskToken, - Identity: identity, - }, - }) - s.NotNil(err) - s.EqualError(err, "FAILED") -} - -func (s *engineSuite) TestRespondDecisionTaskCompletedIfTaskCompleted() { - - we := types.WorkflowExecution{ - WorkflowID: "wId", - RunID: constants.TestRunID, - } - tl := "testTaskList" - taskToken, _ := json.Marshal(&common.TaskToken{ - WorkflowID: we.WorkflowID, - RunID: we.RunID, - ScheduleID: 2, - }) - identity := "testIdentity" - - msBuilder := execution.NewMutableStateBuilderWithEventV2( - s.mockHistoryEngine.shard, - testlogger.New(s.Suite.T()), - we.GetRunID(), - constants.TestLocalDomainEntry, - ) - test.AddWorkflowExecutionStartedEvent(msBuilder, we, "wType", tl, []byte("input"), 100, 200, identity) - di := test.AddDecisionTaskScheduledEvent(msBuilder) - startedEvent := test.AddDecisionTaskStartedEvent(msBuilder, di.ScheduleID, tl, identity) - test.AddDecisionTaskCompletedEvent(msBuilder, di.ScheduleID, startedEvent.ID, nil, identity) - - ms := execution.CreatePersistenceMutableState(msBuilder) - gwmsResponse := &persistence.GetWorkflowExecutionResponse{State: ms} - - s.mockExecutionMgr.On("GetWorkflowExecution", mock.Anything, mock.Anything).Return(gwmsResponse, nil).Once() - - _, err := s.mockHistoryEngine.RespondDecisionTaskCompleted(context.Background(), &types.HistoryRespondDecisionTaskCompletedRequest{ - DomainUUID: constants.TestDomainID, - CompleteRequest: &types.RespondDecisionTaskCompletedRequest{ - TaskToken: taskToken, - Identity: identity, - }, - }) - s.NotNil(err) - s.IsType(&types.EntityNotExistsError{}, err) -} - -func (s *engineSuite) TestRespondDecisionTaskCompletedIfTaskNotStarted() { - - we := types.WorkflowExecution{ - WorkflowID: "wId", - RunID: constants.TestRunID, - } - tl := "testTaskList" - taskToken, _ := json.Marshal(&common.TaskToken{ - WorkflowID: we.WorkflowID, - RunID: we.RunID, - ScheduleID: 2, - }) - identity := "testIdentity" - - msBuilder := execution.NewMutableStateBuilderWithEventV2( - s.mockHistoryEngine.shard, - testlogger.New(s.Suite.T()), - we.GetRunID(), - constants.TestLocalDomainEntry, - ) - test.AddWorkflowExecutionStartedEvent(msBuilder, we, "wType", tl, []byte("input"), 100, 200, identity) - test.AddDecisionTaskScheduledEvent(msBuilder) - - ms := execution.CreatePersistenceMutableState(msBuilder) - gwmsResponse := &persistence.GetWorkflowExecutionResponse{State: ms} - - s.mockExecutionMgr.On("GetWorkflowExecution", mock.Anything, mock.Anything).Return(gwmsResponse, nil).Once() - - _, err := s.mockHistoryEngine.RespondDecisionTaskCompleted(context.Background(), &types.HistoryRespondDecisionTaskCompletedRequest{ - DomainUUID: constants.TestDomainID, - CompleteRequest: &types.RespondDecisionTaskCompletedRequest{ - TaskToken: taskToken, - }, - }) - s.NotNil(err) - s.IsType(&types.EntityNotExistsError{}, err) -} - -func (s *engineSuite) TestRespondDecisionTaskCompletedConflictOnUpdate() { - - we := types.WorkflowExecution{ - WorkflowID: "wId", - RunID: constants.TestRunID, - } - tl := "testTaskList" - identity := "testIdentity" - executionContext := []byte("context") - activity1ID := "activity1" - activity1Type := "activity_type1" - activity1Input := []byte("input1") - activity1Result := []byte("activity1_result") - activity2ID := "activity2" - activity2Type := "activity_type2" - activity2Input := []byte("input2") - activity2Result := []byte("activity2_result") - activity3ID := "activity3" - activity3Type := "activity_type3" - activity3Input := []byte("input3") - - msBuilder := execution.NewMutableStateBuilderWithEventV2( - s.mockHistoryEngine.shard, - testlogger.New(s.Suite.T()), - we.GetRunID(), - constants.TestLocalDomainEntry, - ) - test.AddWorkflowExecutionStartedEvent(msBuilder, we, "wType", tl, []byte("input"), 100, 100, identity) - di1 := test.AddDecisionTaskScheduledEvent(msBuilder) - decisionStartedEvent1 := test.AddDecisionTaskStartedEvent(msBuilder, di1.ScheduleID, tl, identity) - decisionCompletedEvent1 := test.AddDecisionTaskCompletedEvent(msBuilder, di1.ScheduleID, - decisionStartedEvent1.ID, nil, identity) - activity1ScheduledEvent, _ := test.AddActivityTaskScheduledEvent(msBuilder, decisionCompletedEvent1.ID, - activity1ID, activity1Type, tl, activity1Input, 100, 10, 1, 5) - activity2ScheduledEvent, _ := test.AddActivityTaskScheduledEvent(msBuilder, decisionCompletedEvent1.ID, - activity2ID, activity2Type, tl, activity2Input, 100, 10, 1, 5) - activity1StartedEvent := test.AddActivityTaskStartedEvent(msBuilder, activity1ScheduledEvent.ID, identity) - activity2StartedEvent := test.AddActivityTaskStartedEvent(msBuilder, activity2ScheduledEvent.ID, identity) - test.AddActivityTaskCompletedEvent(msBuilder, activity1ScheduledEvent.ID, - activity1StartedEvent.ID, activity1Result, identity) - di2 := test.AddDecisionTaskScheduledEvent(msBuilder) - decisionStartedEvent2 := test.AddDecisionTaskStartedEvent(msBuilder, di2.ScheduleID, tl, identity) - - taskToken, _ := json.Marshal(&common.TaskToken{ - WorkflowID: "wId", - RunID: we.GetRunID(), - ScheduleID: di2.ScheduleID, - }) - - decisions := []*types.Decision{{ - DecisionType: types.DecisionTypeScheduleActivityTask.Ptr(), - ScheduleActivityTaskDecisionAttributes: &types.ScheduleActivityTaskDecisionAttributes{ - ActivityID: activity3ID, - ActivityType: &types.ActivityType{Name: activity3Type}, - TaskList: &types.TaskList{Name: tl}, - Input: activity3Input, - ScheduleToCloseTimeoutSeconds: common.Int32Ptr(100), - ScheduleToStartTimeoutSeconds: common.Int32Ptr(10), - StartToCloseTimeoutSeconds: common.Int32Ptr(50), - HeartbeatTimeoutSeconds: common.Int32Ptr(5), - }, - }} - - ms := execution.CreatePersistenceMutableState(msBuilder) - gwmsResponse := &persistence.GetWorkflowExecutionResponse{State: ms} - - test.AddActivityTaskCompletedEvent(msBuilder, activity2ScheduledEvent.ID, - activity2StartedEvent.ID, activity2Result, identity) - - ms2 := execution.CreatePersistenceMutableState(msBuilder) - gwmsResponse2 := &persistence.GetWorkflowExecutionResponse{State: ms2} - - s.mockExecutionMgr.On("GetWorkflowExecution", mock.Anything, mock.Anything).Return(gwmsResponse, nil).Once() - s.mockHistoryV2Mgr.On("AppendHistoryNodes", mock.Anything, mock.Anything).Return(&persistence.AppendHistoryNodesResponse{}, nil).Once() - s.mockExecutionMgr.On("UpdateWorkflowExecution", mock.Anything, mock.Anything).Return(&persistence.UpdateWorkflowExecutionResponse{MutableStateUpdateSessionStats: &persistence.MutableStateUpdateSessionStats{}}, - &persistence.ConditionFailedError{}).Once() - - s.mockExecutionMgr.On("GetWorkflowExecution", mock.Anything, mock.Anything).Return(gwmsResponse2, nil).Once() - s.mockHistoryV2Mgr.On("AppendHistoryNodes", mock.Anything, mock.Anything).Return(&persistence.AppendHistoryNodesResponse{}, nil).Once() - s.mockExecutionMgr.On("UpdateWorkflowExecution", mock.Anything, mock.Anything).Return(&persistence.UpdateWorkflowExecutionResponse{MutableStateUpdateSessionStats: &persistence.MutableStateUpdateSessionStats{}}, nil).Once() - - _, err := s.mockHistoryEngine.RespondDecisionTaskCompleted(context.Background(), &types.HistoryRespondDecisionTaskCompletedRequest{ - DomainUUID: constants.TestDomainID, - CompleteRequest: &types.RespondDecisionTaskCompletedRequest{ - TaskToken: taskToken, - Decisions: decisions, - ExecutionContext: executionContext, - Identity: identity, - }, - }) - s.Nil(err, s.printHistory(msBuilder)) - s.Equal(int64(16), ms2.ExecutionInfo.NextEventID) - s.Equal(decisionStartedEvent2.ID, ms2.ExecutionInfo.LastProcessedEvent) - s.Equal(executionContext, ms2.ExecutionInfo.ExecutionContext) - - executionBuilder := s.getBuilder(constants.TestDomainID, we) - activity3Attributes := s.getActivityScheduledEvent(executionBuilder, 13).ActivityTaskScheduledEventAttributes - s.Equal(activity3ID, activity3Attributes.ActivityID) - s.Equal(activity3Type, activity3Attributes.ActivityType.Name) - s.Equal(int64(12), activity3Attributes.DecisionTaskCompletedEventID) - s.Equal(tl, activity3Attributes.TaskList.Name) - s.Equal(activity3Input, activity3Attributes.Input) - s.Equal(int32(100), *activity3Attributes.ScheduleToCloseTimeoutSeconds) - s.Equal(int32(10), *activity3Attributes.ScheduleToStartTimeoutSeconds) - s.Equal(int32(50), *activity3Attributes.StartToCloseTimeoutSeconds) - s.Equal(int32(5), *activity3Attributes.HeartbeatTimeoutSeconds) - - di, ok := executionBuilder.GetDecisionInfo(15) - s.True(ok) - s.Equal(int32(100), di.DecisionTimeout) -} - -func (s *engineSuite) TestValidateSignalRequest() { - workflowType := "testType" - input := []byte("input") - startRequest := &types.StartWorkflowExecutionRequest{ - WorkflowID: "ID", - WorkflowType: &types.WorkflowType{Name: workflowType}, - TaskList: &types.TaskList{Name: "taskptr"}, - Input: input, - ExecutionStartToCloseTimeoutSeconds: common.Int32Ptr(10), - TaskStartToCloseTimeoutSeconds: common.Int32Ptr(10), - Identity: "identity", - } - - err := s.mockHistoryEngine.validateStartWorkflowExecutionRequest(startRequest, 0) - s.Error(err, "startRequest doesn't have request id, it should error out") -} - -func (s *engineSuite) TestRespondDecisionTaskCompletedMaxAttemptsExceeded() { - - we := types.WorkflowExecution{ - WorkflowID: "wId", - RunID: constants.TestRunID, - } - tl := "testTaskList" - taskToken, _ := json.Marshal(&common.TaskToken{ - WorkflowID: we.WorkflowID, - RunID: we.RunID, - ScheduleID: 2, - }) - identity := "testIdentity" - executionContext := []byte("context") - input := []byte("input") - - msBuilder := execution.NewMutableStateBuilderWithEventV2( - s.mockHistoryEngine.shard, - testlogger.New(s.Suite.T()), - we.GetRunID(), - constants.TestLocalDomainEntry, - ) - test.AddWorkflowExecutionStartedEvent(msBuilder, we, "wType", tl, []byte("input"), 100, 200, identity) - di := test.AddDecisionTaskScheduledEvent(msBuilder) - test.AddDecisionTaskStartedEvent(msBuilder, di.ScheduleID, tl, identity) - - decisions := []*types.Decision{{ - DecisionType: types.DecisionTypeScheduleActivityTask.Ptr(), - ScheduleActivityTaskDecisionAttributes: &types.ScheduleActivityTaskDecisionAttributes{ - ActivityID: "activity1", - ActivityType: &types.ActivityType{Name: "activity_type1"}, - TaskList: &types.TaskList{Name: tl}, - Input: input, - ScheduleToCloseTimeoutSeconds: common.Int32Ptr(100), - ScheduleToStartTimeoutSeconds: common.Int32Ptr(10), - StartToCloseTimeoutSeconds: common.Int32Ptr(50), - HeartbeatTimeoutSeconds: common.Int32Ptr(5), - }, - }} - - for i := 0; i < workflow.ConditionalRetryCount; i++ { - ms := execution.CreatePersistenceMutableState(msBuilder) - gwmsResponse := &persistence.GetWorkflowExecutionResponse{State: ms} - - s.mockExecutionMgr.On("GetWorkflowExecution", mock.Anything, mock.Anything).Return(gwmsResponse, nil).Once() - s.mockHistoryV2Mgr.On("AppendHistoryNodes", mock.Anything, mock.Anything).Return(&persistence.AppendHistoryNodesResponse{}, nil).Once() - s.mockExecutionMgr.On("UpdateWorkflowExecution", mock.Anything, mock.Anything).Return(&persistence.UpdateWorkflowExecutionResponse{MutableStateUpdateSessionStats: &persistence.MutableStateUpdateSessionStats{}}, - &persistence.ConditionFailedError{}).Once() - } - - _, err := s.mockHistoryEngine.RespondDecisionTaskCompleted(context.Background(), &types.HistoryRespondDecisionTaskCompletedRequest{ - DomainUUID: constants.TestDomainID, - CompleteRequest: &types.RespondDecisionTaskCompletedRequest{ - TaskToken: taskToken, - Decisions: decisions, - ExecutionContext: executionContext, - Identity: identity, - }, - }) - s.NotNil(err) - s.Equal(workflow.ErrMaxAttemptsExceeded, err) -} - -func (s *engineSuite) TestRespondDecisionTaskCompletedCompleteWorkflowFailed() { - - we := types.WorkflowExecution{ - WorkflowID: "wId", - RunID: constants.TestRunID, - } - tl := "testTaskList" - identity := "testIdentity" - executionContext := []byte("context") - activity1ID := "activity1" - activity1Type := "activity_type1" - activity1Input := []byte("input1") - activity1Result := []byte("activity1_result") - activity2ID := "activity2" - activity2Type := "activity_type2" - activity2Input := []byte("input2") - activity2Result := []byte("activity2_result") - workflowResult := []byte("workflow result") - - msBuilder := execution.NewMutableStateBuilderWithEventV2( - s.mockHistoryEngine.shard, - testlogger.New(s.Suite.T()), - we.GetRunID(), - constants.TestLocalDomainEntry, - ) - test.AddWorkflowExecutionStartedEvent(msBuilder, we, "wType", tl, []byte("input"), 25, 200, identity) - di1 := test.AddDecisionTaskScheduledEvent(msBuilder) - decisionStartedEvent1 := test.AddDecisionTaskStartedEvent(msBuilder, di1.ScheduleID, tl, identity) - decisionCompletedEvent1 := test.AddDecisionTaskCompletedEvent(msBuilder, di1.ScheduleID, - decisionStartedEvent1.ID, nil, identity) - activity1ScheduledEvent, _ := test.AddActivityTaskScheduledEvent(msBuilder, decisionCompletedEvent1.ID, - activity1ID, activity1Type, tl, activity1Input, 100, 10, 1, 5) - activity2ScheduledEvent, _ := test.AddActivityTaskScheduledEvent(msBuilder, decisionCompletedEvent1.ID, - activity2ID, activity2Type, tl, activity2Input, 100, 10, 1, 5) - activity1StartedEvent := test.AddActivityTaskStartedEvent(msBuilder, activity1ScheduledEvent.ID, identity) - activity2StartedEvent := test.AddActivityTaskStartedEvent(msBuilder, activity2ScheduledEvent.ID, identity) - test.AddActivityTaskCompletedEvent(msBuilder, activity1ScheduledEvent.ID, - activity1StartedEvent.ID, activity1Result, identity) - di2 := test.AddDecisionTaskScheduledEvent(msBuilder) - test.AddDecisionTaskStartedEvent(msBuilder, di2.ScheduleID, tl, identity) - test.AddActivityTaskCompletedEvent(msBuilder, activity2ScheduledEvent.ID, - activity2StartedEvent.ID, activity2Result, identity) - - taskToken, _ := json.Marshal(&common.TaskToken{ - WorkflowID: we.WorkflowID, - RunID: we.RunID, - ScheduleID: di2.ScheduleID, - }) - - decisions := []*types.Decision{{ - DecisionType: types.DecisionTypeCompleteWorkflowExecution.Ptr(), - CompleteWorkflowExecutionDecisionAttributes: &types.CompleteWorkflowExecutionDecisionAttributes{ - Result: workflowResult, - }, - }} - - for i := 0; i < 2; i++ { - ms := execution.CreatePersistenceMutableState(msBuilder) - gwmsResponse := &persistence.GetWorkflowExecutionResponse{State: ms} - s.mockExecutionMgr.On("GetWorkflowExecution", mock.Anything, mock.Anything).Return(gwmsResponse, nil).Once() - } - - s.mockHistoryV2Mgr.On("AppendHistoryNodes", mock.Anything, mock.Anything).Return(&persistence.AppendHistoryNodesResponse{}, nil).Once() - s.mockExecutionMgr.On("UpdateWorkflowExecution", mock.Anything, mock.Anything).Return(&persistence.UpdateWorkflowExecutionResponse{MutableStateUpdateSessionStats: &persistence.MutableStateUpdateSessionStats{}}, nil).Once() - - _, err := s.mockHistoryEngine.RespondDecisionTaskCompleted(context.Background(), &types.HistoryRespondDecisionTaskCompletedRequest{ - DomainUUID: constants.TestDomainID, - CompleteRequest: &types.RespondDecisionTaskCompletedRequest{ - TaskToken: taskToken, - Decisions: decisions, - ExecutionContext: executionContext, - Identity: identity, - }, - }) - s.Nil(err, s.printHistory(msBuilder)) - executionBuilder := s.getBuilder(constants.TestDomainID, we) - s.Equal(int64(15), executionBuilder.GetExecutionInfo().NextEventID) - s.Equal(decisionStartedEvent1.ID, executionBuilder.GetExecutionInfo().LastProcessedEvent) - s.Empty(executionBuilder.GetExecutionInfo().ExecutionContext) - s.Equal(persistence.WorkflowStateRunning, executionBuilder.GetExecutionInfo().State) - s.True(executionBuilder.HasPendingDecision()) - di3, ok := executionBuilder.GetDecisionInfo(executionBuilder.GetExecutionInfo().NextEventID - 1) - s.True(ok) - s.Equal(executionBuilder.GetExecutionInfo().NextEventID-1, di3.ScheduleID) - s.Equal(int64(0), di3.Attempt) -} - -func (s *engineSuite) TestRespondDecisionTaskCompletedFailWorkflowFailed() { - - we := types.WorkflowExecution{ - WorkflowID: "wId", - RunID: constants.TestRunID, - } - tl := "testTaskList" - identity := "testIdentity" - executionContext := []byte("context") - activity1ID := "activity1" - activity1Type := "activity_type1" - activity1Input := []byte("input1") - activity1Result := []byte("activity1_result") - activity2ID := "activity2" - activity2Type := "activity_type2" - activity2Input := []byte("input2") - activity2Result := []byte("activity2_result") - reason := "workflow fail reason" - details := []byte("workflow fail details") - - msBuilder := execution.NewMutableStateBuilderWithEventV2( - s.mockHistoryEngine.shard, - testlogger.New(s.Suite.T()), - we.GetRunID(), - constants.TestLocalDomainEntry, - ) - test.AddWorkflowExecutionStartedEvent(msBuilder, we, "wType", tl, []byte("input"), 25, 200, identity) - di1 := test.AddDecisionTaskScheduledEvent(msBuilder) - decisionStartedEvent1 := test.AddDecisionTaskStartedEvent(msBuilder, di1.ScheduleID, tl, identity) - decisionCompletedEvent1 := test.AddDecisionTaskCompletedEvent(msBuilder, di1.ScheduleID, - decisionStartedEvent1.ID, nil, identity) - activity1ScheduledEvent, _ := test.AddActivityTaskScheduledEvent(msBuilder, decisionCompletedEvent1.ID, activity1ID, - activity1Type, tl, activity1Input, 100, 10, 1, 5) - activity2ScheduledEvent, _ := test.AddActivityTaskScheduledEvent(msBuilder, decisionCompletedEvent1.ID, activity2ID, - activity2Type, tl, activity2Input, 100, 10, 1, 5) - activity1StartedEvent := test.AddActivityTaskStartedEvent(msBuilder, activity1ScheduledEvent.ID, identity) - activity2StartedEvent := test.AddActivityTaskStartedEvent(msBuilder, activity2ScheduledEvent.ID, identity) - test.AddActivityTaskCompletedEvent(msBuilder, activity1ScheduledEvent.ID, - activity1StartedEvent.ID, activity1Result, identity) - di2 := test.AddDecisionTaskScheduledEvent(msBuilder) - test.AddDecisionTaskStartedEvent(msBuilder, di2.ScheduleID, tl, identity) - test.AddActivityTaskCompletedEvent(msBuilder, activity2ScheduledEvent.ID, - activity2StartedEvent.ID, activity2Result, identity) - - taskToken, _ := json.Marshal(&common.TaskToken{ - WorkflowID: we.WorkflowID, - RunID: we.RunID, - ScheduleID: di2.ScheduleID, - }) - - decisions := []*types.Decision{{ - DecisionType: types.DecisionTypeFailWorkflowExecution.Ptr(), - FailWorkflowExecutionDecisionAttributes: &types.FailWorkflowExecutionDecisionAttributes{ - Reason: &reason, - Details: details, - }, - }} - - for i := 0; i < 2; i++ { - ms := execution.CreatePersistenceMutableState(msBuilder) - gwmsResponse := &persistence.GetWorkflowExecutionResponse{State: ms} - s.mockExecutionMgr.On("GetWorkflowExecution", mock.Anything, mock.Anything).Return(gwmsResponse, nil).Once() - } - - s.mockHistoryV2Mgr.On("AppendHistoryNodes", mock.Anything, mock.Anything).Return(&persistence.AppendHistoryNodesResponse{}, nil).Once() - s.mockExecutionMgr.On("UpdateWorkflowExecution", mock.Anything, mock.Anything).Return(&persistence.UpdateWorkflowExecutionResponse{MutableStateUpdateSessionStats: &persistence.MutableStateUpdateSessionStats{}}, nil).Once() - - _, err := s.mockHistoryEngine.RespondDecisionTaskCompleted(context.Background(), &types.HistoryRespondDecisionTaskCompletedRequest{ - DomainUUID: constants.TestDomainID, - CompleteRequest: &types.RespondDecisionTaskCompletedRequest{ - TaskToken: taskToken, - Decisions: decisions, - ExecutionContext: executionContext, - Identity: identity, - }, - }) - s.Nil(err, s.printHistory(msBuilder)) - executionBuilder := s.getBuilder(constants.TestDomainID, we) - s.Equal(int64(15), executionBuilder.GetExecutionInfo().NextEventID) - s.Equal(decisionStartedEvent1.ID, executionBuilder.GetExecutionInfo().LastProcessedEvent) - s.Empty(executionBuilder.GetExecutionInfo().ExecutionContext) - s.Equal(persistence.WorkflowStateRunning, executionBuilder.GetExecutionInfo().State) - s.True(executionBuilder.HasPendingDecision()) - di3, ok := executionBuilder.GetDecisionInfo(executionBuilder.GetExecutionInfo().NextEventID - 1) - s.True(ok) - s.Equal(executionBuilder.GetExecutionInfo().NextEventID-1, di3.ScheduleID) - s.Equal(int64(0), di3.Attempt) -} - -func (s *engineSuite) TestRespondDecisionTaskCompletedBadDecisionAttributes() { - - we := types.WorkflowExecution{ - WorkflowID: "wId", - RunID: constants.TestRunID, - } - tl := "testTaskList" - identity := "testIdentity" - executionContext := []byte("context") - activity1ID := "activity1" - activity1Type := "activity_type1" - activity1Input := []byte("input1") - activity1Result := []byte("activity1_result") - - msBuilder := execution.NewMutableStateBuilderWithEventV2( - s.mockHistoryEngine.shard, - testlogger.New(s.Suite.T()), - we.GetRunID(), - constants.TestLocalDomainEntry, - ) - test.AddWorkflowExecutionStartedEvent(msBuilder, we, "wType", tl, []byte("input"), 25, 200, identity) - di1 := test.AddDecisionTaskScheduledEvent(msBuilder) - decisionStartedEvent1 := test.AddDecisionTaskStartedEvent(msBuilder, di1.ScheduleID, tl, identity) - decisionCompletedEvent1 := test.AddDecisionTaskCompletedEvent(msBuilder, di1.ScheduleID, - decisionStartedEvent1.ID, nil, identity) - activity1ScheduledEvent, _ := test.AddActivityTaskScheduledEvent(msBuilder, decisionCompletedEvent1.ID, activity1ID, - activity1Type, tl, activity1Input, 100, 10, 1, 5) - activity1StartedEvent := test.AddActivityTaskStartedEvent(msBuilder, activity1ScheduledEvent.ID, identity) - test.AddActivityTaskCompletedEvent(msBuilder, activity1ScheduledEvent.ID, - activity1StartedEvent.ID, activity1Result, identity) - di2 := test.AddDecisionTaskScheduledEvent(msBuilder) - test.AddDecisionTaskStartedEvent(msBuilder, di2.ScheduleID, tl, identity) - - taskToken, _ := json.Marshal(&common.TaskToken{ - WorkflowID: we.WorkflowID, - RunID: we.RunID, - ScheduleID: di2.ScheduleID, - }) - - // Decision with nil attributes - decisions := []*types.Decision{{ - DecisionType: types.DecisionTypeCompleteWorkflowExecution.Ptr(), - }} - - gwmsResponse1 := &persistence.GetWorkflowExecutionResponse{State: execution.CreatePersistenceMutableState(msBuilder)} - gwmsResponse2 := &persistence.GetWorkflowExecutionResponse{State: execution.CreatePersistenceMutableState(msBuilder)} - s.mockExecutionMgr.On("GetWorkflowExecution", mock.Anything, mock.Anything).Return(gwmsResponse1, nil).Once() - s.mockExecutionMgr.On("GetWorkflowExecution", mock.Anything, mock.Anything).Return(gwmsResponse2, nil).Once() - - s.mockHistoryV2Mgr.On("AppendHistoryNodes", mock.Anything, mock.Anything).Return(&persistence.AppendHistoryNodesResponse{}, nil).Once() - s.mockExecutionMgr.On("UpdateWorkflowExecution", mock.Anything, mock.Anything).Return(&persistence.UpdateWorkflowExecutionResponse{ - MutableStateUpdateSessionStats: &persistence.MutableStateUpdateSessionStats{}}, nil, - ).Once() - - _, err := s.mockHistoryEngine.RespondDecisionTaskCompleted(context.Background(), &types.HistoryRespondDecisionTaskCompletedRequest{ - DomainUUID: constants.TestDomainID, - CompleteRequest: &types.RespondDecisionTaskCompletedRequest{ - TaskToken: taskToken, - Decisions: decisions, - ExecutionContext: executionContext, - Identity: identity, - }, - }) - s.Nil(err) -} - -// This test unit tests the activity schedule timeout validation logic of HistoryEngine's RespondDecisionTaskComplete function. -// An scheduled activity decision has 3 timeouts: ScheduleToClose, ScheduleToStart and StartToClose. -// This test verifies that when either ScheduleToClose or ScheduleToStart and StartToClose are specified, -// HistoryEngine's validateActivityScheduleAttribute will deduce the missing timeout and fill it in -// instead of returning a BadRequest error and only when all three are missing should a BadRequest be returned. -func (s *engineSuite) TestRespondDecisionTaskCompletedSingleActivityScheduledAttribute() { - workflowTimeout := int32(100) - testIterationVariables := []struct { - scheduleToClose *int32 - scheduleToStart *int32 - startToClose *int32 - heartbeat *int32 - expectedScheduleToClose int32 - expectedScheduleToStart int32 - expectedStartToClose int32 - expectDecisionFail bool - }{ - // No ScheduleToClose timeout, will use ScheduleToStart + StartToClose - {nil, common.Int32Ptr(3), common.Int32Ptr(7), nil, - 3 + 7, 3, 7, false}, - // Has ScheduleToClose timeout but not ScheduleToStart or StartToClose, - // will use ScheduleToClose for ScheduleToStart and StartToClose - {common.Int32Ptr(7), nil, nil, nil, - 7, 7, 7, false}, - // No ScheduleToClose timeout, ScheduleToStart or StartToClose, expect error return - {nil, nil, nil, nil, - 0, 0, 0, true}, - // Negative ScheduleToClose, expect error return - {common.Int32Ptr(-1), nil, nil, nil, - 0, 0, 0, true}, - // Negative ScheduleToStart, expect error return - {nil, common.Int32Ptr(-1), nil, nil, - 0, 0, 0, true}, - // Negative StartToClose, expect error return - {nil, nil, common.Int32Ptr(-1), nil, - 0, 0, 0, true}, - // Negative HeartBeat, expect error return - {nil, nil, nil, common.Int32Ptr(-1), - 0, 0, 0, true}, - // Use workflow timeout - {common.Int32Ptr(workflowTimeout), nil, nil, nil, - workflowTimeout, workflowTimeout, workflowTimeout, false}, - // Timeout larger than workflow timeout - {common.Int32Ptr(workflowTimeout + 1), nil, nil, nil, - workflowTimeout, workflowTimeout, workflowTimeout, false}, - {nil, common.Int32Ptr(workflowTimeout + 1), nil, nil, - 0, 0, 0, true}, - {nil, nil, common.Int32Ptr(workflowTimeout + 1), nil, - 0, 0, 0, true}, - {nil, nil, nil, common.Int32Ptr(workflowTimeout + 1), - 0, 0, 0, true}, - // No ScheduleToClose timeout, will use ScheduleToStart + StartToClose, but exceed limit - {nil, common.Int32Ptr(workflowTimeout), common.Int32Ptr(10), nil, - workflowTimeout, workflowTimeout, 10, false}, - } - - for _, iVar := range testIterationVariables { - - we := types.WorkflowExecution{ - WorkflowID: "wId", - RunID: constants.TestRunID, - } - tl := "testTaskList" - taskToken, _ := json.Marshal(&common.TaskToken{ - WorkflowID: "wId", - RunID: we.GetRunID(), - ScheduleID: 2, - }) - identity := "testIdentity" - executionContext := []byte("context") - input := []byte("input") - - msBuilder := execution.NewMutableStateBuilderWithEventV2( - s.mockHistoryEngine.shard, - testlogger.New(s.Suite.T()), - we.GetRunID(), - constants.TestLocalDomainEntry, - ) - test.AddWorkflowExecutionStartedEvent(msBuilder, we, "wType", tl, []byte("input"), workflowTimeout, 200, identity) - di := test.AddDecisionTaskScheduledEvent(msBuilder) - test.AddDecisionTaskStartedEvent(msBuilder, di.ScheduleID, tl, identity) - - decisions := []*types.Decision{{ - DecisionType: types.DecisionTypeScheduleActivityTask.Ptr(), - ScheduleActivityTaskDecisionAttributes: &types.ScheduleActivityTaskDecisionAttributes{ - ActivityID: "activity1", - ActivityType: &types.ActivityType{Name: "activity_type1"}, - TaskList: &types.TaskList{Name: tl}, - Input: input, - ScheduleToCloseTimeoutSeconds: iVar.scheduleToClose, - ScheduleToStartTimeoutSeconds: iVar.scheduleToStart, - StartToCloseTimeoutSeconds: iVar.startToClose, - HeartbeatTimeoutSeconds: iVar.heartbeat, - }, - }} - - gwmsResponse1 := &persistence.GetWorkflowExecutionResponse{State: execution.CreatePersistenceMutableState(msBuilder)} - s.mockExecutionMgr.On("GetWorkflowExecution", mock.Anything, mock.Anything).Return(gwmsResponse1, nil).Once() - if iVar.expectDecisionFail { - gwmsResponse2 := &persistence.GetWorkflowExecutionResponse{State: execution.CreatePersistenceMutableState(msBuilder)} - s.mockExecutionMgr.On("GetWorkflowExecution", mock.Anything, mock.Anything).Return(gwmsResponse2, nil).Once() - } - - s.mockHistoryV2Mgr.On("AppendHistoryNodes", mock.Anything, mock.Anything).Return(&persistence.AppendHistoryNodesResponse{}, nil).Once() - s.mockExecutionMgr.On("UpdateWorkflowExecution", mock.Anything, mock.Anything).Return(&persistence.UpdateWorkflowExecutionResponse{MutableStateUpdateSessionStats: &persistence.MutableStateUpdateSessionStats{}}, nil).Once() - - _, err := s.mockHistoryEngine.RespondDecisionTaskCompleted(context.Background(), &types.HistoryRespondDecisionTaskCompletedRequest{ - DomainUUID: constants.TestDomainID, - CompleteRequest: &types.RespondDecisionTaskCompletedRequest{ - TaskToken: taskToken, - Decisions: decisions, - ExecutionContext: executionContext, - Identity: identity, - }, - }) - - s.Nil(err, s.printHistory(msBuilder)) - executionBuilder := s.getBuilder(constants.TestDomainID, we) - if !iVar.expectDecisionFail { - s.Equal(int64(6), executionBuilder.GetExecutionInfo().NextEventID) - s.Equal(int64(3), executionBuilder.GetExecutionInfo().LastProcessedEvent) - s.Equal(persistence.WorkflowStateRunning, executionBuilder.GetExecutionInfo().State) - s.False(executionBuilder.HasPendingDecision()) - - activity1Attributes := s.getActivityScheduledEvent(executionBuilder, int64(5)).ActivityTaskScheduledEventAttributes - s.Equal(iVar.expectedScheduleToClose, activity1Attributes.GetScheduleToCloseTimeoutSeconds()) - s.Equal(iVar.expectedScheduleToStart, activity1Attributes.GetScheduleToStartTimeoutSeconds()) - s.Equal(iVar.expectedStartToClose, activity1Attributes.GetStartToCloseTimeoutSeconds()) - } else { - s.Equal(int64(5), executionBuilder.GetExecutionInfo().NextEventID) - s.Equal(common.EmptyEventID, executionBuilder.GetExecutionInfo().LastProcessedEvent) - s.Equal(persistence.WorkflowStateRunning, executionBuilder.GetExecutionInfo().State) - s.True(executionBuilder.HasPendingDecision()) - } - s.TearDownTest() - s.SetupTest() - } -} - -func (s *engineSuite) TestRespondDecisionTaskCompletedBadBinary() { - domainID := uuid.New() - we := types.WorkflowExecution{ - WorkflowID: "wId", - RunID: constants.TestRunID, - } - tl := "testTaskList" - taskToken, _ := json.Marshal(&common.TaskToken{ - WorkflowID: "wId", - RunID: we.GetRunID(), - ScheduleID: 2, - }) - identity := "testIdentity" - executionContext := []byte("context") - domainEntry := cache.NewLocalDomainCacheEntryForTest( - &persistence.DomainInfo{ID: domainID, Name: constants.TestDomainName}, - &persistence.DomainConfig{ - Retention: 2, - BadBinaries: types.BadBinaries{ - Binaries: map[string]*types.BadBinaryInfo{ - "test-bad-binary": {}, - }, - }, - }, - cluster.TestCurrentClusterName, - ) - - msBuilder := execution.NewMutableStateBuilderWithEventV2( - s.mockHistoryEngine.shard, - testlogger.New(s.Suite.T()), - we.GetRunID(), - domainEntry, - ) - test.AddWorkflowExecutionStartedEvent(msBuilder, we, "wType", tl, []byte("input"), 100, 200, identity) - di := test.AddDecisionTaskScheduledEvent(msBuilder) - test.AddDecisionTaskStartedEvent(msBuilder, di.ScheduleID, tl, identity) - - var decisions []*types.Decision - - gwmsResponse1 := &persistence.GetWorkflowExecutionResponse{State: execution.CreatePersistenceMutableState(msBuilder)} - gwmsResponse2 := &persistence.GetWorkflowExecutionResponse{State: execution.CreatePersistenceMutableState(msBuilder)} - - s.mockExecutionMgr.On("GetWorkflowExecution", mock.Anything, mock.Anything).Return(gwmsResponse1, nil).Once() - s.mockExecutionMgr.On("GetWorkflowExecution", mock.Anything, mock.Anything).Return(gwmsResponse2, nil).Once() - s.mockHistoryV2Mgr.On("AppendHistoryNodes", mock.Anything, mock.Anything).Return(&persistence.AppendHistoryNodesResponse{}, nil).Once() - s.mockExecutionMgr.On("UpdateWorkflowExecution", mock.Anything, mock.Anything).Return(&persistence.UpdateWorkflowExecutionResponse{MutableStateUpdateSessionStats: &persistence.MutableStateUpdateSessionStats{}}, nil).Once() - s.mockDomainCache.EXPECT().GetDomainByID(domainID).Return(domainEntry, nil).AnyTimes() - s.mockDomainCache.EXPECT().GetDomainName(domainID).Return(constants.TestDomainName, nil).AnyTimes() - - _, err := s.mockHistoryEngine.RespondDecisionTaskCompleted(context.Background(), &types.HistoryRespondDecisionTaskCompletedRequest{ - DomainUUID: domainID, - CompleteRequest: &types.RespondDecisionTaskCompletedRequest{ - TaskToken: taskToken, - Decisions: decisions, - ExecutionContext: executionContext, - Identity: identity, - BinaryChecksum: "test-bad-binary", - }, - }) - s.Nil(err, s.printHistory(msBuilder)) - executionBuilder := s.getBuilder(domainID, we) - s.Equal(int64(5), executionBuilder.GetExecutionInfo().NextEventID) - s.Equal(common.EmptyEventID, executionBuilder.GetExecutionInfo().LastProcessedEvent) - s.Empty(executionBuilder.GetExecutionInfo().ExecutionContext) - s.Equal(persistence.WorkflowStateRunning, executionBuilder.GetExecutionInfo().State) - s.True(executionBuilder.HasPendingDecision()) -} - -func (s *engineSuite) TestRespondDecisionTaskCompletedSingleActivityScheduledDecision() { - - we := types.WorkflowExecution{ - WorkflowID: "wId", - RunID: constants.TestRunID, - } - tl := "testTaskList" - taskToken, _ := json.Marshal(&common.TaskToken{ - WorkflowID: "wId", - RunID: we.GetRunID(), - ScheduleID: 2, - }) - identity := "testIdentity" - executionContext := []byte("context") - input := []byte("input") - - msBuilder := execution.NewMutableStateBuilderWithEventV2( - s.mockHistoryEngine.shard, - testlogger.New(s.Suite.T()), - we.GetRunID(), - constants.TestLocalDomainEntry, - ) - test.AddWorkflowExecutionStartedEvent(msBuilder, we, "wType", tl, []byte("input"), 100, 200, identity) - di := test.AddDecisionTaskScheduledEvent(msBuilder) - test.AddDecisionTaskStartedEvent(msBuilder, di.ScheduleID, tl, identity) - - decisions := []*types.Decision{{ - DecisionType: types.DecisionTypeScheduleActivityTask.Ptr(), - ScheduleActivityTaskDecisionAttributes: &types.ScheduleActivityTaskDecisionAttributes{ - ActivityID: "activity1", - ActivityType: &types.ActivityType{Name: "activity_type1"}, - TaskList: &types.TaskList{Name: tl}, - Input: input, - ScheduleToCloseTimeoutSeconds: common.Int32Ptr(100), - ScheduleToStartTimeoutSeconds: common.Int32Ptr(10), - StartToCloseTimeoutSeconds: common.Int32Ptr(50), - HeartbeatTimeoutSeconds: common.Int32Ptr(5), - }, - }} - - ms := execution.CreatePersistenceMutableState(msBuilder) - gwmsResponse := &persistence.GetWorkflowExecutionResponse{State: ms} - - s.mockExecutionMgr.On("GetWorkflowExecution", mock.Anything, mock.Anything).Return(gwmsResponse, nil).Once() - s.mockHistoryV2Mgr.On("AppendHistoryNodes", mock.Anything, mock.Anything).Return(&persistence.AppendHistoryNodesResponse{}, nil).Once() - s.mockExecutionMgr.On("UpdateWorkflowExecution", mock.Anything, mock.Anything).Return(&persistence.UpdateWorkflowExecutionResponse{MutableStateUpdateSessionStats: &persistence.MutableStateUpdateSessionStats{}}, nil).Once() - - _, err := s.mockHistoryEngine.RespondDecisionTaskCompleted(context.Background(), &types.HistoryRespondDecisionTaskCompletedRequest{ - DomainUUID: constants.TestDomainID, - CompleteRequest: &types.RespondDecisionTaskCompletedRequest{ - TaskToken: taskToken, - Decisions: decisions, - ExecutionContext: executionContext, - Identity: identity, - }, - }) - s.Nil(err, s.printHistory(msBuilder)) - executionBuilder := s.getBuilder(constants.TestDomainID, we) - s.Equal(int64(6), executionBuilder.GetExecutionInfo().NextEventID) - s.Equal(int64(3), executionBuilder.GetExecutionInfo().LastProcessedEvent) - s.Equal(executionContext, executionBuilder.GetExecutionInfo().ExecutionContext) - s.Equal(persistence.WorkflowStateRunning, executionBuilder.GetExecutionInfo().State) - s.False(executionBuilder.HasPendingDecision()) - - activity1Attributes := s.getActivityScheduledEvent(executionBuilder, int64(5)).ActivityTaskScheduledEventAttributes - s.Equal("activity1", activity1Attributes.ActivityID) - s.Equal("activity_type1", activity1Attributes.ActivityType.Name) - s.Equal(int64(4), activity1Attributes.DecisionTaskCompletedEventID) - s.Equal(tl, activity1Attributes.TaskList.Name) - s.Equal(input, activity1Attributes.Input) - s.Equal(int32(100), *activity1Attributes.ScheduleToCloseTimeoutSeconds) - s.Equal(int32(10), *activity1Attributes.ScheduleToStartTimeoutSeconds) - s.Equal(int32(50), *activity1Attributes.StartToCloseTimeoutSeconds) - s.Equal(int32(5), *activity1Attributes.HeartbeatTimeoutSeconds) -} - -func (s *engineSuite) TestRespondDecisionTaskCompleted_DecisionHeartbeatTimeout() { - - we := types.WorkflowExecution{ - WorkflowID: "wId", - RunID: constants.TestRunID, - } - tl := "testTaskList" - taskToken, _ := json.Marshal(&common.TaskToken{ - WorkflowID: we.WorkflowID, - RunID: we.RunID, - ScheduleID: 2, - }) - identity := "testIdentity" - executionContext := []byte("context") - - msBuilder := execution.NewMutableStateBuilderWithEventV2( - s.mockHistoryEngine.shard, - testlogger.New(s.Suite.T()), - we.GetRunID(), - constants.TestLocalDomainEntry, - ) - test.AddWorkflowExecutionStartedEvent(msBuilder, we, "wType", tl, []byte("input"), 100, 200, identity) - di := test.AddDecisionTaskScheduledEvent(msBuilder) - test.AddDecisionTaskStartedEvent(msBuilder, di.ScheduleID, tl, identity) - msBuilder.GetExecutionInfo().DecisionOriginalScheduledTimestamp = time.Now().Add(-time.Hour).UnixNano() - - decisions := []*types.Decision{} - - ms := execution.CreatePersistenceMutableState(msBuilder) - gwmsResponse := &persistence.GetWorkflowExecutionResponse{State: ms} - - s.mockExecutionMgr.On("GetWorkflowExecution", mock.Anything, mock.Anything).Return(gwmsResponse, nil).Once() - s.mockHistoryV2Mgr.On("AppendHistoryNodes", mock.Anything, mock.Anything).Return(&persistence.AppendHistoryNodesResponse{}, nil).Once() - s.mockExecutionMgr.On("UpdateWorkflowExecution", mock.Anything, mock.Anything).Return(&persistence.UpdateWorkflowExecutionResponse{MutableStateUpdateSessionStats: &persistence.MutableStateUpdateSessionStats{}}, nil).Once() - - _, err := s.mockHistoryEngine.RespondDecisionTaskCompleted(context.Background(), &types.HistoryRespondDecisionTaskCompletedRequest{ - DomainUUID: constants.TestDomainID, - CompleteRequest: &types.RespondDecisionTaskCompletedRequest{ - ForceCreateNewDecisionTask: true, - TaskToken: taskToken, - Decisions: decisions, - ExecutionContext: executionContext, - Identity: identity, - }, - }) - s.Error(err, "decision heartbeat timeout") -} - -func (s *engineSuite) TestRespondDecisionTaskCompleted_DecisionHeartbeatNotTimeout() { - - we := types.WorkflowExecution{ - WorkflowID: "wId", - RunID: constants.TestRunID, - } - tl := "testTaskList" - taskToken, _ := json.Marshal(&common.TaskToken{ - WorkflowID: we.WorkflowID, - RunID: we.RunID, - ScheduleID: 2, - }) - identity := "testIdentity" - executionContext := []byte("context") - - msBuilder := execution.NewMutableStateBuilderWithEventV2( - s.mockHistoryEngine.shard, - testlogger.New(s.Suite.T()), - we.GetRunID(), - constants.TestLocalDomainEntry, - ) - test.AddWorkflowExecutionStartedEvent(msBuilder, we, "wType", tl, []byte("input"), 100, 200, identity) - di := test.AddDecisionTaskScheduledEvent(msBuilder) - test.AddDecisionTaskStartedEvent(msBuilder, di.ScheduleID, tl, identity) - msBuilder.GetExecutionInfo().DecisionOriginalScheduledTimestamp = time.Now().Add(-time.Minute).UnixNano() - - decisions := []*types.Decision{} - - ms := execution.CreatePersistenceMutableState(msBuilder) - gwmsResponse := &persistence.GetWorkflowExecutionResponse{State: ms} - - s.mockExecutionMgr.On("GetWorkflowExecution", mock.Anything, mock.Anything).Return(gwmsResponse, nil).Once() - s.mockHistoryV2Mgr.On("AppendHistoryNodes", mock.Anything, mock.Anything).Return(&persistence.AppendHistoryNodesResponse{}, nil).Once() - s.mockExecutionMgr.On("UpdateWorkflowExecution", mock.Anything, mock.Anything).Return(&persistence.UpdateWorkflowExecutionResponse{MutableStateUpdateSessionStats: &persistence.MutableStateUpdateSessionStats{}}, nil).Once() - - _, err := s.mockHistoryEngine.RespondDecisionTaskCompleted(context.Background(), &types.HistoryRespondDecisionTaskCompletedRequest{ - DomainUUID: constants.TestDomainID, - CompleteRequest: &types.RespondDecisionTaskCompletedRequest{ - ForceCreateNewDecisionTask: true, - TaskToken: taskToken, - Decisions: decisions, - ExecutionContext: executionContext, - Identity: identity, - }, - }) - s.Nil(err) -} - -func (s *engineSuite) TestRespondDecisionTaskCompleted_DecisionHeartbeatNotTimeout_ZeroOrignalScheduledTime() { - - we := types.WorkflowExecution{ - WorkflowID: "wId", - RunID: constants.TestRunID, - } - tl := "testTaskList" - taskToken, _ := json.Marshal(&common.TaskToken{ - WorkflowID: we.WorkflowID, - RunID: we.RunID, - ScheduleID: 2, - }) - identity := "testIdentity" - executionContext := []byte("context") - - msBuilder := execution.NewMutableStateBuilderWithEventV2( - s.mockHistoryEngine.shard, - testlogger.New(s.Suite.T()), - we.GetRunID(), - constants.TestLocalDomainEntry, - ) - test.AddWorkflowExecutionStartedEvent(msBuilder, we, "wType", tl, []byte("input"), 100, 200, identity) - di := test.AddDecisionTaskScheduledEvent(msBuilder) - test.AddDecisionTaskStartedEvent(msBuilder, di.ScheduleID, tl, identity) - msBuilder.GetExecutionInfo().DecisionOriginalScheduledTimestamp = 0 - - decisions := []*types.Decision{} - - ms := execution.CreatePersistenceMutableState(msBuilder) - gwmsResponse := &persistence.GetWorkflowExecutionResponse{State: ms} - - s.mockExecutionMgr.On("GetWorkflowExecution", mock.Anything, mock.Anything).Return(gwmsResponse, nil).Once() - s.mockHistoryV2Mgr.On("AppendHistoryNodes", mock.Anything, mock.Anything).Return(&persistence.AppendHistoryNodesResponse{}, nil).Once() - s.mockExecutionMgr.On("UpdateWorkflowExecution", mock.Anything, mock.Anything).Return(&persistence.UpdateWorkflowExecutionResponse{MutableStateUpdateSessionStats: &persistence.MutableStateUpdateSessionStats{}}, nil).Once() - - _, err := s.mockHistoryEngine.RespondDecisionTaskCompleted(context.Background(), &types.HistoryRespondDecisionTaskCompletedRequest{ - DomainUUID: constants.TestDomainID, - CompleteRequest: &types.RespondDecisionTaskCompletedRequest{ - ForceCreateNewDecisionTask: true, - TaskToken: taskToken, - Decisions: decisions, - ExecutionContext: executionContext, - Identity: identity, - }, - }) - s.Nil(err) -} - -func (s *engineSuite) TestRespondDecisionTaskCompletedCompleteWorkflowSuccess() { - - we := types.WorkflowExecution{ - WorkflowID: "wId", - RunID: constants.TestRunID, - } - tl := "testTaskList" - taskToken, _ := json.Marshal(&common.TaskToken{ - WorkflowID: we.WorkflowID, - RunID: we.RunID, - ScheduleID: 2, - }) - identity := "testIdentity" - executionContext := []byte("context") - workflowResult := []byte("success") - - msBuilder := execution.NewMutableStateBuilderWithEventV2( - s.mockHistoryEngine.shard, - testlogger.New(s.Suite.T()), - we.GetRunID(), - constants.TestLocalDomainEntry, - ) - test.AddWorkflowExecutionStartedEvent(msBuilder, we, "wType", tl, []byte("input"), 100, 200, identity) - di := test.AddDecisionTaskScheduledEvent(msBuilder) - test.AddDecisionTaskStartedEvent(msBuilder, di.ScheduleID, tl, identity) - - decisions := []*types.Decision{{ - DecisionType: types.DecisionTypeCompleteWorkflowExecution.Ptr(), - CompleteWorkflowExecutionDecisionAttributes: &types.CompleteWorkflowExecutionDecisionAttributes{ - Result: workflowResult, - }, - }} - - ms := execution.CreatePersistenceMutableState(msBuilder) - gwmsResponse := &persistence.GetWorkflowExecutionResponse{State: ms} - - s.mockExecutionMgr.On("GetWorkflowExecution", mock.Anything, mock.Anything).Return(gwmsResponse, nil).Once() - s.mockHistoryV2Mgr.On("AppendHistoryNodes", mock.Anything, mock.Anything).Return(&persistence.AppendHistoryNodesResponse{}, nil).Once() - s.mockExecutionMgr.On("UpdateWorkflowExecution", mock.Anything, mock.Anything).Return(&persistence.UpdateWorkflowExecutionResponse{MutableStateUpdateSessionStats: &persistence.MutableStateUpdateSessionStats{}}, nil).Once() - - _, err := s.mockHistoryEngine.RespondDecisionTaskCompleted(context.Background(), &types.HistoryRespondDecisionTaskCompletedRequest{ - DomainUUID: constants.TestDomainID, - CompleteRequest: &types.RespondDecisionTaskCompletedRequest{ - TaskToken: taskToken, - Decisions: decisions, - ExecutionContext: executionContext, - Identity: identity, - }, - }) - s.Nil(err, s.printHistory(msBuilder)) - executionBuilder := s.getBuilder(constants.TestDomainID, we) - s.Equal(int64(6), executionBuilder.GetExecutionInfo().NextEventID) - s.Equal(int64(3), executionBuilder.GetExecutionInfo().LastProcessedEvent) - s.Equal(executionContext, executionBuilder.GetExecutionInfo().ExecutionContext) - s.Equal(persistence.WorkflowStateCompleted, executionBuilder.GetExecutionInfo().State) - s.False(executionBuilder.HasPendingDecision()) -} - -func (s *engineSuite) TestRespondDecisionTaskCompletedFailWorkflowSuccess() { - - we := types.WorkflowExecution{ - WorkflowID: "wId", - RunID: constants.TestRunID, - } - tl := "testTaskList" - taskToken, _ := json.Marshal(&common.TaskToken{ - WorkflowID: we.WorkflowID, - RunID: we.RunID, - ScheduleID: 2, - }) - identity := "testIdentity" - executionContext := []byte("context") - details := []byte("fail workflow details") - reason := "fail workflow reason" - - msBuilder := execution.NewMutableStateBuilderWithEventV2( - s.mockHistoryEngine.shard, - testlogger.New(s.Suite.T()), - we.GetRunID(), - constants.TestLocalDomainEntry, - ) - test.AddWorkflowExecutionStartedEvent(msBuilder, we, "wType", tl, []byte("input"), 100, 200, identity) - di := test.AddDecisionTaskScheduledEvent(msBuilder) - test.AddDecisionTaskStartedEvent(msBuilder, di.ScheduleID, tl, identity) - - decisions := []*types.Decision{{ - DecisionType: types.DecisionTypeFailWorkflowExecution.Ptr(), - FailWorkflowExecutionDecisionAttributes: &types.FailWorkflowExecutionDecisionAttributes{ - Reason: &reason, - Details: details, - }, - }} - - ms := execution.CreatePersistenceMutableState(msBuilder) - gwmsResponse := &persistence.GetWorkflowExecutionResponse{State: ms} - - s.mockExecutionMgr.On("GetWorkflowExecution", mock.Anything, mock.Anything).Return(gwmsResponse, nil).Once() - s.mockHistoryV2Mgr.On("AppendHistoryNodes", mock.Anything, mock.Anything).Return(&persistence.AppendHistoryNodesResponse{}, nil).Once() - s.mockExecutionMgr.On("UpdateWorkflowExecution", mock.Anything, mock.Anything).Return(&persistence.UpdateWorkflowExecutionResponse{MutableStateUpdateSessionStats: &persistence.MutableStateUpdateSessionStats{}}, nil).Once() - - _, err := s.mockHistoryEngine.RespondDecisionTaskCompleted(context.Background(), &types.HistoryRespondDecisionTaskCompletedRequest{ - DomainUUID: constants.TestDomainID, - CompleteRequest: &types.RespondDecisionTaskCompletedRequest{ - TaskToken: taskToken, - Decisions: decisions, - ExecutionContext: executionContext, - Identity: identity, - }, - }) - s.Nil(err, s.printHistory(msBuilder)) - executionBuilder := s.getBuilder(constants.TestDomainID, we) - s.Equal(int64(6), executionBuilder.GetExecutionInfo().NextEventID) - s.Equal(int64(3), executionBuilder.GetExecutionInfo().LastProcessedEvent) - s.Equal(executionContext, executionBuilder.GetExecutionInfo().ExecutionContext) - s.Equal(persistence.WorkflowStateCompleted, executionBuilder.GetExecutionInfo().State) - s.False(executionBuilder.HasPendingDecision()) -} - -func (s *engineSuite) TestRespondDecisionTaskCompletedSignalExternalWorkflowSuccess() { - - we := types.WorkflowExecution{ - WorkflowID: "wId", - RunID: constants.TestRunID, - } - tl := "testTaskList" - taskToken, _ := json.Marshal(&common.TaskToken{ - WorkflowID: we.WorkflowID, - RunID: we.RunID, - ScheduleID: 2, - }) - identity := "testIdentity" - executionContext := []byte("context") - - msBuilder := execution.NewMutableStateBuilderWithEventV2( - s.mockHistoryEngine.shard, - testlogger.New(s.Suite.T()), - we.GetRunID(), - constants.TestLocalDomainEntry, - ) - test.AddWorkflowExecutionStartedEvent(msBuilder, we, "wType", tl, []byte("input"), 100, 200, identity) - di := test.AddDecisionTaskScheduledEvent(msBuilder) - test.AddDecisionTaskStartedEvent(msBuilder, di.ScheduleID, tl, identity) - - decisions := []*types.Decision{{ - DecisionType: types.DecisionTypeSignalExternalWorkflowExecution.Ptr(), - SignalExternalWorkflowExecutionDecisionAttributes: &types.SignalExternalWorkflowExecutionDecisionAttributes{ - Domain: constants.TestDomainName, - Execution: &types.WorkflowExecution{ - WorkflowID: we.WorkflowID, - RunID: we.RunID, - }, - SignalName: "signal", - Input: []byte("test input"), - }, - }} - - ms := execution.CreatePersistenceMutableState(msBuilder) - gwmsResponse := &persistence.GetWorkflowExecutionResponse{State: ms} - - s.mockExecutionMgr.On("GetWorkflowExecution", mock.Anything, mock.Anything).Return(gwmsResponse, nil).Once() - s.mockHistoryV2Mgr.On("AppendHistoryNodes", mock.Anything, mock.Anything).Return(&persistence.AppendHistoryNodesResponse{}, nil).Once() - s.mockExecutionMgr.On("UpdateWorkflowExecution", mock.Anything, mock.Anything).Return(&persistence.UpdateWorkflowExecutionResponse{MutableStateUpdateSessionStats: &persistence.MutableStateUpdateSessionStats{}}, nil).Once() - - _, err := s.mockHistoryEngine.RespondDecisionTaskCompleted(context.Background(), &types.HistoryRespondDecisionTaskCompletedRequest{ - DomainUUID: constants.TestDomainID, - CompleteRequest: &types.RespondDecisionTaskCompletedRequest{ - TaskToken: taskToken, - Decisions: decisions, - ExecutionContext: executionContext, - Identity: identity, - }, - }) - s.Nil(err, s.printHistory(msBuilder)) - executionBuilder := s.getBuilder(constants.TestDomainID, we) - s.Equal(int64(6), executionBuilder.GetExecutionInfo().NextEventID) - s.Equal(int64(3), executionBuilder.GetExecutionInfo().LastProcessedEvent) - s.Equal(executionContext, executionBuilder.GetExecutionInfo().ExecutionContext) -} - -func (s *engineSuite) TestRespondDecisionTaskCompletedStartChildWorkflowWithAbandonPolicy() { - - we := types.WorkflowExecution{ - WorkflowID: "wId", - RunID: constants.TestRunID, - } - tl := "testTaskList" - taskToken, _ := json.Marshal(&common.TaskToken{ - WorkflowID: we.WorkflowID, - RunID: we.RunID, - ScheduleID: 2, - }) - identity := "testIdentity" - executionContext := []byte("context") - - msBuilder := execution.NewMutableStateBuilderWithEventV2( - s.mockHistoryEngine.shard, - testlogger.New(s.Suite.T()), - we.GetRunID(), - constants.TestLocalDomainEntry, - ) - test.AddWorkflowExecutionStartedEvent(msBuilder, we, "wType", tl, []byte("input"), 100, 200, identity) - di := test.AddDecisionTaskScheduledEvent(msBuilder) - test.AddDecisionTaskStartedEvent(msBuilder, di.ScheduleID, tl, identity) - - abandon := types.ParentClosePolicyAbandon - decisions := []*types.Decision{{ - DecisionType: types.DecisionTypeStartChildWorkflowExecution.Ptr(), - StartChildWorkflowExecutionDecisionAttributes: &types.StartChildWorkflowExecutionDecisionAttributes{ - Domain: constants.TestDomainName, - WorkflowID: "child-workflow-id", - WorkflowType: &types.WorkflowType{ - Name: "child-workflow-type", - }, - ParentClosePolicy: &abandon, - }, - }} - - ms := execution.CreatePersistenceMutableState(msBuilder) - gwmsResponse := &persistence.GetWorkflowExecutionResponse{State: ms} - - s.mockExecutionMgr.On("GetWorkflowExecution", mock.Anything, mock.Anything).Return(gwmsResponse, nil).Once() - s.mockHistoryV2Mgr.On("AppendHistoryNodes", mock.Anything, mock.Anything).Return(&persistence.AppendHistoryNodesResponse{}, nil).Once() - s.mockExecutionMgr.On("UpdateWorkflowExecution", mock.Anything, mock.Anything).Return(&persistence.UpdateWorkflowExecutionResponse{MutableStateUpdateSessionStats: &persistence.MutableStateUpdateSessionStats{}}, nil).Once() - - _, err := s.mockHistoryEngine.RespondDecisionTaskCompleted(context.Background(), &types.HistoryRespondDecisionTaskCompletedRequest{ - DomainUUID: constants.TestDomainID, - CompleteRequest: &types.RespondDecisionTaskCompletedRequest{ - TaskToken: taskToken, - Decisions: decisions, - ExecutionContext: executionContext, - Identity: identity, - }, - }) - s.Nil(err, s.printHistory(msBuilder)) - executionBuilder := s.getBuilder(constants.TestDomainID, we) - s.Equal(int64(6), executionBuilder.GetExecutionInfo().NextEventID) - s.Equal(int64(3), executionBuilder.GetExecutionInfo().LastProcessedEvent) - s.Equal(executionContext, executionBuilder.GetExecutionInfo().ExecutionContext) - s.Equal(int(1), len(executionBuilder.GetPendingChildExecutionInfos())) - var childID int64 - for c := range executionBuilder.GetPendingChildExecutionInfos() { - childID = c - break - } - s.Equal("child-workflow-id", executionBuilder.GetPendingChildExecutionInfos()[childID].StartedWorkflowID) - s.Equal(types.ParentClosePolicyAbandon, executionBuilder.GetPendingChildExecutionInfos()[childID].ParentClosePolicy) -} - -func (s *engineSuite) TestRespondDecisionTaskCompletedStartChildWorkflowWithTerminatePolicy() { - - we := types.WorkflowExecution{ - WorkflowID: "wId", - RunID: constants.TestRunID, - } - tl := "testTaskList" - taskToken, _ := json.Marshal(&common.TaskToken{ - WorkflowID: we.WorkflowID, - RunID: we.RunID, - ScheduleID: 2, - }) - identity := "testIdentity" - executionContext := []byte("context") - - msBuilder := execution.NewMutableStateBuilderWithEventV2( - s.mockHistoryEngine.shard, - testlogger.New(s.Suite.T()), - we.GetRunID(), - constants.TestLocalDomainEntry, - ) - test.AddWorkflowExecutionStartedEvent(msBuilder, we, "wType", tl, []byte("input"), 100, 200, identity) - di := test.AddDecisionTaskScheduledEvent(msBuilder) - test.AddDecisionTaskStartedEvent(msBuilder, di.ScheduleID, tl, identity) - - terminate := types.ParentClosePolicyTerminate - decisions := []*types.Decision{{ - DecisionType: types.DecisionTypeStartChildWorkflowExecution.Ptr(), - StartChildWorkflowExecutionDecisionAttributes: &types.StartChildWorkflowExecutionDecisionAttributes{ - Domain: constants.TestDomainName, - WorkflowID: "child-workflow-id", - WorkflowType: &types.WorkflowType{ - Name: "child-workflow-type", - }, - ParentClosePolicy: &terminate, - }, - }} - - ms := execution.CreatePersistenceMutableState(msBuilder) - gwmsResponse := &persistence.GetWorkflowExecutionResponse{State: ms} - - s.mockExecutionMgr.On("GetWorkflowExecution", mock.Anything, mock.Anything).Return(gwmsResponse, nil).Once() - s.mockHistoryV2Mgr.On("AppendHistoryNodes", mock.Anything, mock.Anything).Return(&persistence.AppendHistoryNodesResponse{}, nil).Once() - s.mockExecutionMgr.On("UpdateWorkflowExecution", mock.Anything, mock.Anything).Return(&persistence.UpdateWorkflowExecutionResponse{MutableStateUpdateSessionStats: &persistence.MutableStateUpdateSessionStats{}}, nil).Once() - - _, err := s.mockHistoryEngine.RespondDecisionTaskCompleted(context.Background(), &types.HistoryRespondDecisionTaskCompletedRequest{ - DomainUUID: constants.TestDomainID, - CompleteRequest: &types.RespondDecisionTaskCompletedRequest{ - TaskToken: taskToken, - Decisions: decisions, - ExecutionContext: executionContext, - Identity: identity, - }, - }) - s.Nil(err, s.printHistory(msBuilder)) - executionBuilder := s.getBuilder(constants.TestDomainID, we) - s.Equal(int64(6), executionBuilder.GetExecutionInfo().NextEventID) - s.Equal(int64(3), executionBuilder.GetExecutionInfo().LastProcessedEvent) - s.Equal(executionContext, executionBuilder.GetExecutionInfo().ExecutionContext) - s.Equal(int(1), len(executionBuilder.GetPendingChildExecutionInfos())) - var childID int64 - for c := range executionBuilder.GetPendingChildExecutionInfos() { - childID = c - break - } - s.Equal("child-workflow-id", executionBuilder.GetPendingChildExecutionInfos()[childID].StartedWorkflowID) - s.Equal(types.ParentClosePolicyTerminate, executionBuilder.GetPendingChildExecutionInfos()[childID].ParentClosePolicy) -} - -func (s *engineSuite) TestRespondDecisionTaskCompletedSignalExternalWorkflowFailed() { - - we := types.WorkflowExecution{ - WorkflowID: "wId", - RunID: "invalid run id", - } - tl := "testTaskList" - taskToken, _ := json.Marshal(&common.TaskToken{ - WorkflowID: we.GetWorkflowID(), - RunID: we.GetRunID(), - ScheduleID: 2, - }) - identity := "testIdentity" - executionContext := []byte("context") - - msBuilder := execution.NewMutableStateBuilderWithEventV2( - s.mockHistoryEngine.shard, - testlogger.New(s.Suite.T()), - we.GetRunID(), - constants.TestLocalDomainEntry, - ) - test.AddWorkflowExecutionStartedEvent(msBuilder, we, "wType", tl, []byte("input"), 100, 200, identity) - di := test.AddDecisionTaskScheduledEvent(msBuilder) - test.AddDecisionTaskStartedEvent(msBuilder, di.ScheduleID, tl, identity) - - decisions := []*types.Decision{{ - DecisionType: types.DecisionTypeSignalExternalWorkflowExecution.Ptr(), - SignalExternalWorkflowExecutionDecisionAttributes: &types.SignalExternalWorkflowExecutionDecisionAttributes{ - Domain: constants.TestDomainID, - Execution: &types.WorkflowExecution{ - WorkflowID: we.WorkflowID, - RunID: we.RunID, - }, - SignalName: "signal", - Input: []byte("test input"), - }, - }} - - _, err := s.mockHistoryEngine.RespondDecisionTaskCompleted(context.Background(), &types.HistoryRespondDecisionTaskCompletedRequest{ - DomainUUID: constants.TestDomainID, - CompleteRequest: &types.RespondDecisionTaskCompletedRequest{ - TaskToken: taskToken, - Decisions: decisions, - ExecutionContext: executionContext, - Identity: identity, - }, - }) - - s.EqualError(err, "RunID is not valid UUID.") -} - -func (s *engineSuite) TestRespondDecisionTaskCompletedSignalExternalWorkflowFailed_UnKnownDomain() { - - we := types.WorkflowExecution{ - WorkflowID: "wId", - RunID: constants.TestRunID, - } - tl := "testTaskList" - taskToken, _ := json.Marshal(&common.TaskToken{ - WorkflowID: we.WorkflowID, - RunID: we.RunID, - ScheduleID: 2, - }) - identity := "testIdentity" - executionContext := []byte("context") - foreignDomain := "unknown domain" - - msBuilder := execution.NewMutableStateBuilderWithEventV2( - s.mockHistoryEngine.shard, - testlogger.New(s.Suite.T()), - we.GetRunID(), - constants.TestLocalDomainEntry, - ) - test.AddWorkflowExecutionStartedEvent(msBuilder, we, "wType", tl, []byte("input"), 100, 200, identity) - di := test.AddDecisionTaskScheduledEvent(msBuilder) - test.AddDecisionTaskStartedEvent(msBuilder, di.ScheduleID, tl, identity) - - decisions := []*types.Decision{{ - DecisionType: types.DecisionTypeSignalExternalWorkflowExecution.Ptr(), - SignalExternalWorkflowExecutionDecisionAttributes: &types.SignalExternalWorkflowExecutionDecisionAttributes{ - Domain: foreignDomain, - Execution: &types.WorkflowExecution{ - WorkflowID: we.WorkflowID, - RunID: we.RunID, - }, - SignalName: "signal", - Input: []byte("test input"), - }, - }} - - ms := execution.CreatePersistenceMutableState(msBuilder) - gwmsResponse := &persistence.GetWorkflowExecutionResponse{State: ms} - - s.mockExecutionMgr.On("GetWorkflowExecution", mock.Anything, mock.Anything).Return(gwmsResponse, nil).Once() - s.mockDomainCache.EXPECT().GetDomain(foreignDomain).Return( - nil, errors.New("get foreign domain error"), - ).Times(1) - - _, err := s.mockHistoryEngine.RespondDecisionTaskCompleted(context.Background(), &types.HistoryRespondDecisionTaskCompletedRequest{ - DomainUUID: constants.TestDomainID, - CompleteRequest: &types.RespondDecisionTaskCompletedRequest{ - TaskToken: taskToken, - Decisions: decisions, - ExecutionContext: executionContext, - Identity: identity, - }, - }) - - s.NotNil(err) -} - -func (s *engineSuite) TestRespondActivityTaskCompletedInvalidToken() { - - invalidToken, _ := json.Marshal("bad token") - identity := "testIdentity" - - err := s.mockHistoryEngine.RespondActivityTaskCompleted(context.Background(), &types.HistoryRespondActivityTaskCompletedRequest{ - DomainUUID: constants.TestDomainID, - CompleteRequest: &types.RespondActivityTaskCompletedRequest{ - TaskToken: invalidToken, - Result: nil, - Identity: identity, - }, - }) - - s.NotNil(err) - s.IsType(&types.BadRequestError{}, err) -} - -func (s *engineSuite) TestRespondActivityTaskCompletedIfNoExecution() { - - taskToken, _ := json.Marshal(&common.TaskToken{ - WorkflowID: "wId", - RunID: constants.TestRunID, - ScheduleID: 2, - }) - identity := "testIdentity" - - s.mockExecutionMgr.On("GetWorkflowExecution", mock.Anything, mock.Anything).Return(nil, &types.EntityNotExistsError{}).Once() - - err := s.mockHistoryEngine.RespondActivityTaskCompleted(context.Background(), &types.HistoryRespondActivityTaskCompletedRequest{ - DomainUUID: constants.TestDomainID, - CompleteRequest: &types.RespondActivityTaskCompletedRequest{ - TaskToken: taskToken, - Identity: identity, - }, - }) - s.NotNil(err) - s.IsType(&types.EntityNotExistsError{}, err) -} - -func (s *engineSuite) TestRespondActivityTaskCompletedIfNoRunID() { - - taskToken, _ := json.Marshal(&common.TaskToken{ - WorkflowID: "wId", - ScheduleID: 2, - }) - identity := "testIdentity" - - s.mockExecutionMgr.On("GetCurrentExecution", mock.Anything, mock.Anything).Return(nil, &types.EntityNotExistsError{}).Once() - - err := s.mockHistoryEngine.RespondActivityTaskCompleted(context.Background(), &types.HistoryRespondActivityTaskCompletedRequest{ - DomainUUID: constants.TestDomainID, - CompleteRequest: &types.RespondActivityTaskCompletedRequest{ - TaskToken: taskToken, - Identity: identity, - }, - }) - s.NotNil(err) - s.IsType(&types.EntityNotExistsError{}, err) -} - -func (s *engineSuite) TestRespondActivityTaskCompletedIfGetExecutionFailed() { - - taskToken, _ := json.Marshal(&common.TaskToken{ - WorkflowID: "wId", - RunID: constants.TestRunID, - ScheduleID: 2, - }) - identity := "testIdentity" - - s.mockExecutionMgr.On("GetWorkflowExecution", mock.Anything, mock.Anything).Return(nil, errors.New("FAILED")).Once() - - err := s.mockHistoryEngine.RespondActivityTaskCompleted(context.Background(), &types.HistoryRespondActivityTaskCompletedRequest{ - DomainUUID: constants.TestDomainID, - CompleteRequest: &types.RespondActivityTaskCompletedRequest{ - TaskToken: taskToken, - Identity: identity, - }, - }) - s.EqualError(err, "FAILED") -} - -func (s *engineSuite) TestRespondActivityTaskCompletedIfNoAIdProvided() { - - workflowExecution := types.WorkflowExecution{ - WorkflowID: "wId", - RunID: constants.TestRunID, - } - tasklist := "testTaskList" - identity := "testIdentity" - taskToken, _ := json.Marshal(&common.TaskToken{ - WorkflowID: "wId", - ScheduleID: common.EmptyEventID, - }) - - msBuilder := execution.NewMutableStateBuilderWithEventV2( - s.mockHistoryEngine.shard, - testlogger.New(s.Suite.T()), - constants.TestRunID, - constants.TestLocalDomainEntry, - ) - test.AddWorkflowExecutionStartedEvent(msBuilder, workflowExecution, "wType", tasklist, []byte("input"), 100, 200, identity) - test.AddDecisionTaskScheduledEvent(msBuilder) - ms := execution.CreatePersistenceMutableState(msBuilder) - gwmsResponse := &persistence.GetWorkflowExecutionResponse{State: ms} - gceResponse := &persistence.GetCurrentExecutionResponse{RunID: constants.TestRunID} - - s.mockExecutionMgr.On("GetCurrentExecution", mock.Anything, mock.Anything).Return(gceResponse, nil).Once() - s.mockExecutionMgr.On("GetWorkflowExecution", mock.Anything, mock.Anything).Return(gwmsResponse, nil).Once() - - err := s.mockHistoryEngine.RespondActivityTaskCompleted(context.Background(), &types.HistoryRespondActivityTaskCompletedRequest{ - DomainUUID: constants.TestDomainID, - CompleteRequest: &types.RespondActivityTaskCompletedRequest{ - TaskToken: taskToken, - Identity: identity, - }, - }) - s.EqualError(err, "Neither ActivityID nor ScheduleID is provided") -} - -func (s *engineSuite) TestRespondActivityTaskCompletedIfNotFound() { - - taskToken, _ := json.Marshal(&common.TaskToken{ - WorkflowID: "wId", - ScheduleID: common.EmptyEventID, - ActivityID: "aid", - }) - workflowExecution := types.WorkflowExecution{ - WorkflowID: "wId", - RunID: constants.TestRunID, - } - tasklist := "testTaskList" - identity := "testIdentity" - - msBuilder := execution.NewMutableStateBuilderWithEventV2( - s.mockHistoryEngine.shard, - testlogger.New(s.Suite.T()), - constants.TestRunID, - constants.TestLocalDomainEntry, - ) - test.AddWorkflowExecutionStartedEvent(msBuilder, workflowExecution, "wType", tasklist, []byte("input"), 100, 200, identity) - test.AddDecisionTaskScheduledEvent(msBuilder) - ms := execution.CreatePersistenceMutableState(msBuilder) - gwmsResponse := &persistence.GetWorkflowExecutionResponse{State: ms} - gceResponse := &persistence.GetCurrentExecutionResponse{RunID: constants.TestRunID} - - s.mockExecutionMgr.On("GetCurrentExecution", mock.Anything, mock.Anything).Return(gceResponse, nil).Once() - s.mockExecutionMgr.On("GetWorkflowExecution", mock.Anything, mock.Anything).Return(gwmsResponse, nil).Once() - - err := s.mockHistoryEngine.RespondActivityTaskCompleted(context.Background(), &types.HistoryRespondActivityTaskCompletedRequest{ - DomainUUID: constants.TestDomainID, - CompleteRequest: &types.RespondActivityTaskCompletedRequest{ - TaskToken: taskToken, - Identity: identity, - }, - }) - s.Error(err) -} - -func (s *engineSuite) TestRespondActivityTaskCompletedUpdateExecutionFailed() { - - we := types.WorkflowExecution{ - WorkflowID: "wId", - RunID: constants.TestRunID, - } - tl := "testTaskList" - taskToken, _ := json.Marshal(&common.TaskToken{ - WorkflowID: we.WorkflowID, - RunID: we.RunID, - ScheduleID: 5, - }) - identity := "testIdentity" - activityID := "activity1_id" - activityType := "activity_type1" - activityInput := []byte("input1") - activityResult := []byte("activity result") - - msBuilder := execution.NewMutableStateBuilderWithEventV2( - s.mockHistoryEngine.shard, - testlogger.New(s.Suite.T()), - we.GetRunID(), - constants.TestLocalDomainEntry, - ) - test.AddWorkflowExecutionStartedEvent(msBuilder, we, "wType", tl, []byte("input"), 100, 200, identity) - di := test.AddDecisionTaskScheduledEvent(msBuilder) - decisionStartedEvent := test.AddDecisionTaskStartedEvent(msBuilder, di.ScheduleID, tl, identity) - decisionCompletedEvent := test.AddDecisionTaskCompletedEvent(msBuilder, di.ScheduleID, - decisionStartedEvent.ID, nil, identity) - activityScheduledEvent, _ := test.AddActivityTaskScheduledEvent(msBuilder, decisionCompletedEvent.ID, activityID, - activityType, tl, activityInput, 100, 10, 1, 5) - test.AddActivityTaskStartedEvent(msBuilder, activityScheduledEvent.ID, identity) - - ms := execution.CreatePersistenceMutableState(msBuilder) - gwmsResponse := &persistence.GetWorkflowExecutionResponse{State: ms} - - s.mockExecutionMgr.On("GetWorkflowExecution", mock.Anything, mock.Anything).Return(gwmsResponse, nil).Once() - s.mockHistoryV2Mgr.On("AppendHistoryNodes", mock.Anything, mock.Anything).Return(&persistence.AppendHistoryNodesResponse{}, nil).Once() - s.mockExecutionMgr.On("UpdateWorkflowExecution", mock.Anything, mock.Anything).Return(&persistence.UpdateWorkflowExecutionResponse{MutableStateUpdateSessionStats: &persistence.MutableStateUpdateSessionStats{}}, errors.New("FAILED")).Once() - s.mockShardManager.On("UpdateShard", mock.Anything, mock.Anything).Return(nil).Once() - - err := s.mockHistoryEngine.RespondActivityTaskCompleted(context.Background(), &types.HistoryRespondActivityTaskCompletedRequest{ - DomainUUID: constants.TestDomainID, - CompleteRequest: &types.RespondActivityTaskCompletedRequest{ - TaskToken: taskToken, - Result: activityResult, - Identity: identity, - }, - }) - s.EqualError(err, "FAILED") -} - -func (s *engineSuite) TestRespondActivityTaskCompletedIfTaskCompleted() { - - we := types.WorkflowExecution{ - WorkflowID: "wId", - RunID: constants.TestRunID, - } - tl := "testTaskList" - taskToken, _ := json.Marshal(&common.TaskToken{ - WorkflowID: we.WorkflowID, - RunID: we.RunID, - ScheduleID: 5, - }) - identity := "testIdentity" - activityID := "activity1_id" - activityType := "activity_type1" - activityInput := []byte("input1") - activityResult := []byte("activity result") - - msBuilder := execution.NewMutableStateBuilderWithEventV2( - s.mockHistoryEngine.shard, - testlogger.New(s.Suite.T()), - we.GetRunID(), - constants.TestLocalDomainEntry, - ) - test.AddWorkflowExecutionStartedEvent(msBuilder, we, "wType", tl, []byte("input"), 100, 200, identity) - di := test.AddDecisionTaskScheduledEvent(msBuilder) - decisionStartedEvent := test.AddDecisionTaskStartedEvent(msBuilder, di.ScheduleID, tl, identity) - decisionCompletedEvent := test.AddDecisionTaskCompletedEvent(msBuilder, di.ScheduleID, - decisionStartedEvent.ID, nil, identity) - activityScheduledEvent, _ := test.AddActivityTaskScheduledEvent(msBuilder, decisionCompletedEvent.ID, activityID, - activityType, tl, activityInput, 100, 10, 1, 5) - activityStartedEvent := test.AddActivityTaskStartedEvent(msBuilder, activityScheduledEvent.ID, identity) - test.AddActivityTaskCompletedEvent(msBuilder, activityScheduledEvent.ID, activityStartedEvent.ID, - activityResult, identity) - test.AddDecisionTaskScheduledEvent(msBuilder) - - ms := execution.CreatePersistenceMutableState(msBuilder) - gwmsResponse := &persistence.GetWorkflowExecutionResponse{State: ms} - - s.mockExecutionMgr.On("GetWorkflowExecution", mock.Anything, mock.Anything).Return(gwmsResponse, nil).Once() - - err := s.mockHistoryEngine.RespondActivityTaskCompleted(context.Background(), &types.HistoryRespondActivityTaskCompletedRequest{ - DomainUUID: constants.TestDomainID, - CompleteRequest: &types.RespondActivityTaskCompletedRequest{ - TaskToken: taskToken, - Result: activityResult, - Identity: identity, - }, - }) - s.NotNil(err) - s.IsType(&types.EntityNotExistsError{}, err) -} - -func (s *engineSuite) TestRespondActivityTaskCompletedIfTaskNotStarted() { - - we := types.WorkflowExecution{ - WorkflowID: "wId", - RunID: constants.TestRunID, - } - tl := "testTaskList" - taskToken, _ := json.Marshal(&common.TaskToken{ - WorkflowID: we.WorkflowID, - RunID: we.RunID, - ScheduleID: 5, - }) - identity := "testIdentity" - activityID := "activity1_id" - activityType := "activity_type1" - activityInput := []byte("input1") - activityResult := []byte("activity result") - - msBuilder := execution.NewMutableStateBuilderWithEventV2( - s.mockHistoryEngine.shard, - testlogger.New(s.Suite.T()), - we.GetRunID(), - constants.TestLocalDomainEntry, - ) - test.AddWorkflowExecutionStartedEvent(msBuilder, we, "wType", tl, []byte("input"), 100, 200, identity) - di := test.AddDecisionTaskScheduledEvent(msBuilder) - decisionStartedEvent := test.AddDecisionTaskStartedEvent(msBuilder, di.ScheduleID, tl, identity) - decisionCompletedEvent := test.AddDecisionTaskCompletedEvent(msBuilder, di.ScheduleID, - decisionStartedEvent.ID, nil, identity) - test.AddActivityTaskScheduledEvent(msBuilder, decisionCompletedEvent.ID, activityID, - activityType, tl, activityInput, 100, 10, 1, 5) - - ms := execution.CreatePersistenceMutableState(msBuilder) - gwmsResponse := &persistence.GetWorkflowExecutionResponse{State: ms} - - s.mockExecutionMgr.On("GetWorkflowExecution", mock.Anything, mock.Anything).Return(gwmsResponse, nil).Once() - - err := s.mockHistoryEngine.RespondActivityTaskCompleted(context.Background(), &types.HistoryRespondActivityTaskCompletedRequest{ - DomainUUID: constants.TestDomainID, - CompleteRequest: &types.RespondActivityTaskCompletedRequest{ - TaskToken: taskToken, - Result: activityResult, - Identity: identity, - }, - }) - s.NotNil(err) - s.IsType(&types.EntityNotExistsError{}, err) -} - -func (s *engineSuite) TestRespondActivityTaskCompletedConflictOnUpdate() { - - we := types.WorkflowExecution{ - WorkflowID: "wId", - RunID: constants.TestRunID, - } - tl := "testTaskList" - taskToken, _ := json.Marshal(&common.TaskToken{ - WorkflowID: we.WorkflowID, - RunID: we.RunID, - ScheduleID: 5, - }) - identity := "testIdentity" - activity1ID := "activity1" - activity1Type := "activity_type1" - activity1Input := []byte("input1") - activity1Result := []byte("activity1_result") - activity2ID := "activity2" - activity2Type := "activity_type2" - activity2Input := []byte("input2") - - msBuilder := execution.NewMutableStateBuilderWithEventV2( - s.mockHistoryEngine.shard, - testlogger.New(s.Suite.T()), - we.GetRunID(), - constants.TestLocalDomainEntry, - ) - test.AddWorkflowExecutionStartedEvent(msBuilder, we, "wType", tl, []byte("input"), 100, 100, identity) - di := test.AddDecisionTaskScheduledEvent(msBuilder) - decisionStartedEvent1 := test.AddDecisionTaskStartedEvent(msBuilder, di.ScheduleID, tl, identity) - decisionCompletedEvent1 := test.AddDecisionTaskCompletedEvent(msBuilder, di.ScheduleID, - decisionStartedEvent1.ID, nil, identity) - activity1ScheduledEvent, _ := test.AddActivityTaskScheduledEvent(msBuilder, decisionCompletedEvent1.ID, activity1ID, - activity1Type, tl, activity1Input, 100, 10, 1, 5) - activity2ScheduledEvent, _ := test.AddActivityTaskScheduledEvent(msBuilder, decisionCompletedEvent1.ID, activity2ID, - activity2Type, tl, activity2Input, 100, 10, 1, 5) - test.AddActivityTaskStartedEvent(msBuilder, activity1ScheduledEvent.ID, identity) - test.AddActivityTaskStartedEvent(msBuilder, activity2ScheduledEvent.ID, identity) - - ms1 := execution.CreatePersistenceMutableState(msBuilder) - gwmsResponse1 := &persistence.GetWorkflowExecutionResponse{State: ms1} - - ms2 := execution.CreatePersistenceMutableState(msBuilder) - gwmsResponse2 := &persistence.GetWorkflowExecutionResponse{State: ms2} - - s.mockExecutionMgr.On("GetWorkflowExecution", mock.Anything, mock.Anything).Return(gwmsResponse1, nil).Once() - s.mockHistoryV2Mgr.On("AppendHistoryNodes", mock.Anything, mock.Anything).Return(&persistence.AppendHistoryNodesResponse{}, nil).Once() - s.mockExecutionMgr.On("UpdateWorkflowExecution", mock.Anything, mock.Anything).Return(&persistence.UpdateWorkflowExecutionResponse{MutableStateUpdateSessionStats: &persistence.MutableStateUpdateSessionStats{}}, &persistence.ConditionFailedError{}).Once() - - s.mockExecutionMgr.On("GetWorkflowExecution", mock.Anything, mock.Anything).Return(gwmsResponse2, nil).Once() - s.mockHistoryV2Mgr.On("AppendHistoryNodes", mock.Anything, mock.Anything).Return(&persistence.AppendHistoryNodesResponse{}, nil).Once() - s.mockExecutionMgr.On("UpdateWorkflowExecution", mock.Anything, mock.Anything).Return(&persistence.UpdateWorkflowExecutionResponse{MutableStateUpdateSessionStats: &persistence.MutableStateUpdateSessionStats{}}, nil).Once() - - err := s.mockHistoryEngine.RespondActivityTaskCompleted(context.Background(), &types.HistoryRespondActivityTaskCompletedRequest{ - DomainUUID: constants.TestDomainID, - CompleteRequest: &types.RespondActivityTaskCompletedRequest{ - TaskToken: taskToken, - Result: activity1Result, - Identity: identity, - }, - }) - s.Nil(err, s.printHistory(msBuilder)) - executionBuilder := s.getBuilder(constants.TestDomainID, we) - s.Equal(int64(11), executionBuilder.GetExecutionInfo().NextEventID) - s.Equal(int64(3), executionBuilder.GetExecutionInfo().LastProcessedEvent) - s.Equal(persistence.WorkflowStateRunning, executionBuilder.GetExecutionInfo().State) - - s.True(executionBuilder.HasPendingDecision()) - di, ok := executionBuilder.GetDecisionInfo(int64(10)) - s.True(ok) - s.Equal(int32(100), di.DecisionTimeout) - s.Equal(int64(10), di.ScheduleID) - s.Equal(common.EmptyEventID, di.StartedID) -} - -func (s *engineSuite) TestRespondActivityTaskCompletedMaxAttemptsExceeded() { - - we := types.WorkflowExecution{ - WorkflowID: "wId", - RunID: constants.TestRunID, - } - tl := "testTaskList" - taskToken, _ := json.Marshal(&common.TaskToken{ - WorkflowID: we.WorkflowID, - RunID: we.RunID, - ScheduleID: 5, - }) - identity := "testIdentity" - activityID := "activity1_id" - activityType := "activity_type1" - activityInput := []byte("input1") - activityResult := []byte("activity result") - - msBuilder := execution.NewMutableStateBuilderWithEventV2( - s.mockHistoryEngine.shard, - testlogger.New(s.Suite.T()), - we.GetRunID(), - constants.TestLocalDomainEntry, - ) - test.AddWorkflowExecutionStartedEvent(msBuilder, we, "wType", tl, []byte("input"), 100, 100, identity) - di := test.AddDecisionTaskScheduledEvent(msBuilder) - decisionStartedEvent := test.AddDecisionTaskStartedEvent(msBuilder, di.ScheduleID, tl, identity) - decisionCompletedEvent := test.AddDecisionTaskCompletedEvent(msBuilder, di.ScheduleID, - decisionStartedEvent.ID, nil, identity) - activityScheduledEvent, _ := test.AddActivityTaskScheduledEvent(msBuilder, decisionCompletedEvent.ID, activityID, - activityType, tl, activityInput, 100, 10, 1, 5) - test.AddActivityTaskStartedEvent(msBuilder, activityScheduledEvent.ID, identity) - - for i := 0; i < workflow.ConditionalRetryCount; i++ { - ms := execution.CreatePersistenceMutableState(msBuilder) - gwmsResponse := &persistence.GetWorkflowExecutionResponse{State: ms} - - s.mockExecutionMgr.On("GetWorkflowExecution", mock.Anything, mock.Anything).Return(gwmsResponse, nil).Once() - s.mockHistoryV2Mgr.On("AppendHistoryNodes", mock.Anything, mock.Anything).Return(&persistence.AppendHistoryNodesResponse{}, nil).Once() - s.mockExecutionMgr.On("UpdateWorkflowExecution", mock.Anything, mock.Anything).Return(&persistence.UpdateWorkflowExecutionResponse{MutableStateUpdateSessionStats: &persistence.MutableStateUpdateSessionStats{}}, &persistence.ConditionFailedError{}).Once() - } - - err := s.mockHistoryEngine.RespondActivityTaskCompleted(context.Background(), &types.HistoryRespondActivityTaskCompletedRequest{ - DomainUUID: constants.TestDomainID, - CompleteRequest: &types.RespondActivityTaskCompletedRequest{ - TaskToken: taskToken, - Result: activityResult, - Identity: identity, - }, - }) - s.Equal(workflow.ErrMaxAttemptsExceeded, err) -} - -func (s *engineSuite) TestRespondActivityTaskCompletedSuccess() { - - we := types.WorkflowExecution{ - WorkflowID: "wId", - RunID: constants.TestRunID, - } - tl := "testTaskList" - taskToken, _ := json.Marshal(&common.TaskToken{ - WorkflowID: we.WorkflowID, - RunID: we.RunID, - ScheduleID: 5, - }) - identity := "testIdentity" - activityID := "activity1_id" - activityType := "activity_type1" - activityInput := []byte("input1") - activityResult := []byte("activity result") - - msBuilder := execution.NewMutableStateBuilderWithEventV2( - s.mockHistoryEngine.shard, - testlogger.New(s.Suite.T()), - we.GetRunID(), - constants.TestLocalDomainEntry, - ) - test.AddWorkflowExecutionStartedEvent(msBuilder, we, "wType", tl, []byte("input"), 100, 100, identity) - di := test.AddDecisionTaskScheduledEvent(msBuilder) - decisionStartedEvent := test.AddDecisionTaskStartedEvent(msBuilder, di.ScheduleID, tl, identity) - decisionCompletedEvent := test.AddDecisionTaskCompletedEvent(msBuilder, di.ScheduleID, - decisionStartedEvent.ID, nil, identity) - activityScheduledEvent, _ := test.AddActivityTaskScheduledEvent(msBuilder, decisionCompletedEvent.ID, activityID, - activityType, tl, activityInput, 100, 10, 1, 5) - test.AddActivityTaskStartedEvent(msBuilder, activityScheduledEvent.ID, identity) - - ms := execution.CreatePersistenceMutableState(msBuilder) - gwmsResponse := &persistence.GetWorkflowExecutionResponse{State: ms} - - s.mockExecutionMgr.On("GetWorkflowExecution", mock.Anything, mock.Anything).Return(gwmsResponse, nil).Once() - s.mockHistoryV2Mgr.On("AppendHistoryNodes", mock.Anything, mock.Anything).Return(&persistence.AppendHistoryNodesResponse{}, nil).Once() - s.mockExecutionMgr.On("UpdateWorkflowExecution", mock.Anything, mock.Anything).Return(&persistence.UpdateWorkflowExecutionResponse{MutableStateUpdateSessionStats: &persistence.MutableStateUpdateSessionStats{}}, nil).Once() - - err := s.mockHistoryEngine.RespondActivityTaskCompleted(context.Background(), &types.HistoryRespondActivityTaskCompletedRequest{ - DomainUUID: constants.TestDomainID, - CompleteRequest: &types.RespondActivityTaskCompletedRequest{ - TaskToken: taskToken, - Result: activityResult, - Identity: identity, - }, - }) - s.Nil(err, s.printHistory(msBuilder)) - executionBuilder := s.getBuilder(constants.TestDomainID, we) - s.Equal(int64(9), executionBuilder.GetExecutionInfo().NextEventID) - s.Equal(int64(3), executionBuilder.GetExecutionInfo().LastProcessedEvent) - s.Equal(persistence.WorkflowStateRunning, executionBuilder.GetExecutionInfo().State) - - s.True(executionBuilder.HasPendingDecision()) - di, ok := executionBuilder.GetDecisionInfo(int64(8)) - s.True(ok) - s.Equal(int32(100), di.DecisionTimeout) - s.Equal(int64(8), di.ScheduleID) - s.Equal(common.EmptyEventID, di.StartedID) -} - -func (s *engineSuite) TestRespondActivityTaskCompletedByIdSuccess() { - - we := types.WorkflowExecution{ - WorkflowID: "wId", - RunID: constants.TestRunID, - } - tl := "testTaskList" - - identity := "testIdentity" - activityID := "activity1_id" - activityType := "activity_type1" - activityInput := []byte("input1") - activityResult := []byte("activity result") - taskToken, _ := json.Marshal(&common.TaskToken{ - WorkflowID: we.WorkflowID, - ScheduleID: common.EmptyEventID, - ActivityID: activityID, - }) - - msBuilder := execution.NewMutableStateBuilderWithEventV2( - s.mockHistoryEngine.shard, - testlogger.New(s.Suite.T()), - we.GetRunID(), - constants.TestLocalDomainEntry, - ) - test.AddWorkflowExecutionStartedEvent(msBuilder, we, "wType", tl, []byte("input"), 100, 100, identity) - decisionScheduledEvent := test.AddDecisionTaskScheduledEvent(msBuilder) - decisionStartedEvent := test.AddDecisionTaskStartedEvent(msBuilder, decisionScheduledEvent.ScheduleID, tl, identity) - decisionCompletedEvent := test.AddDecisionTaskCompletedEvent(msBuilder, decisionScheduledEvent.ScheduleID, - decisionStartedEvent.ID, nil, identity) - activityScheduledEvent, _ := test.AddActivityTaskScheduledEvent(msBuilder, decisionCompletedEvent.ID, activityID, - activityType, tl, activityInput, 100, 10, 1, 5) - test.AddActivityTaskStartedEvent(msBuilder, activityScheduledEvent.ID, identity) - - ms := execution.CreatePersistenceMutableState(msBuilder) - gwmsResponse := &persistence.GetWorkflowExecutionResponse{State: ms} - gceResponse := &persistence.GetCurrentExecutionResponse{RunID: we.RunID} - - s.mockExecutionMgr.On("GetCurrentExecution", mock.Anything, mock.Anything).Return(gceResponse, nil).Once() - s.mockExecutionMgr.On("GetWorkflowExecution", mock.Anything, mock.Anything).Return(gwmsResponse, nil).Once() - s.mockHistoryV2Mgr.On("AppendHistoryNodes", mock.Anything, mock.Anything).Return(&persistence.AppendHistoryNodesResponse{}, nil).Once() - s.mockExecutionMgr.On("UpdateWorkflowExecution", mock.Anything, mock.Anything).Return(&persistence.UpdateWorkflowExecutionResponse{MutableStateUpdateSessionStats: &persistence.MutableStateUpdateSessionStats{}}, nil).Once() - - err := s.mockHistoryEngine.RespondActivityTaskCompleted(context.Background(), &types.HistoryRespondActivityTaskCompletedRequest{ - DomainUUID: constants.TestDomainID, - CompleteRequest: &types.RespondActivityTaskCompletedRequest{ - TaskToken: taskToken, - Result: activityResult, - Identity: identity, - }, - }) - s.Nil(err, s.printHistory(msBuilder)) - executionBuilder := s.getBuilder(constants.TestDomainID, we) - s.Equal(int64(9), executionBuilder.GetExecutionInfo().NextEventID) - s.Equal(int64(3), executionBuilder.GetExecutionInfo().LastProcessedEvent) - s.Equal(persistence.WorkflowStateRunning, executionBuilder.GetExecutionInfo().State) - - s.True(executionBuilder.HasPendingDecision()) - di, ok := executionBuilder.GetDecisionInfo(int64(8)) - s.True(ok) - s.Equal(int32(100), di.DecisionTimeout) - s.Equal(int64(8), di.ScheduleID) - s.Equal(common.EmptyEventID, di.StartedID) -} - -func (s *engineSuite) TestRespondActivityTaskFailedInvalidToken() { - - invalidToken, _ := json.Marshal("bad token") - identity := "testIdentity" - - err := s.mockHistoryEngine.RespondActivityTaskFailed(context.Background(), &types.HistoryRespondActivityTaskFailedRequest{ - DomainUUID: constants.TestDomainID, - FailedRequest: &types.RespondActivityTaskFailedRequest{ - TaskToken: invalidToken, - Identity: identity, - }, - }) - - s.NotNil(err) - s.IsType(&types.BadRequestError{}, err) -} - -func (s *engineSuite) TestRespondActivityTaskFailedIfNoExecution() { - - taskToken, _ := json.Marshal(&common.TaskToken{ - WorkflowID: "wId", - RunID: constants.TestRunID, - ScheduleID: 2, - }) - identity := "testIdentity" - - s.mockExecutionMgr.On("GetWorkflowExecution", mock.Anything, mock.Anything).Return(nil, - &types.EntityNotExistsError{}).Once() - - err := s.mockHistoryEngine.RespondActivityTaskFailed(context.Background(), &types.HistoryRespondActivityTaskFailedRequest{ - DomainUUID: constants.TestDomainID, - FailedRequest: &types.RespondActivityTaskFailedRequest{ - TaskToken: taskToken, - Identity: identity, - }, - }) - s.NotNil(err) - s.IsType(&types.EntityNotExistsError{}, err) -} - -func (s *engineSuite) TestRespondActivityTaskFailedIfNoRunID() { - - taskToken, _ := json.Marshal(&common.TaskToken{ - WorkflowID: "wId", - ScheduleID: 2, - }) - identity := "testIdentity" - - s.mockExecutionMgr.On("GetCurrentExecution", mock.Anything, mock.Anything).Return(nil, - &types.EntityNotExistsError{}).Once() - - err := s.mockHistoryEngine.RespondActivityTaskFailed(context.Background(), &types.HistoryRespondActivityTaskFailedRequest{ - DomainUUID: constants.TestDomainID, - FailedRequest: &types.RespondActivityTaskFailedRequest{ - TaskToken: taskToken, - Identity: identity, - }, - }) - s.NotNil(err) - s.IsType(&types.EntityNotExistsError{}, err) -} - -func (s *engineSuite) TestRespondActivityTaskFailedIfGetExecutionFailed() { - - taskToken, _ := json.Marshal(&common.TaskToken{ - WorkflowID: "wId", - RunID: constants.TestRunID, - ScheduleID: 2, - }) - identity := "testIdentity" - - s.mockExecutionMgr.On("GetWorkflowExecution", mock.Anything, mock.Anything).Return(nil, - errors.New("FAILED")).Once() - - err := s.mockHistoryEngine.RespondActivityTaskFailed(context.Background(), &types.HistoryRespondActivityTaskFailedRequest{ - DomainUUID: constants.TestDomainID, - FailedRequest: &types.RespondActivityTaskFailedRequest{ - TaskToken: taskToken, - Identity: identity, - }, - }) - s.EqualError(err, "FAILED") -} - -func (s *engineSuite) TestRespondActivityTaskFailededIfNoAIdProvided() { - - taskToken, _ := json.Marshal(&common.TaskToken{ - WorkflowID: "wId", - ScheduleID: common.EmptyEventID, - }) - workflowExecution := types.WorkflowExecution{ - WorkflowID: "wId", - RunID: constants.TestRunID, - } - tasklist := "testTaskList" - identity := "testIdentity" - - msBuilder := execution.NewMutableStateBuilderWithEventV2( - s.mockHistoryEngine.shard, - testlogger.New(s.Suite.T()), - constants.TestRunID, - constants.TestLocalDomainEntry, - ) - test.AddWorkflowExecutionStartedEvent(msBuilder, workflowExecution, "wType", tasklist, []byte("input"), 100, 200, identity) - test.AddDecisionTaskScheduledEvent(msBuilder) - ms := execution.CreatePersistenceMutableState(msBuilder) - gwmsResponse := &persistence.GetWorkflowExecutionResponse{State: ms} - gceResponse := &persistence.GetCurrentExecutionResponse{RunID: constants.TestRunID} - - s.mockExecutionMgr.On("GetCurrentExecution", mock.Anything, mock.Anything).Return(gceResponse, nil).Once() - s.mockExecutionMgr.On("GetWorkflowExecution", mock.Anything, mock.Anything).Return(gwmsResponse, nil).Once() - - err := s.mockHistoryEngine.RespondActivityTaskFailed(context.Background(), &types.HistoryRespondActivityTaskFailedRequest{ - DomainUUID: constants.TestDomainID, - FailedRequest: &types.RespondActivityTaskFailedRequest{ - TaskToken: taskToken, - Identity: identity, - }, - }) - s.EqualError(err, "Neither ActivityID nor ScheduleID is provided") -} - -func (s *engineSuite) TestRespondActivityTaskFailededIfNotFound() { - - taskToken, _ := json.Marshal(&common.TaskToken{ - WorkflowID: "wId", - ScheduleID: common.EmptyEventID, - ActivityID: "aid", - }) - workflowExecution := types.WorkflowExecution{ - WorkflowID: "wId", - RunID: constants.TestRunID, - } - tasklist := "testTaskList" - identity := "testIdentity" - - msBuilder := execution.NewMutableStateBuilderWithEventV2( - s.mockHistoryEngine.shard, - testlogger.New(s.Suite.T()), - constants.TestRunID, - constants.TestLocalDomainEntry, - ) - test.AddWorkflowExecutionStartedEvent(msBuilder, workflowExecution, "wType", tasklist, []byte("input"), 100, 200, identity) - test.AddDecisionTaskScheduledEvent(msBuilder) - ms := execution.CreatePersistenceMutableState(msBuilder) - gwmsResponse := &persistence.GetWorkflowExecutionResponse{State: ms} - gceResponse := &persistence.GetCurrentExecutionResponse{RunID: constants.TestRunID} - - s.mockExecutionMgr.On("GetCurrentExecution", mock.Anything, mock.Anything).Return(gceResponse, nil).Once() - s.mockExecutionMgr.On("GetWorkflowExecution", mock.Anything, mock.Anything).Return(gwmsResponse, nil).Once() - - err := s.mockHistoryEngine.RespondActivityTaskFailed(context.Background(), &types.HistoryRespondActivityTaskFailedRequest{ - DomainUUID: constants.TestDomainID, - FailedRequest: &types.RespondActivityTaskFailedRequest{ - TaskToken: taskToken, - Identity: identity, - }, - }) - s.Error(err) -} - -func (s *engineSuite) TestRespondActivityTaskFailedUpdateExecutionFailed() { - - we := types.WorkflowExecution{ - WorkflowID: "wId", - RunID: constants.TestRunID, - } - tl := "testTaskList" - taskToken, _ := json.Marshal(&common.TaskToken{ - WorkflowID: we.WorkflowID, - RunID: we.RunID, - ScheduleID: 5, - }) - identity := "testIdentity" - activityID := "activity1_id" - activityType := "activity_type1" - activityInput := []byte("input1") - - msBuilder := execution.NewMutableStateBuilderWithEventV2( - s.mockHistoryEngine.shard, - testlogger.New(s.Suite.T()), - we.GetRunID(), - constants.TestLocalDomainEntry, - ) - test.AddWorkflowExecutionStartedEvent(msBuilder, we, "wType", tl, []byte("input"), 100, 100, identity) - di := test.AddDecisionTaskScheduledEvent(msBuilder) - decisionStartedEvent := test.AddDecisionTaskStartedEvent(msBuilder, di.ScheduleID, tl, identity) - decisionCompletedEvent := test.AddDecisionTaskCompletedEvent(msBuilder, di.ScheduleID, - decisionStartedEvent.ID, nil, identity) - activityScheduledEvent, _ := test.AddActivityTaskScheduledEvent(msBuilder, decisionCompletedEvent.ID, activityID, - activityType, tl, activityInput, 100, 10, 1, 5) - test.AddActivityTaskStartedEvent(msBuilder, activityScheduledEvent.ID, identity) - - ms := execution.CreatePersistenceMutableState(msBuilder) - gwmsResponse := &persistence.GetWorkflowExecutionResponse{State: ms} - - s.mockExecutionMgr.On("GetWorkflowExecution", mock.Anything, mock.Anything).Return(gwmsResponse, nil).Once() - s.mockHistoryV2Mgr.On("AppendHistoryNodes", mock.Anything, mock.Anything).Return(&persistence.AppendHistoryNodesResponse{}, nil).Once() - s.mockExecutionMgr.On("UpdateWorkflowExecution", mock.Anything, mock.Anything).Return(&persistence.UpdateWorkflowExecutionResponse{MutableStateUpdateSessionStats: &persistence.MutableStateUpdateSessionStats{}}, errors.New("FAILED")).Once() - s.mockShardManager.On("UpdateShard", mock.Anything, mock.Anything).Return(nil).Once() - - err := s.mockHistoryEngine.RespondActivityTaskFailed(context.Background(), &types.HistoryRespondActivityTaskFailedRequest{ - DomainUUID: constants.TestDomainID, - FailedRequest: &types.RespondActivityTaskFailedRequest{ - TaskToken: taskToken, - Identity: identity, - }, - }) - s.EqualError(err, "FAILED") -} - -func (s *engineSuite) TestRespondActivityTaskFailedIfTaskCompleted() { - - we := types.WorkflowExecution{ - WorkflowID: "wId", - RunID: constants.TestRunID, - } - tl := "testTaskList" - taskToken, _ := json.Marshal(&common.TaskToken{ - WorkflowID: we.WorkflowID, - RunID: we.RunID, - ScheduleID: 5, - }) - identity := "testIdentity" - activityID := "activity1_id" - activityType := "activity_type1" - activityInput := []byte("input1") - failReason := "fail reason" - details := []byte("fail details") - - msBuilder := execution.NewMutableStateBuilderWithEventV2( - s.mockHistoryEngine.shard, - testlogger.New(s.Suite.T()), - we.GetRunID(), - constants.TestLocalDomainEntry, - ) - test.AddWorkflowExecutionStartedEvent(msBuilder, we, "wType", tl, []byte("input"), 100, 100, identity) - di := test.AddDecisionTaskScheduledEvent(msBuilder) - decisionStartedEvent := test.AddDecisionTaskStartedEvent(msBuilder, di.ScheduleID, tl, identity) - decisionCompletedEvent := test.AddDecisionTaskCompletedEvent(msBuilder, di.ScheduleID, - decisionStartedEvent.ID, nil, identity) - activityScheduledEvent, _ := test.AddActivityTaskScheduledEvent(msBuilder, decisionCompletedEvent.ID, activityID, - activityType, tl, activityInput, 100, 10, 1, 5) - activityStartedEvent := test.AddActivityTaskStartedEvent(msBuilder, activityScheduledEvent.ID, identity) - test.AddActivityTaskFailedEvent(msBuilder, activityScheduledEvent.ID, activityStartedEvent.ID, - failReason, details, identity) - test.AddDecisionTaskScheduledEvent(msBuilder) - - ms := execution.CreatePersistenceMutableState(msBuilder) - gwmsResponse := &persistence.GetWorkflowExecutionResponse{State: ms} - - s.mockExecutionMgr.On("GetWorkflowExecution", mock.Anything, mock.Anything).Return(gwmsResponse, nil).Once() - - err := s.mockHistoryEngine.RespondActivityTaskFailed(context.Background(), &types.HistoryRespondActivityTaskFailedRequest{ - DomainUUID: constants.TestDomainID, - FailedRequest: &types.RespondActivityTaskFailedRequest{ - TaskToken: taskToken, - Reason: &failReason, - Details: details, - Identity: identity, - }, - }) - s.NotNil(err) - s.IsType(&types.EntityNotExistsError{}, err) -} - -func (s *engineSuite) TestRespondActivityTaskFailedIfTaskNotStarted() { - - we := types.WorkflowExecution{ - WorkflowID: "wId", - RunID: constants.TestRunID, - } - tl := "testTaskList" - taskToken, _ := json.Marshal(&common.TaskToken{ - WorkflowID: we.WorkflowID, - RunID: we.RunID, - ScheduleID: 5, - }) - identity := "testIdentity" - activityID := "activity1_id" - activityType := "activity_type1" - activityInput := []byte("input1") - - msBuilder := execution.NewMutableStateBuilderWithEventV2( - s.mockHistoryEngine.shard, - testlogger.New(s.Suite.T()), - we.GetRunID(), - constants.TestLocalDomainEntry, - ) - test.AddWorkflowExecutionStartedEvent(msBuilder, we, "wType", tl, []byte("input"), 100, 100, identity) - di := test.AddDecisionTaskScheduledEvent(msBuilder) - decisionStartedEvent := test.AddDecisionTaskStartedEvent(msBuilder, di.ScheduleID, tl, identity) - decisionCompletedEvent := test.AddDecisionTaskCompletedEvent(msBuilder, di.ScheduleID, - decisionStartedEvent.ID, nil, identity) - test.AddActivityTaskScheduledEvent(msBuilder, decisionCompletedEvent.ID, activityID, - activityType, tl, activityInput, 100, 10, 1, 5) - - ms := execution.CreatePersistenceMutableState(msBuilder) - gwmsResponse := &persistence.GetWorkflowExecutionResponse{State: ms} - - s.mockExecutionMgr.On("GetWorkflowExecution", mock.Anything, mock.Anything).Return(gwmsResponse, nil).Once() - - err := s.mockHistoryEngine.RespondActivityTaskFailed(context.Background(), &types.HistoryRespondActivityTaskFailedRequest{ - DomainUUID: constants.TestDomainID, - FailedRequest: &types.RespondActivityTaskFailedRequest{ - TaskToken: taskToken, - Identity: identity, - }, - }) - s.NotNil(err) - s.IsType(&types.EntityNotExistsError{}, err) -} - -func (s *engineSuite) TestRespondActivityTaskFailedConflictOnUpdate() { - - we := types.WorkflowExecution{ - WorkflowID: "wId", - RunID: constants.TestRunID, - } - tl := "testTaskList" - taskToken, _ := json.Marshal(&common.TaskToken{ - WorkflowID: we.WorkflowID, - RunID: we.RunID, - ScheduleID: 5, - }) - identity := "testIdentity" - activity1ID := "activity1" - activity1Type := "activity_type1" - activity1Input := []byte("input1") - failReason := "fail reason" - details := []byte("fail details.") - activity2ID := "activity2" - activity2Type := "activity_type2" - activity2Input := []byte("input2") - activity2Result := []byte("activity2_result") - - msBuilder := execution.NewMutableStateBuilderWithEventV2( - s.mockHistoryEngine.shard, - testlogger.New(s.Suite.T()), - we.GetRunID(), - constants.TestLocalDomainEntry, - ) - test.AddWorkflowExecutionStartedEvent(msBuilder, we, "wType", tl, []byte("input"), 25, 25, identity) - di1 := test.AddDecisionTaskScheduledEvent(msBuilder) - decisionStartedEvent1 := test.AddDecisionTaskStartedEvent(msBuilder, di1.ScheduleID, tl, identity) - decisionCompletedEvent1 := test.AddDecisionTaskCompletedEvent(msBuilder, di1.ScheduleID, - decisionStartedEvent1.ID, nil, identity) - activity1ScheduledEvent, _ := test.AddActivityTaskScheduledEvent(msBuilder, decisionCompletedEvent1.ID, activity1ID, - activity1Type, tl, activity1Input, 100, 10, 1, 5) - activity2ScheduledEvent, _ := test.AddActivityTaskScheduledEvent(msBuilder, decisionCompletedEvent1.ID, activity2ID, - activity2Type, tl, activity2Input, 100, 10, 1, 5) - test.AddActivityTaskStartedEvent(msBuilder, activity1ScheduledEvent.ID, identity) - activity2StartedEvent := test.AddActivityTaskStartedEvent(msBuilder, activity2ScheduledEvent.ID, identity) - - ms1 := execution.CreatePersistenceMutableState(msBuilder) - gwmsResponse1 := &persistence.GetWorkflowExecutionResponse{State: ms1} - - test.AddActivityTaskCompletedEvent(msBuilder, activity2ScheduledEvent.ID, - activity2StartedEvent.ID, activity2Result, identity) - test.AddDecisionTaskScheduledEvent(msBuilder) - - ms2 := execution.CreatePersistenceMutableState(msBuilder) - gwmsResponse2 := &persistence.GetWorkflowExecutionResponse{State: ms2} - - s.mockExecutionMgr.On("GetWorkflowExecution", mock.Anything, mock.Anything).Return(gwmsResponse1, nil).Once() - s.mockHistoryV2Mgr.On("AppendHistoryNodes", mock.Anything, mock.Anything).Return(&persistence.AppendHistoryNodesResponse{}, nil).Once() - s.mockExecutionMgr.On("UpdateWorkflowExecution", mock.Anything, mock.Anything).Return(&persistence.UpdateWorkflowExecutionResponse{MutableStateUpdateSessionStats: &persistence.MutableStateUpdateSessionStats{}}, &persistence.ConditionFailedError{}).Once() - - s.mockExecutionMgr.On("GetWorkflowExecution", mock.Anything, mock.Anything).Return(gwmsResponse2, nil).Once() - s.mockHistoryV2Mgr.On("AppendHistoryNodes", mock.Anything, mock.Anything).Return(&persistence.AppendHistoryNodesResponse{}, nil).Once() - s.mockExecutionMgr.On("UpdateWorkflowExecution", mock.Anything, mock.Anything).Return(&persistence.UpdateWorkflowExecutionResponse{MutableStateUpdateSessionStats: &persistence.MutableStateUpdateSessionStats{}}, nil).Once() - - err := s.mockHistoryEngine.RespondActivityTaskFailed(context.Background(), &types.HistoryRespondActivityTaskFailedRequest{ - DomainUUID: constants.TestDomainID, - FailedRequest: &types.RespondActivityTaskFailedRequest{ - TaskToken: taskToken, - Reason: &failReason, - Details: details, - Identity: identity, - }, - }) - s.Nil(err, s.printHistory(msBuilder)) - executionBuilder := s.getBuilder(constants.TestDomainID, we) - s.Equal(int64(12), executionBuilder.GetExecutionInfo().NextEventID) - s.Equal(int64(3), executionBuilder.GetExecutionInfo().LastProcessedEvent) - s.Equal(persistence.WorkflowStateRunning, executionBuilder.GetExecutionInfo().State) - - s.True(executionBuilder.HasPendingDecision()) - di, ok := executionBuilder.GetDecisionInfo(int64(10)) - s.True(ok) - s.Equal(int32(25), di.DecisionTimeout) - s.Equal(int64(10), di.ScheduleID) - s.Equal(common.EmptyEventID, di.StartedID) -} - -func (s *engineSuite) TestRespondActivityTaskFailedMaxAttemptsExceeded() { - - we := types.WorkflowExecution{ - WorkflowID: "wId", - RunID: constants.TestRunID, - } - tl := "testTaskList" - taskToken, _ := json.Marshal(&common.TaskToken{ - WorkflowID: we.WorkflowID, - RunID: we.RunID, - ScheduleID: 5, - }) - identity := "testIdentity" - activityID := "activity1_id" - activityType := "activity_type1" - activityInput := []byte("input1") - - msBuilder := execution.NewMutableStateBuilderWithEventV2( - s.mockHistoryEngine.shard, - testlogger.New(s.Suite.T()), - we.GetRunID(), - constants.TestLocalDomainEntry, - ) - test.AddWorkflowExecutionStartedEvent(msBuilder, we, "wType", tl, []byte("input"), 100, 100, identity) - di := test.AddDecisionTaskScheduledEvent(msBuilder) - decisionStartedEvent := test.AddDecisionTaskStartedEvent(msBuilder, di.ScheduleID, tl, identity) - decisionCompletedEvent := test.AddDecisionTaskCompletedEvent(msBuilder, di.ScheduleID, - decisionStartedEvent.ID, nil, identity) - activityScheduledEvent, _ := test.AddActivityTaskScheduledEvent(msBuilder, decisionCompletedEvent.ID, activityID, - activityType, tl, activityInput, 100, 10, 1, 5) - test.AddActivityTaskStartedEvent(msBuilder, activityScheduledEvent.ID, identity) - - for i := 0; i < workflow.ConditionalRetryCount; i++ { - ms := execution.CreatePersistenceMutableState(msBuilder) - gwmsResponse := &persistence.GetWorkflowExecutionResponse{State: ms} - - s.mockExecutionMgr.On("GetWorkflowExecution", mock.Anything, mock.Anything).Return(gwmsResponse, nil).Once() - s.mockHistoryV2Mgr.On("AppendHistoryNodes", mock.Anything, mock.Anything).Return(&persistence.AppendHistoryNodesResponse{}, nil).Once() - s.mockExecutionMgr.On("UpdateWorkflowExecution", mock.Anything, mock.Anything).Return(&persistence.UpdateWorkflowExecutionResponse{MutableStateUpdateSessionStats: &persistence.MutableStateUpdateSessionStats{}}, &persistence.ConditionFailedError{}).Once() - } - - err := s.mockHistoryEngine.RespondActivityTaskFailed(context.Background(), &types.HistoryRespondActivityTaskFailedRequest{ - DomainUUID: constants.TestDomainID, - FailedRequest: &types.RespondActivityTaskFailedRequest{ - TaskToken: taskToken, - Identity: identity, - }, - }) - s.Equal(workflow.ErrMaxAttemptsExceeded, err) -} - -func (s *engineSuite) TestRespondActivityTaskFailedSuccess() { - - we := types.WorkflowExecution{ - WorkflowID: "wId", - RunID: constants.TestRunID, - } - tl := "testTaskList" - taskToken, _ := json.Marshal(&common.TaskToken{ - WorkflowID: we.WorkflowID, - RunID: we.RunID, - ScheduleID: 5, - }) - identity := "testIdentity" - activityID := "activity1_id" - activityType := "activity_type1" - activityInput := []byte("input1") - failReason := "failed" - failDetails := []byte("fail details.") - - msBuilder := execution.NewMutableStateBuilderWithEventV2( - s.mockHistoryEngine.shard, - testlogger.New(s.Suite.T()), - we.GetRunID(), - constants.TestLocalDomainEntry, - ) - test.AddWorkflowExecutionStartedEvent(msBuilder, we, "wType", tl, []byte("input"), 100, 100, identity) - di := test.AddDecisionTaskScheduledEvent(msBuilder) - decisionStartedEvent := test.AddDecisionTaskStartedEvent(msBuilder, di.ScheduleID, tl, identity) - decisionCompletedEvent := test.AddDecisionTaskCompletedEvent(msBuilder, di.ScheduleID, - decisionStartedEvent.ID, nil, identity) - activityScheduledEvent, _ := test.AddActivityTaskScheduledEvent(msBuilder, decisionCompletedEvent.ID, activityID, - activityType, tl, activityInput, 100, 10, 1, 5) - test.AddActivityTaskStartedEvent(msBuilder, activityScheduledEvent.ID, identity) - - ms := execution.CreatePersistenceMutableState(msBuilder) - gwmsResponse := &persistence.GetWorkflowExecutionResponse{State: ms} - - s.mockExecutionMgr.On("GetWorkflowExecution", mock.Anything, mock.Anything).Return(gwmsResponse, nil).Once() - s.mockHistoryV2Mgr.On("AppendHistoryNodes", mock.Anything, mock.Anything).Return(&persistence.AppendHistoryNodesResponse{}, nil).Once() - s.mockExecutionMgr.On("UpdateWorkflowExecution", mock.Anything, mock.Anything).Return(&persistence.UpdateWorkflowExecutionResponse{MutableStateUpdateSessionStats: &persistence.MutableStateUpdateSessionStats{}}, nil).Once() - - err := s.mockHistoryEngine.RespondActivityTaskFailed(context.Background(), &types.HistoryRespondActivityTaskFailedRequest{ - DomainUUID: constants.TestDomainID, - FailedRequest: &types.RespondActivityTaskFailedRequest{ - TaskToken: taskToken, - Reason: &failReason, - Details: failDetails, - Identity: identity, - }, - }) - s.Nil(err) - executionBuilder := s.getBuilder(constants.TestDomainID, we) - s.Equal(int64(9), executionBuilder.GetExecutionInfo().NextEventID) - s.Equal(int64(3), executionBuilder.GetExecutionInfo().LastProcessedEvent) - s.Equal(persistence.WorkflowStateRunning, executionBuilder.GetExecutionInfo().State) - - s.True(executionBuilder.HasPendingDecision()) - di, ok := executionBuilder.GetDecisionInfo(int64(8)) - s.True(ok) - s.Equal(int32(100), di.DecisionTimeout) - s.Equal(int64(8), di.ScheduleID) - s.Equal(common.EmptyEventID, di.StartedID) -} - -func (s *engineSuite) TestRespondActivityTaskFailedByIDSuccess() { - - we := types.WorkflowExecution{ - WorkflowID: "wId", - RunID: constants.TestRunID, - } - tl := "testTaskList" - - identity := "testIdentity" - activityID := "activity1_id" - activityType := "activity_type1" - activityInput := []byte("input1") - failReason := "failed" - failDetails := []byte("fail details.") - taskToken, _ := json.Marshal(&common.TaskToken{ - WorkflowID: we.WorkflowID, - ScheduleID: common.EmptyEventID, - ActivityID: activityID, - }) - - msBuilder := execution.NewMutableStateBuilderWithEventV2( - s.mockHistoryEngine.shard, - testlogger.New(s.Suite.T()), - we.GetRunID(), - constants.TestLocalDomainEntry, - ) - test.AddWorkflowExecutionStartedEvent(msBuilder, we, "wType", tl, []byte("input"), 100, 100, identity) - decisionScheduledEvent := test.AddDecisionTaskScheduledEvent(msBuilder) - decisionStartedEvent := test.AddDecisionTaskStartedEvent(msBuilder, decisionScheduledEvent.ScheduleID, tl, identity) - decisionCompletedEvent := test.AddDecisionTaskCompletedEvent(msBuilder, decisionScheduledEvent.ScheduleID, - decisionStartedEvent.ID, nil, identity) - activityScheduledEvent, _ := test.AddActivityTaskScheduledEvent(msBuilder, decisionCompletedEvent.ID, activityID, - activityType, tl, activityInput, 100, 10, 1, 5) - test.AddActivityTaskStartedEvent(msBuilder, activityScheduledEvent.ID, identity) - - ms := execution.CreatePersistenceMutableState(msBuilder) - gwmsResponse := &persistence.GetWorkflowExecutionResponse{State: ms} - gceResponse := &persistence.GetCurrentExecutionResponse{RunID: we.RunID} - - s.mockExecutionMgr.On("GetCurrentExecution", mock.Anything, mock.Anything).Return(gceResponse, nil).Once() - s.mockExecutionMgr.On("GetWorkflowExecution", mock.Anything, mock.Anything).Return(gwmsResponse, nil).Once() - s.mockHistoryV2Mgr.On("AppendHistoryNodes", mock.Anything, mock.Anything).Return(&persistence.AppendHistoryNodesResponse{}, nil).Once() - s.mockExecutionMgr.On("UpdateWorkflowExecution", mock.Anything, mock.Anything).Return(&persistence.UpdateWorkflowExecutionResponse{MutableStateUpdateSessionStats: &persistence.MutableStateUpdateSessionStats{}}, nil).Once() - - err := s.mockHistoryEngine.RespondActivityTaskFailed(context.Background(), &types.HistoryRespondActivityTaskFailedRequest{ - DomainUUID: constants.TestDomainID, - FailedRequest: &types.RespondActivityTaskFailedRequest{ - TaskToken: taskToken, - Reason: &failReason, - Details: failDetails, - Identity: identity, - }, - }) - s.Nil(err) - executionBuilder := s.getBuilder(constants.TestDomainID, we) - s.Equal(int64(9), executionBuilder.GetExecutionInfo().NextEventID) - s.Equal(int64(3), executionBuilder.GetExecutionInfo().LastProcessedEvent) - s.Equal(persistence.WorkflowStateRunning, executionBuilder.GetExecutionInfo().State) - - s.True(executionBuilder.HasPendingDecision()) - di, ok := executionBuilder.GetDecisionInfo(int64(8)) - s.True(ok) - s.Equal(int32(100), di.DecisionTimeout) - s.Equal(int64(8), di.ScheduleID) - s.Equal(common.EmptyEventID, di.StartedID) -} - -func (s *engineSuite) TestRecordActivityTaskHeartBeatSuccess_NoTimer() { - - we := types.WorkflowExecution{ - WorkflowID: "wId", - RunID: constants.TestRunID, - } - tl := "testTaskList" - taskToken, _ := json.Marshal(&common.TaskToken{ - WorkflowID: we.WorkflowID, - RunID: we.RunID, - ScheduleID: 5, - }) - identity := "testIdentity" - activityID := "activity1_id" - activityType := "activity_type1" - activityInput := []byte("input1") - - msBuilder := execution.NewMutableStateBuilderWithEventV2( - s.mockHistoryEngine.shard, - testlogger.New(s.Suite.T()), - we.GetRunID(), - constants.TestLocalDomainEntry, - ) - test.AddWorkflowExecutionStartedEvent(msBuilder, we, "wType", tl, []byte("input"), 100, 100, identity) - di := test.AddDecisionTaskScheduledEvent(msBuilder) - decisionStartedEvent := test.AddDecisionTaskStartedEvent(msBuilder, di.ScheduleID, tl, identity) - decisionCompletedEvent := test.AddDecisionTaskCompletedEvent(msBuilder, di.ScheduleID, - decisionStartedEvent.ID, nil, identity) - activityScheduledEvent, _ := test.AddActivityTaskScheduledEvent(msBuilder, decisionCompletedEvent.ID, activityID, - activityType, tl, activityInput, 100, 10, 1, 0) - test.AddActivityTaskStartedEvent(msBuilder, activityScheduledEvent.ID, identity) - - // No HeartBeat timer running. - ms := execution.CreatePersistenceMutableState(msBuilder) - gwmsResponse := &persistence.GetWorkflowExecutionResponse{State: ms} - s.mockExecutionMgr.On("GetWorkflowExecution", mock.Anything, mock.Anything).Return(gwmsResponse, nil).Once() - s.mockExecutionMgr.On("UpdateWorkflowExecution", mock.Anything, mock.Anything).Return(&persistence.UpdateWorkflowExecutionResponse{MutableStateUpdateSessionStats: &persistence.MutableStateUpdateSessionStats{}}, nil).Once() - - detais := []byte("details") - - _, err := s.mockHistoryEngine.RecordActivityTaskHeartbeat(context.Background(), &types.HistoryRecordActivityTaskHeartbeatRequest{ - DomainUUID: constants.TestDomainID, - HeartbeatRequest: &types.RecordActivityTaskHeartbeatRequest{ - TaskToken: taskToken, - Identity: identity, - Details: detais, - }, - }) - s.Nil(err) -} - -func (s *engineSuite) TestRecordActivityTaskHeartBeatSuccess_TimerRunning() { - - we := types.WorkflowExecution{ - WorkflowID: "wId", - RunID: constants.TestRunID, - } - tl := "testTaskList" - taskToken, _ := json.Marshal(&common.TaskToken{ - WorkflowID: we.WorkflowID, - RunID: we.RunID, - ScheduleID: 5, - }) - identity := "testIdentity" - activityID := "activity1_id" - activityType := "activity_type1" - activityInput := []byte("input1") - - msBuilder := execution.NewMutableStateBuilderWithEventV2( - s.mockHistoryEngine.shard, - testlogger.New(s.Suite.T()), - we.GetRunID(), - constants.TestLocalDomainEntry, - ) - test.AddWorkflowExecutionStartedEvent(msBuilder, we, "wType", tl, []byte("input"), 100, 100, identity) - di := test.AddDecisionTaskScheduledEvent(msBuilder) - decisionStartedEvent := test.AddDecisionTaskStartedEvent(msBuilder, di.ScheduleID, tl, identity) - decisionCompletedEvent := test.AddDecisionTaskCompletedEvent(msBuilder, di.ScheduleID, - decisionStartedEvent.ID, nil, identity) - activityScheduledEvent, _ := test.AddActivityTaskScheduledEvent(msBuilder, decisionCompletedEvent.ID, activityID, - activityType, tl, activityInput, 100, 10, 1, 1) - test.AddActivityTaskStartedEvent(msBuilder, activityScheduledEvent.ID, identity) - - ms := execution.CreatePersistenceMutableState(msBuilder) - gwmsResponse := &persistence.GetWorkflowExecutionResponse{State: ms} - - // HeartBeat timer running. - s.mockExecutionMgr.On("GetWorkflowExecution", mock.Anything, mock.Anything).Return(gwmsResponse, nil).Once() - s.mockExecutionMgr.On("UpdateWorkflowExecution", mock.Anything, mock.Anything).Return(&persistence.UpdateWorkflowExecutionResponse{MutableStateUpdateSessionStats: &persistence.MutableStateUpdateSessionStats{}}, nil).Once() - - detais := []byte("details") - - _, err := s.mockHistoryEngine.RecordActivityTaskHeartbeat(context.Background(), &types.HistoryRecordActivityTaskHeartbeatRequest{ - DomainUUID: constants.TestDomainID, - HeartbeatRequest: &types.RecordActivityTaskHeartbeatRequest{ - TaskToken: taskToken, - Identity: identity, - Details: detais, - }, - }) - s.Nil(err) - executionBuilder := s.getBuilder(constants.TestDomainID, we) - s.Equal(int64(7), executionBuilder.GetExecutionInfo().NextEventID) - s.Equal(int64(3), executionBuilder.GetExecutionInfo().LastProcessedEvent) - s.Equal(persistence.WorkflowStateRunning, executionBuilder.GetExecutionInfo().State) - s.False(executionBuilder.HasPendingDecision()) -} - -func (s *engineSuite) TestRecordActivityTaskHeartBeatByIDSuccess() { - - we := types.WorkflowExecution{ - WorkflowID: "wId", - RunID: constants.TestRunID, - } - tl := "testTaskList" - identity := "testIdentity" - activityID := "activity1_id" - activityType := "activity_type1" - activityInput := []byte("input1") - taskToken, _ := json.Marshal(&common.TaskToken{ - WorkflowID: we.WorkflowID, - RunID: we.RunID, - ScheduleID: common.EmptyEventID, - ActivityID: activityID, - }) - - msBuilder := execution.NewMutableStateBuilderWithEventV2( - s.mockHistoryEngine.shard, - testlogger.New(s.Suite.T()), - we.GetRunID(), - constants.TestLocalDomainEntry, - ) - test.AddWorkflowExecutionStartedEvent(msBuilder, we, "wType", tl, []byte("input"), 100, 100, identity) - di := test.AddDecisionTaskScheduledEvent(msBuilder) - decisionStartedEvent := test.AddDecisionTaskStartedEvent(msBuilder, di.ScheduleID, tl, identity) - decisionCompletedEvent := test.AddDecisionTaskCompletedEvent(msBuilder, di.ScheduleID, - decisionStartedEvent.ID, nil, identity) - activityScheduledEvent, _ := test.AddActivityTaskScheduledEvent(msBuilder, decisionCompletedEvent.ID, activityID, - activityType, tl, activityInput, 100, 10, 1, 0) - test.AddActivityTaskStartedEvent(msBuilder, activityScheduledEvent.ID, identity) - - // No HeartBeat timer running. - ms := execution.CreatePersistenceMutableState(msBuilder) - gwmsResponse := &persistence.GetWorkflowExecutionResponse{State: ms} - s.mockExecutionMgr.On("GetWorkflowExecution", mock.Anything, mock.Anything).Return(gwmsResponse, nil).Once() - s.mockExecutionMgr.On("UpdateWorkflowExecution", mock.Anything, mock.Anything).Return(&persistence.UpdateWorkflowExecutionResponse{MutableStateUpdateSessionStats: &persistence.MutableStateUpdateSessionStats{}}, nil).Once() - - detais := []byte("details") - - _, err := s.mockHistoryEngine.RecordActivityTaskHeartbeat(context.Background(), &types.HistoryRecordActivityTaskHeartbeatRequest{ - DomainUUID: constants.TestDomainID, - HeartbeatRequest: &types.RecordActivityTaskHeartbeatRequest{ - TaskToken: taskToken, - Identity: identity, - Details: detais, - }, - }) - s.Nil(err) -} - -func (s *engineSuite) TestRespondActivityTaskCanceled_Scheduled() { - - we := types.WorkflowExecution{ - WorkflowID: "wId", - RunID: constants.TestRunID, - } - tl := "testTaskList" - taskToken, _ := json.Marshal(&common.TaskToken{ - WorkflowID: we.WorkflowID, - RunID: we.RunID, - ScheduleID: 5, - }) - identity := "testIdentity" - activityID := "activity1_id" - activityType := "activity_type1" - activityInput := []byte("input1") - - msBuilder := execution.NewMutableStateBuilderWithEventV2( - s.mockHistoryEngine.shard, - testlogger.New(s.Suite.T()), - we.GetRunID(), - constants.TestLocalDomainEntry, - ) - test.AddWorkflowExecutionStartedEvent(msBuilder, we, "wType", tl, []byte("input"), 100, 100, identity) - di := test.AddDecisionTaskScheduledEvent(msBuilder) - decisionStartedEvent := test.AddDecisionTaskStartedEvent(msBuilder, di.ScheduleID, tl, identity) - decisionCompletedEvent := test.AddDecisionTaskCompletedEvent(msBuilder, di.ScheduleID, - decisionStartedEvent.ID, nil, identity) - test.AddActivityTaskScheduledEvent(msBuilder, decisionCompletedEvent.ID, activityID, - activityType, tl, activityInput, 100, 10, 1, 1) - - ms := execution.CreatePersistenceMutableState(msBuilder) - gwmsResponse := &persistence.GetWorkflowExecutionResponse{State: ms} - - s.mockExecutionMgr.On("GetWorkflowExecution", mock.Anything, mock.Anything).Return(gwmsResponse, nil).Once() - - err := s.mockHistoryEngine.RespondActivityTaskCanceled(context.Background(), &types.HistoryRespondActivityTaskCanceledRequest{ - DomainUUID: constants.TestDomainID, - CancelRequest: &types.RespondActivityTaskCanceledRequest{ - TaskToken: taskToken, - Identity: identity, - Details: []byte("details"), - }, - }) - s.NotNil(err) - s.IsType(&types.EntityNotExistsError{}, err) -} - -func (s *engineSuite) TestRespondActivityTaskCanceled_Started() { - - we := types.WorkflowExecution{ - WorkflowID: "wId", - RunID: constants.TestRunID, - } - tl := "testTaskList" - taskToken, _ := json.Marshal(&common.TaskToken{ - WorkflowID: we.WorkflowID, - RunID: we.RunID, - ScheduleID: 5, - }) - identity := "testIdentity" - activityID := "activity1_id" - activityType := "activity_type1" - activityInput := []byte("input1") - - msBuilder := execution.NewMutableStateBuilderWithEventV2( - s.mockHistoryEngine.shard, - testlogger.New(s.Suite.T()), - we.GetRunID(), - constants.TestLocalDomainEntry, - ) - test.AddWorkflowExecutionStartedEvent(msBuilder, we, "wType", tl, []byte("input"), 100, 100, identity) - di := test.AddDecisionTaskScheduledEvent(msBuilder) - decisionStartedEvent := test.AddDecisionTaskStartedEvent(msBuilder, di.ScheduleID, tl, identity) - decisionCompletedEvent := test.AddDecisionTaskCompletedEvent(msBuilder, di.ScheduleID, - decisionStartedEvent.ID, nil, identity) - activityScheduledEvent, _ := test.AddActivityTaskScheduledEvent(msBuilder, decisionCompletedEvent.ID, activityID, - activityType, tl, activityInput, 100, 10, 1, 1) - test.AddActivityTaskStartedEvent(msBuilder, activityScheduledEvent.ID, identity) - _, _, err := msBuilder.AddActivityTaskCancelRequestedEvent(decisionCompletedEvent.ID, activityID, identity) - s.Nil(err) - - ms := execution.CreatePersistenceMutableState(msBuilder) - gwmsResponse := &persistence.GetWorkflowExecutionResponse{State: ms} - - s.mockExecutionMgr.On("GetWorkflowExecution", mock.Anything, mock.Anything).Return(gwmsResponse, nil).Once() - s.mockHistoryV2Mgr.On("AppendHistoryNodes", mock.Anything, mock.Anything).Return(&persistence.AppendHistoryNodesResponse{}, nil).Once() - s.mockExecutionMgr.On("UpdateWorkflowExecution", mock.Anything, mock.Anything).Return(&persistence.UpdateWorkflowExecutionResponse{MutableStateUpdateSessionStats: &persistence.MutableStateUpdateSessionStats{}}, nil).Once() - - err = s.mockHistoryEngine.RespondActivityTaskCanceled(context.Background(), &types.HistoryRespondActivityTaskCanceledRequest{ - DomainUUID: constants.TestDomainID, - CancelRequest: &types.RespondActivityTaskCanceledRequest{ - TaskToken: taskToken, - Identity: identity, - Details: []byte("details"), - }, - }) - s.Nil(err) - executionBuilder := s.getBuilder(constants.TestDomainID, we) - s.Equal(int64(10), executionBuilder.GetExecutionInfo().NextEventID) - s.Equal(int64(3), executionBuilder.GetExecutionInfo().LastProcessedEvent) - s.Equal(persistence.WorkflowStateRunning, executionBuilder.GetExecutionInfo().State) - - s.True(executionBuilder.HasPendingDecision()) - di, ok := executionBuilder.GetDecisionInfo(int64(9)) - s.True(ok) - s.Equal(int32(100), di.DecisionTimeout) - s.Equal(int64(9), di.ScheduleID) - s.Equal(common.EmptyEventID, di.StartedID) -} - -func (s *engineSuite) TestRespondActivityTaskCanceledByID_Started() { - - we := types.WorkflowExecution{ - WorkflowID: "wId", - RunID: constants.TestRunID, - } - tl := "testTaskList" - identity := "testIdentity" - activityID := "activity1_id" - activityType := "activity_type1" - activityInput := []byte("input1") - taskToken, _ := json.Marshal(&common.TaskToken{ - WorkflowID: we.WorkflowID, - ScheduleID: common.EmptyEventID, - ActivityID: activityID, - }) - - msBuilder := execution.NewMutableStateBuilderWithEventV2( - s.mockHistoryEngine.shard, - testlogger.New(s.Suite.T()), - we.GetRunID(), - constants.TestLocalDomainEntry, - ) - test.AddWorkflowExecutionStartedEvent(msBuilder, we, "wType", tl, []byte("input"), 100, 100, identity) - decisionScheduledEvent := test.AddDecisionTaskScheduledEvent(msBuilder) - decisionStartedEvent := test.AddDecisionTaskStartedEvent(msBuilder, decisionScheduledEvent.ScheduleID, tl, identity) - decisionCompletedEvent := test.AddDecisionTaskCompletedEvent(msBuilder, decisionScheduledEvent.ScheduleID, - decisionStartedEvent.ID, nil, identity) - activityScheduledEvent, _ := test.AddActivityTaskScheduledEvent(msBuilder, decisionCompletedEvent.ID, activityID, - activityType, tl, activityInput, 100, 10, 1, 1) - test.AddActivityTaskStartedEvent(msBuilder, activityScheduledEvent.ID, identity) - _, _, err := msBuilder.AddActivityTaskCancelRequestedEvent(decisionCompletedEvent.ID, activityID, identity) - s.Nil(err) - - ms := execution.CreatePersistenceMutableState(msBuilder) - gwmsResponse := &persistence.GetWorkflowExecutionResponse{State: ms} - gceResponse := &persistence.GetCurrentExecutionResponse{RunID: we.RunID} - - s.mockExecutionMgr.On("GetCurrentExecution", mock.Anything, mock.Anything).Return(gceResponse, nil).Once() - s.mockExecutionMgr.On("GetWorkflowExecution", mock.Anything, mock.Anything).Return(gwmsResponse, nil).Once() - s.mockHistoryV2Mgr.On("AppendHistoryNodes", mock.Anything, mock.Anything).Return(&persistence.AppendHistoryNodesResponse{}, nil).Once() - s.mockExecutionMgr.On("UpdateWorkflowExecution", mock.Anything, mock.Anything).Return(&persistence.UpdateWorkflowExecutionResponse{MutableStateUpdateSessionStats: &persistence.MutableStateUpdateSessionStats{}}, nil).Once() - - err = s.mockHistoryEngine.RespondActivityTaskCanceled(context.Background(), &types.HistoryRespondActivityTaskCanceledRequest{ - DomainUUID: constants.TestDomainID, - CancelRequest: &types.RespondActivityTaskCanceledRequest{ - TaskToken: taskToken, - Identity: identity, - Details: []byte("details"), - }, - }) - s.Nil(err) - executionBuilder := s.getBuilder(constants.TestDomainID, we) - s.Equal(int64(10), executionBuilder.GetExecutionInfo().NextEventID) - s.Equal(int64(3), executionBuilder.GetExecutionInfo().LastProcessedEvent) - s.Equal(persistence.WorkflowStateRunning, executionBuilder.GetExecutionInfo().State) - - s.True(executionBuilder.HasPendingDecision()) - di, ok := executionBuilder.GetDecisionInfo(int64(9)) - s.True(ok) - s.Equal(int32(100), di.DecisionTimeout) - s.Equal(int64(9), di.ScheduleID) - s.Equal(common.EmptyEventID, di.StartedID) -} - -func (s *engineSuite) TestRespondActivityTaskCanceledIfNoRunID() { - - taskToken, _ := json.Marshal(&common.TaskToken{ - WorkflowID: "wId", - ScheduleID: 2, - }) - identity := "testIdentity" - - s.mockExecutionMgr.On("GetCurrentExecution", mock.Anything, mock.Anything).Return(nil, &types.EntityNotExistsError{}).Once() - - err := s.mockHistoryEngine.RespondActivityTaskCanceled(context.Background(), &types.HistoryRespondActivityTaskCanceledRequest{ - DomainUUID: constants.TestDomainID, - CancelRequest: &types.RespondActivityTaskCanceledRequest{ - TaskToken: taskToken, - Identity: identity, - }, - }) - s.NotNil(err) - s.IsType(&types.EntityNotExistsError{}, err) -} - -func (s *engineSuite) TestRespondActivityTaskCanceledIfNoAIdProvided() { - - taskToken, _ := json.Marshal(&common.TaskToken{ - WorkflowID: "wId", - ScheduleID: common.EmptyEventID, - }) - identity := "testIdentity" - - msBuilder := execution.NewMutableStateBuilderWithEventV2( - s.mockHistoryEngine.shard, - testlogger.New(s.Suite.T()), - constants.TestRunID, - constants.TestLocalDomainEntry, - ) - ms := execution.CreatePersistenceMutableState(msBuilder) - gwmsResponse := &persistence.GetWorkflowExecutionResponse{State: ms} - gceResponse := &persistence.GetCurrentExecutionResponse{RunID: constants.TestRunID} - - s.mockExecutionMgr.On("GetCurrentExecution", mock.Anything, mock.Anything).Return(gceResponse, nil).Once() - s.mockExecutionMgr.On("GetWorkflowExecution", mock.Anything, mock.Anything).Return(gwmsResponse, nil).Once() - - err := s.mockHistoryEngine.RespondActivityTaskCanceled(context.Background(), &types.HistoryRespondActivityTaskCanceledRequest{ - DomainUUID: constants.TestDomainID, - CancelRequest: &types.RespondActivityTaskCanceledRequest{ - TaskToken: taskToken, - Identity: identity, - }, - }) - s.EqualError(err, "Neither ActivityID nor ScheduleID is provided") -} - -func (s *engineSuite) TestRespondActivityTaskCanceledIfNotFound() { - - taskToken, _ := json.Marshal(&common.TaskToken{ - WorkflowID: "wId", - ScheduleID: common.EmptyEventID, - ActivityID: "aid", - }) - identity := "testIdentity" - - msBuilder := execution.NewMutableStateBuilderWithEventV2( - s.mockHistoryEngine.shard, - testlogger.New(s.Suite.T()), - constants.TestRunID, - constants.TestLocalDomainEntry, - ) - ms := execution.CreatePersistenceMutableState(msBuilder) - gwmsResponse := &persistence.GetWorkflowExecutionResponse{State: ms} - gceResponse := &persistence.GetCurrentExecutionResponse{RunID: constants.TestRunID} - - s.mockExecutionMgr.On("GetCurrentExecution", mock.Anything, mock.Anything).Return(gceResponse, nil).Once() - s.mockExecutionMgr.On("GetWorkflowExecution", mock.Anything, mock.Anything).Return(gwmsResponse, nil).Once() - - err := s.mockHistoryEngine.RespondActivityTaskCanceled(context.Background(), &types.HistoryRespondActivityTaskCanceledRequest{ - DomainUUID: constants.TestDomainID, - CancelRequest: &types.RespondActivityTaskCanceledRequest{ - TaskToken: taskToken, - Identity: identity, - }, - }) - s.Error(err) -} - -func (s *engineSuite) TestRequestCancel_RespondDecisionTaskCompleted_NotScheduled() { - - we := types.WorkflowExecution{ - WorkflowID: "wId", - RunID: constants.TestRunID, - } - tl := "testTaskList" - taskToken, _ := json.Marshal(&common.TaskToken{ - WorkflowID: we.WorkflowID, - RunID: we.RunID, - ScheduleID: 2, - }) - identity := "testIdentity" - activityID := "activity1_id" - - msBuilder := execution.NewMutableStateBuilderWithEventV2( - s.mockHistoryEngine.shard, - testlogger.New(s.Suite.T()), - we.GetRunID(), - constants.TestLocalDomainEntry, - ) - test.AddWorkflowExecutionStartedEvent(msBuilder, we, "wType", tl, []byte("input"), 100, 100, identity) - di := test.AddDecisionTaskScheduledEvent(msBuilder) - test.AddDecisionTaskStartedEvent(msBuilder, di.ScheduleID, tl, identity) - - decisions := []*types.Decision{{ - DecisionType: types.DecisionTypeRequestCancelActivityTask.Ptr(), - RequestCancelActivityTaskDecisionAttributes: &types.RequestCancelActivityTaskDecisionAttributes{ - ActivityID: activityID, - }, - }} - - ms := execution.CreatePersistenceMutableState(msBuilder) - gwmsResponse := &persistence.GetWorkflowExecutionResponse{State: ms} - - s.mockExecutionMgr.On("GetWorkflowExecution", mock.Anything, mock.Anything).Return(gwmsResponse, nil).Once() - s.mockHistoryV2Mgr.On("AppendHistoryNodes", mock.Anything, mock.Anything).Return(&persistence.AppendHistoryNodesResponse{}, nil).Once() - s.mockExecutionMgr.On("UpdateWorkflowExecution", mock.Anything, mock.Anything).Return(&persistence.UpdateWorkflowExecutionResponse{MutableStateUpdateSessionStats: &persistence.MutableStateUpdateSessionStats{}}, nil).Once() - - _, err := s.mockHistoryEngine.RespondDecisionTaskCompleted(context.Background(), &types.HistoryRespondDecisionTaskCompletedRequest{ - DomainUUID: constants.TestDomainID, - CompleteRequest: &types.RespondDecisionTaskCompletedRequest{ - TaskToken: taskToken, - Decisions: decisions, - ExecutionContext: []byte("context"), - Identity: identity, - }, - }) - s.Nil(err) - executionBuilder := s.getBuilder(constants.TestDomainID, we) - s.Equal(int64(7), executionBuilder.GetExecutionInfo().NextEventID) - s.Equal(int64(3), executionBuilder.GetExecutionInfo().LastProcessedEvent) - s.Equal(persistence.WorkflowStateRunning, executionBuilder.GetExecutionInfo().State) - s.False(executionBuilder.HasPendingDecision()) -} - -func (s *engineSuite) TestRequestCancel_RespondDecisionTaskCompleted_Scheduled() { - - we := types.WorkflowExecution{ - WorkflowID: "wId", - RunID: constants.TestRunID, - } - tl := "testTaskList" - taskToken, _ := json.Marshal(&common.TaskToken{ - WorkflowID: we.WorkflowID, - RunID: we.RunID, - ScheduleID: 6, - }) - identity := "testIdentity" - activityID := "activity1_id" - activityType := "activity_type1" - activityInput := []byte("input1") - - msBuilder := execution.NewMutableStateBuilderWithEventV2( - s.mockHistoryEngine.shard, - testlogger.New(s.Suite.T()), - we.GetRunID(), - constants.TestLocalDomainEntry, - ) - test.AddWorkflowExecutionStartedEvent(msBuilder, we, "wType", tl, []byte("input"), 100, 100, identity) - di := test.AddDecisionTaskScheduledEvent(msBuilder) - decisionStartedEvent := test.AddDecisionTaskStartedEvent(msBuilder, di.ScheduleID, tl, identity) - decisionCompletedEvent := test.AddDecisionTaskCompletedEvent(msBuilder, di.ScheduleID, - decisionStartedEvent.ID, nil, identity) - test.AddActivityTaskScheduledEvent(msBuilder, decisionCompletedEvent.ID, activityID, - activityType, tl, activityInput, 100, 10, 1, 1) - di2 := test.AddDecisionTaskScheduledEvent(msBuilder) - test.AddDecisionTaskStartedEvent(msBuilder, di2.ScheduleID, tl, identity) - - ms := execution.CreatePersistenceMutableState(msBuilder) - gwmsResponse := &persistence.GetWorkflowExecutionResponse{State: ms} - - decisions := []*types.Decision{{ - DecisionType: types.DecisionTypeRequestCancelActivityTask.Ptr(), - RequestCancelActivityTaskDecisionAttributes: &types.RequestCancelActivityTaskDecisionAttributes{ - ActivityID: activityID, - }, - }} - - s.mockExecutionMgr.On("GetWorkflowExecution", mock.Anything, mock.Anything).Return(gwmsResponse, nil).Once() - s.mockHistoryV2Mgr.On("AppendHistoryNodes", mock.Anything, mock.Anything).Return(&persistence.AppendHistoryNodesResponse{}, nil).Once() - s.mockExecutionMgr.On("UpdateWorkflowExecution", mock.Anything, mock.Anything).Return(&persistence.UpdateWorkflowExecutionResponse{MutableStateUpdateSessionStats: &persistence.MutableStateUpdateSessionStats{}}, nil).Once() - - _, err := s.mockHistoryEngine.RespondDecisionTaskCompleted(context.Background(), &types.HistoryRespondDecisionTaskCompletedRequest{ - DomainUUID: constants.TestDomainID, - CompleteRequest: &types.RespondDecisionTaskCompletedRequest{ - TaskToken: taskToken, - Decisions: decisions, - ExecutionContext: []byte("context"), - Identity: identity, - }, - }) - s.Nil(err) - - executionBuilder := s.getBuilder(constants.TestDomainID, we) - s.Equal(int64(12), executionBuilder.GetExecutionInfo().NextEventID) - s.Equal(int64(7), executionBuilder.GetExecutionInfo().LastProcessedEvent) - s.Equal(persistence.WorkflowStateRunning, executionBuilder.GetExecutionInfo().State) - s.True(executionBuilder.HasPendingDecision()) - di2, ok := executionBuilder.GetDecisionInfo(executionBuilder.GetExecutionInfo().NextEventID - 1) - s.True(ok) - s.Equal(executionBuilder.GetExecutionInfo().NextEventID-1, di2.ScheduleID) - s.Equal(int64(0), di2.Attempt) -} - -func (s *engineSuite) TestRequestCancel_RespondDecisionTaskCompleted_Started() { - - we := types.WorkflowExecution{ - WorkflowID: "wId", - RunID: constants.TestRunID, - } - tl := "testTaskList" - taskToken, _ := json.Marshal(&common.TaskToken{ - WorkflowID: we.WorkflowID, - RunID: we.RunID, - ScheduleID: 7, - }) - identity := "testIdentity" - activityID := "activity1_id" - activityType := "activity_type1" - activityInput := []byte("input1") - - msBuilder := execution.NewMutableStateBuilderWithEventV2( - s.mockHistoryEngine.shard, - testlogger.New(s.Suite.T()), - we.GetRunID(), - constants.TestLocalDomainEntry, - ) - test.AddWorkflowExecutionStartedEvent(msBuilder, we, "wType", tl, []byte("input"), 100, 100, identity) - di := test.AddDecisionTaskScheduledEvent(msBuilder) - decisionStartedEvent := test.AddDecisionTaskStartedEvent(msBuilder, di.ScheduleID, tl, identity) - decisionCompletedEvent := test.AddDecisionTaskCompletedEvent(msBuilder, di.ScheduleID, - decisionStartedEvent.ID, nil, identity) - activityScheduledEvent, _ := test.AddActivityTaskScheduledEvent(msBuilder, decisionCompletedEvent.ID, activityID, - activityType, tl, activityInput, 100, 10, 1, 0) - test.AddActivityTaskStartedEvent(msBuilder, activityScheduledEvent.ID, identity) - di2 := test.AddDecisionTaskScheduledEvent(msBuilder) - test.AddDecisionTaskStartedEvent(msBuilder, di2.ScheduleID, tl, identity) - - ms := execution.CreatePersistenceMutableState(msBuilder) - gwmsResponse := &persistence.GetWorkflowExecutionResponse{State: ms} - - decisions := []*types.Decision{{ - DecisionType: types.DecisionTypeRequestCancelActivityTask.Ptr(), - RequestCancelActivityTaskDecisionAttributes: &types.RequestCancelActivityTaskDecisionAttributes{ - ActivityID: activityID, - }, - }} - - s.mockExecutionMgr.On("GetWorkflowExecution", mock.Anything, mock.Anything).Return(gwmsResponse, nil).Once() - s.mockHistoryV2Mgr.On("AppendHistoryNodes", mock.Anything, mock.Anything).Return(&persistence.AppendHistoryNodesResponse{}, nil).Once() - s.mockExecutionMgr.On("UpdateWorkflowExecution", mock.Anything, mock.Anything).Return(&persistence.UpdateWorkflowExecutionResponse{MutableStateUpdateSessionStats: &persistence.MutableStateUpdateSessionStats{}}, nil).Once() - - _, err := s.mockHistoryEngine.RespondDecisionTaskCompleted(context.Background(), &types.HistoryRespondDecisionTaskCompletedRequest{ - DomainUUID: constants.TestDomainID, - CompleteRequest: &types.RespondDecisionTaskCompletedRequest{ - TaskToken: taskToken, - Decisions: decisions, - ExecutionContext: []byte("context"), - Identity: identity, - }, - }) - s.Nil(err) - - executionBuilder := s.getBuilder(constants.TestDomainID, we) - s.Equal(int64(11), executionBuilder.GetExecutionInfo().NextEventID) - s.Equal(int64(8), executionBuilder.GetExecutionInfo().LastProcessedEvent) - s.Equal(persistence.WorkflowStateRunning, executionBuilder.GetExecutionInfo().State) - s.False(executionBuilder.HasPendingDecision()) -} - -func (s *engineSuite) TestRequestCancel_RespondDecisionTaskCompleted_Completed() { - - we := types.WorkflowExecution{ - WorkflowID: "wId", - RunID: constants.TestRunID, - } - tl := "testTaskList" - taskToken, _ := json.Marshal(&common.TaskToken{ - WorkflowID: we.WorkflowID, - RunID: we.RunID, - ScheduleID: 6, - }) - identity := "testIdentity" - activityID := "activity1_id" - activityType := "activity_type1" - activityInput := []byte("input1") - workflowResult := []byte("workflow result") - - msBuilder := execution.NewMutableStateBuilderWithEventV2( - s.mockHistoryEngine.shard, - testlogger.New(s.Suite.T()), - we.GetRunID(), - constants.TestLocalDomainEntry, - ) - test.AddWorkflowExecutionStartedEvent(msBuilder, we, "wType", tl, []byte("input"), 100, 100, identity) - di := test.AddDecisionTaskScheduledEvent(msBuilder) - decisionStartedEvent := test.AddDecisionTaskStartedEvent(msBuilder, di.ScheduleID, tl, identity) - decisionCompletedEvent := test.AddDecisionTaskCompletedEvent(msBuilder, di.ScheduleID, - decisionStartedEvent.ID, nil, identity) - test.AddActivityTaskScheduledEvent(msBuilder, decisionCompletedEvent.ID, activityID, - activityType, tl, activityInput, 100, 10, 1, 0) - di2 := test.AddDecisionTaskScheduledEvent(msBuilder) - test.AddDecisionTaskStartedEvent(msBuilder, di2.ScheduleID, tl, identity) - - decisions := []*types.Decision{ - { - DecisionType: types.DecisionTypeRequestCancelActivityTask.Ptr(), - RequestCancelActivityTaskDecisionAttributes: &types.RequestCancelActivityTaskDecisionAttributes{ - ActivityID: activityID, - }, - }, - { - DecisionType: types.DecisionTypeCompleteWorkflowExecution.Ptr(), - CompleteWorkflowExecutionDecisionAttributes: &types.CompleteWorkflowExecutionDecisionAttributes{ - Result: workflowResult, - }, - }, - } - - ms := execution.CreatePersistenceMutableState(msBuilder) - gwmsResponse := &persistence.GetWorkflowExecutionResponse{State: ms} - s.mockExecutionMgr.On("GetWorkflowExecution", mock.Anything, mock.Anything).Return(gwmsResponse, nil).Once() - s.mockHistoryV2Mgr.On("AppendHistoryNodes", mock.Anything, mock.Anything).Return(&persistence.AppendHistoryNodesResponse{}, nil).Once() - s.mockExecutionMgr.On("UpdateWorkflowExecution", mock.Anything, mock.Anything).Return(&persistence.UpdateWorkflowExecutionResponse{MutableStateUpdateSessionStats: &persistence.MutableStateUpdateSessionStats{}}, nil).Once() - - _, err := s.mockHistoryEngine.RespondDecisionTaskCompleted(context.Background(), &types.HistoryRespondDecisionTaskCompletedRequest{ - DomainUUID: constants.TestDomainID, - CompleteRequest: &types.RespondDecisionTaskCompletedRequest{ - TaskToken: taskToken, - Decisions: decisions, - ExecutionContext: []byte("context"), - Identity: identity, - }, - }) - s.Nil(err) - - executionBuilder := s.getBuilder(constants.TestDomainID, we) - s.Equal(int64(11), executionBuilder.GetExecutionInfo().NextEventID) - s.Equal(int64(7), executionBuilder.GetExecutionInfo().LastProcessedEvent) - s.Equal(persistence.WorkflowStateCompleted, executionBuilder.GetExecutionInfo().State) - s.False(executionBuilder.HasPendingDecision()) -} - -func (s *engineSuite) TestRequestCancel_RespondDecisionTaskCompleted_NoHeartBeat() { - - we := types.WorkflowExecution{ - WorkflowID: "wId", - RunID: constants.TestRunID, - } - tl := "testTaskList" - taskToken, _ := json.Marshal(&common.TaskToken{ - WorkflowID: we.WorkflowID, - RunID: we.RunID, - ScheduleID: 7, - }) - identity := "testIdentity" - activityID := "activity1_id" - activityType := "activity_type1" - activityInput := []byte("input1") - - msBuilder := execution.NewMutableStateBuilderWithEventV2( - s.mockHistoryEngine.shard, - testlogger.New(s.Suite.T()), - we.GetRunID(), - constants.TestLocalDomainEntry, - ) - test.AddWorkflowExecutionStartedEvent(msBuilder, we, "wType", tl, []byte("input"), 100, 100, identity) - di := test.AddDecisionTaskScheduledEvent(msBuilder) - decisionStartedEvent := test.AddDecisionTaskStartedEvent(msBuilder, di.ScheduleID, tl, identity) - decisionCompletedEvent := test.AddDecisionTaskCompletedEvent(msBuilder, di.ScheduleID, - decisionStartedEvent.ID, nil, identity) - activityScheduledEvent, _ := test.AddActivityTaskScheduledEvent(msBuilder, decisionCompletedEvent.ID, activityID, - activityType, tl, activityInput, 100, 10, 1, 0) - test.AddActivityTaskStartedEvent(msBuilder, activityScheduledEvent.ID, identity) - di2 := test.AddDecisionTaskScheduledEvent(msBuilder) - test.AddDecisionTaskStartedEvent(msBuilder, di2.ScheduleID, tl, identity) - - ms := execution.CreatePersistenceMutableState(msBuilder) - gwmsResponse := &persistence.GetWorkflowExecutionResponse{State: ms} - - decisions := []*types.Decision{{ - DecisionType: types.DecisionTypeRequestCancelActivityTask.Ptr(), - RequestCancelActivityTaskDecisionAttributes: &types.RequestCancelActivityTaskDecisionAttributes{ - ActivityID: activityID, - }, - }} - - s.mockExecutionMgr.On("GetWorkflowExecution", mock.Anything, mock.Anything).Return(gwmsResponse, nil).Once() - s.mockHistoryV2Mgr.On("AppendHistoryNodes", mock.Anything, mock.Anything).Return(&persistence.AppendHistoryNodesResponse{}, nil).Once() - s.mockExecutionMgr.On("UpdateWorkflowExecution", mock.Anything, mock.Anything).Return(&persistence.UpdateWorkflowExecutionResponse{MutableStateUpdateSessionStats: &persistence.MutableStateUpdateSessionStats{}}, nil).Once() - - _, err := s.mockHistoryEngine.RespondDecisionTaskCompleted(context.Background(), &types.HistoryRespondDecisionTaskCompletedRequest{ - DomainUUID: constants.TestDomainID, - CompleteRequest: &types.RespondDecisionTaskCompletedRequest{ - TaskToken: taskToken, - Decisions: decisions, - ExecutionContext: []byte("context"), - Identity: identity, - }, - }) - s.Nil(err) - - executionBuilder := s.getBuilder(constants.TestDomainID, we) - s.Equal(int64(11), executionBuilder.GetExecutionInfo().NextEventID) - s.Equal(int64(8), executionBuilder.GetExecutionInfo().LastProcessedEvent) - s.Equal(persistence.WorkflowStateRunning, executionBuilder.GetExecutionInfo().State) - s.False(executionBuilder.HasPendingDecision()) - - // Try recording activity heartbeat - s.mockExecutionMgr.On("UpdateWorkflowExecution", mock.Anything, mock.Anything).Return(&persistence.UpdateWorkflowExecutionResponse{MutableStateUpdateSessionStats: &persistence.MutableStateUpdateSessionStats{}}, nil).Once() - - activityTaskToken, _ := json.Marshal(&common.TaskToken{ - WorkflowID: "wId", - RunID: we.GetRunID(), - ScheduleID: 5, - }) - - hbResponse, err := s.mockHistoryEngine.RecordActivityTaskHeartbeat(context.Background(), &types.HistoryRecordActivityTaskHeartbeatRequest{ - DomainUUID: constants.TestDomainID, - HeartbeatRequest: &types.RecordActivityTaskHeartbeatRequest{ - TaskToken: activityTaskToken, - Identity: identity, - Details: []byte("details"), - }, - }) - s.Nil(err) - s.NotNil(hbResponse) - s.True(hbResponse.CancelRequested) - - // Try cancelling the request. - s.mockHistoryV2Mgr.On("AppendHistoryNodes", mock.Anything, mock.Anything).Return(&persistence.AppendHistoryNodesResponse{}, nil).Once() - s.mockExecutionMgr.On("UpdateWorkflowExecution", mock.Anything, mock.Anything).Return(&persistence.UpdateWorkflowExecutionResponse{MutableStateUpdateSessionStats: &persistence.MutableStateUpdateSessionStats{}}, nil).Once() - - err = s.mockHistoryEngine.RespondActivityTaskCanceled(context.Background(), &types.HistoryRespondActivityTaskCanceledRequest{ - DomainUUID: constants.TestDomainID, - CancelRequest: &types.RespondActivityTaskCanceledRequest{ - TaskToken: activityTaskToken, - Identity: identity, - Details: []byte("details"), - }, - }) - s.Nil(err) - - executionBuilder = s.getBuilder(constants.TestDomainID, we) - s.Equal(int64(13), executionBuilder.GetExecutionInfo().NextEventID) - s.Equal(int64(8), executionBuilder.GetExecutionInfo().LastProcessedEvent) - s.Equal(persistence.WorkflowStateRunning, executionBuilder.GetExecutionInfo().State) - s.True(executionBuilder.HasPendingDecision()) -} - -func (s *engineSuite) TestRequestCancel_RespondDecisionTaskCompleted_Success() { - - we := types.WorkflowExecution{ - WorkflowID: "wId", - RunID: constants.TestRunID, - } - tl := "testTaskList" - taskToken, _ := json.Marshal(&common.TaskToken{ - WorkflowID: we.WorkflowID, - RunID: we.RunID, - ScheduleID: 7, - }) - identity := "testIdentity" - activityID := "activity1_id" - activityType := "activity_type1" - activityInput := []byte("input1") - - msBuilder := execution.NewMutableStateBuilderWithEventV2( - s.mockHistoryEngine.shard, - testlogger.New(s.Suite.T()), - we.GetRunID(), - constants.TestLocalDomainEntry, - ) - test.AddWorkflowExecutionStartedEvent(msBuilder, we, "wType", tl, []byte("input"), 100, 100, identity) - di := test.AddDecisionTaskScheduledEvent(msBuilder) - decisionStartedEvent := test.AddDecisionTaskStartedEvent(msBuilder, di.ScheduleID, tl, identity) - decisionCompletedEvent := test.AddDecisionTaskCompletedEvent(msBuilder, di.ScheduleID, - decisionStartedEvent.ID, nil, identity) - activityScheduledEvent, _ := test.AddActivityTaskScheduledEvent(msBuilder, decisionCompletedEvent.ID, activityID, - activityType, tl, activityInput, 100, 10, 1, 1) - test.AddActivityTaskStartedEvent(msBuilder, activityScheduledEvent.ID, identity) - di2 := test.AddDecisionTaskScheduledEvent(msBuilder) - test.AddDecisionTaskStartedEvent(msBuilder, di2.ScheduleID, tl, identity) - - ms := execution.CreatePersistenceMutableState(msBuilder) - gwmsResponse := &persistence.GetWorkflowExecutionResponse{State: ms} - - decisions := []*types.Decision{{ - DecisionType: types.DecisionTypeRequestCancelActivityTask.Ptr(), - RequestCancelActivityTaskDecisionAttributes: &types.RequestCancelActivityTaskDecisionAttributes{ - ActivityID: activityID, - }, - }} - - s.mockExecutionMgr.On("GetWorkflowExecution", mock.Anything, mock.Anything).Return(gwmsResponse, nil).Once() - s.mockHistoryV2Mgr.On("AppendHistoryNodes", mock.Anything, mock.Anything).Return(&persistence.AppendHistoryNodesResponse{}, nil).Once() - s.mockExecutionMgr.On("UpdateWorkflowExecution", mock.Anything, mock.Anything).Return(&persistence.UpdateWorkflowExecutionResponse{MutableStateUpdateSessionStats: &persistence.MutableStateUpdateSessionStats{}}, nil).Once() - - _, err := s.mockHistoryEngine.RespondDecisionTaskCompleted(context.Background(), &types.HistoryRespondDecisionTaskCompletedRequest{ - DomainUUID: constants.TestDomainID, - CompleteRequest: &types.RespondDecisionTaskCompletedRequest{ - TaskToken: taskToken, - Decisions: decisions, - ExecutionContext: []byte("context"), - Identity: identity, - }, - }) - s.Nil(err) - - executionBuilder := s.getBuilder(constants.TestDomainID, we) - s.Equal(int64(11), executionBuilder.GetExecutionInfo().NextEventID) - s.Equal(int64(8), executionBuilder.GetExecutionInfo().LastProcessedEvent) - s.Equal(persistence.WorkflowStateRunning, executionBuilder.GetExecutionInfo().State) - s.False(executionBuilder.HasPendingDecision()) - - // Try recording activity heartbeat - s.mockExecutionMgr.On("UpdateWorkflowExecution", mock.Anything, mock.Anything).Return(&persistence.UpdateWorkflowExecutionResponse{MutableStateUpdateSessionStats: &persistence.MutableStateUpdateSessionStats{}}, nil).Once() - - activityTaskToken, _ := json.Marshal(&common.TaskToken{ - WorkflowID: "wId", - RunID: we.GetRunID(), - ScheduleID: 5, - }) - - hbResponse, err := s.mockHistoryEngine.RecordActivityTaskHeartbeat(context.Background(), &types.HistoryRecordActivityTaskHeartbeatRequest{ - DomainUUID: constants.TestDomainID, - HeartbeatRequest: &types.RecordActivityTaskHeartbeatRequest{ - TaskToken: activityTaskToken, - Identity: identity, - Details: []byte("details"), - }, - }) - s.Nil(err) - s.NotNil(hbResponse) - s.True(hbResponse.CancelRequested) - - // Try cancelling the request. - s.mockHistoryV2Mgr.On("AppendHistoryNodes", mock.Anything, mock.Anything).Return(&persistence.AppendHistoryNodesResponse{}, nil).Once() - s.mockExecutionMgr.On("UpdateWorkflowExecution", mock.Anything, mock.Anything).Return(&persistence.UpdateWorkflowExecutionResponse{MutableStateUpdateSessionStats: &persistence.MutableStateUpdateSessionStats{}}, nil).Once() - - err = s.mockHistoryEngine.RespondActivityTaskCanceled(context.Background(), &types.HistoryRespondActivityTaskCanceledRequest{ - DomainUUID: constants.TestDomainID, - CancelRequest: &types.RespondActivityTaskCanceledRequest{ - TaskToken: activityTaskToken, - Identity: identity, - Details: []byte("details"), - }, - }) - s.Nil(err) - - executionBuilder = s.getBuilder(constants.TestDomainID, we) - s.Equal(int64(13), executionBuilder.GetExecutionInfo().NextEventID) - s.Equal(int64(8), executionBuilder.GetExecutionInfo().LastProcessedEvent) - s.Equal(persistence.WorkflowStateRunning, executionBuilder.GetExecutionInfo().State) - s.True(executionBuilder.HasPendingDecision()) -} - -func (s *engineSuite) TestRequestCancel_RespondDecisionTaskCompleted_SuccessWithQueries() { - we := types.WorkflowExecution{ - WorkflowID: "wId", - RunID: constants.TestRunID, - } - tl := "testTaskList" - taskToken, _ := json.Marshal(&common.TaskToken{ - WorkflowID: we.WorkflowID, - RunID: we.RunID, - ScheduleID: 7, - }) - identity := "testIdentity" - activityID := "activity1_id" - activityType := "activity_type1" - activityInput := []byte("input1") - - msBuilder := execution.NewMutableStateBuilderWithEventV2( - s.mockHistoryEngine.shard, - testlogger.New(s.Suite.T()), - we.GetRunID(), - constants.TestLocalDomainEntry, - ) - test.AddWorkflowExecutionStartedEvent(msBuilder, we, "wType", tl, []byte("input"), 100, 100, identity) - di := test.AddDecisionTaskScheduledEvent(msBuilder) - decisionStartedEvent := test.AddDecisionTaskStartedEvent(msBuilder, di.ScheduleID, tl, identity) - decisionCompletedEvent := test.AddDecisionTaskCompletedEvent(msBuilder, di.ScheduleID, - decisionStartedEvent.ID, nil, identity) - activityScheduledEvent, _ := test.AddActivityTaskScheduledEvent(msBuilder, decisionCompletedEvent.ID, activityID, - activityType, tl, activityInput, 100, 10, 1, 1) - test.AddActivityTaskStartedEvent(msBuilder, activityScheduledEvent.ID, identity) - di2 := test.AddDecisionTaskScheduledEvent(msBuilder) - test.AddDecisionTaskStartedEvent(msBuilder, di2.ScheduleID, tl, identity) - - ms := execution.CreatePersistenceMutableState(msBuilder) - gwmsResponse := &persistence.GetWorkflowExecutionResponse{State: ms} - - decisions := []*types.Decision{{ - DecisionType: types.DecisionTypeRequestCancelActivityTask.Ptr(), - RequestCancelActivityTaskDecisionAttributes: &types.RequestCancelActivityTaskDecisionAttributes{ - ActivityID: activityID, - }, - }} - - s.mockExecutionMgr.On("GetWorkflowExecution", mock.Anything, mock.Anything).Return(gwmsResponse, nil).Once() - s.mockHistoryV2Mgr.On("AppendHistoryNodes", mock.Anything, mock.Anything).Return(&persistence.AppendHistoryNodesResponse{}, nil).Once() - s.mockExecutionMgr.On("UpdateWorkflowExecution", mock.Anything, mock.Anything).Return(&persistence.UpdateWorkflowExecutionResponse{MutableStateUpdateSessionStats: &persistence.MutableStateUpdateSessionStats{}}, nil).Once() - - // load mutable state such that it already exists in memory when respond decision task is called - // this enables us to set query registry on it - ctx, release, err := s.mockHistoryEngine.executionCache.GetOrCreateWorkflowExecutionForBackground(constants.TestDomainID, we) - s.NoError(err) - loadedMS, err := ctx.LoadWorkflowExecution(context.Background()) - s.NoError(err) - qr := query.NewRegistry() - id1, _ := qr.BufferQuery(&types.WorkflowQuery{}) - id2, _ := qr.BufferQuery(&types.WorkflowQuery{}) - id3, _ := qr.BufferQuery(&types.WorkflowQuery{}) - loadedMS.SetQueryRegistry(qr) - release(nil) - result1 := &types.WorkflowQueryResult{ - ResultType: types.QueryResultTypeAnswered.Ptr(), - Answer: []byte{1, 2, 3}, - } - result2 := &types.WorkflowQueryResult{ - ResultType: types.QueryResultTypeFailed.Ptr(), - ErrorMessage: "error reason", - } - queryResults := map[string]*types.WorkflowQueryResult{ - id1: result1, - id2: result2, - } - _, err = s.mockHistoryEngine.RespondDecisionTaskCompleted(s.constructCallContext(cc.GoWorkerConsistentQueryVersion), &types.HistoryRespondDecisionTaskCompletedRequest{ - DomainUUID: constants.TestDomainID, - CompleteRequest: &types.RespondDecisionTaskCompletedRequest{ - TaskToken: taskToken, - Decisions: decisions, - ExecutionContext: []byte("context"), - Identity: identity, - QueryResults: queryResults, - }, - }) - s.Nil(err) - - executionBuilder := s.getBuilder(constants.TestDomainID, we) - s.Equal(int64(11), executionBuilder.GetExecutionInfo().NextEventID) - s.Equal(int64(8), executionBuilder.GetExecutionInfo().LastProcessedEvent) - s.Equal(persistence.WorkflowStateRunning, executionBuilder.GetExecutionInfo().State) - s.False(executionBuilder.HasPendingDecision()) - s.Len(qr.GetCompletedIDs(), 2) - completed1, err := qr.GetTerminationState(id1) - s.NoError(err) - s.Equal(result1, completed1.QueryResult) - s.Equal(query.TerminationTypeCompleted, completed1.TerminationType) - completed2, err := qr.GetTerminationState(id2) - s.NoError(err) - s.Equal(result2, completed2.QueryResult) - s.Equal(query.TerminationTypeCompleted, completed2.TerminationType) - s.Len(qr.GetBufferedIDs(), 0) - s.Len(qr.GetFailedIDs(), 0) - s.Len(qr.GetUnblockedIDs(), 1) - unblocked1, err := qr.GetTerminationState(id3) - s.NoError(err) - s.Nil(unblocked1.QueryResult) - s.Equal(query.TerminationTypeUnblocked, unblocked1.TerminationType) - - // Try recording activity heartbeat - s.mockExecutionMgr.On("UpdateWorkflowExecution", mock.Anything, mock.Anything).Return(&persistence.UpdateWorkflowExecutionResponse{MutableStateUpdateSessionStats: &persistence.MutableStateUpdateSessionStats{}}, nil).Once() - - activityTaskToken, _ := json.Marshal(&common.TaskToken{ - WorkflowID: "wId", - RunID: we.GetRunID(), - ScheduleID: 5, - }) - - hbResponse, err := s.mockHistoryEngine.RecordActivityTaskHeartbeat(context.Background(), &types.HistoryRecordActivityTaskHeartbeatRequest{ - DomainUUID: constants.TestDomainID, - HeartbeatRequest: &types.RecordActivityTaskHeartbeatRequest{ - TaskToken: activityTaskToken, - Identity: identity, - Details: []byte("details"), - }, - }) - s.Nil(err) - s.NotNil(hbResponse) - s.True(hbResponse.CancelRequested) - - // Try cancelling the request. - s.mockHistoryV2Mgr.On("AppendHistoryNodes", mock.Anything, mock.Anything).Return(&persistence.AppendHistoryNodesResponse{}, nil).Once() - s.mockExecutionMgr.On("UpdateWorkflowExecution", mock.Anything, mock.Anything).Return(&persistence.UpdateWorkflowExecutionResponse{MutableStateUpdateSessionStats: &persistence.MutableStateUpdateSessionStats{}}, nil).Once() - - err = s.mockHistoryEngine.RespondActivityTaskCanceled(context.Background(), &types.HistoryRespondActivityTaskCanceledRequest{ - DomainUUID: constants.TestDomainID, - CancelRequest: &types.RespondActivityTaskCanceledRequest{ - TaskToken: activityTaskToken, - Identity: identity, - Details: []byte("details"), - }, - }) - s.Nil(err) - - executionBuilder = s.getBuilder(constants.TestDomainID, we) - s.Equal(int64(13), executionBuilder.GetExecutionInfo().NextEventID) - s.Equal(int64(8), executionBuilder.GetExecutionInfo().LastProcessedEvent) - s.Equal(persistence.WorkflowStateRunning, executionBuilder.GetExecutionInfo().State) - s.True(executionBuilder.HasPendingDecision()) -} - -func (s *engineSuite) TestRequestCancel_RespondDecisionTaskCompleted_SuccessWithConsistentQueriesUnsupported() { - we := types.WorkflowExecution{ - WorkflowID: "wId", - RunID: constants.TestRunID, - } - tl := "testTaskList" - taskToken, _ := json.Marshal(&common.TaskToken{ - WorkflowID: we.WorkflowID, - RunID: we.RunID, - ScheduleID: 7, - }) - identity := "testIdentity" - activityID := "activity1_id" - activityType := "activity_type1" - activityInput := []byte("input1") - - msBuilder := execution.NewMutableStateBuilderWithEventV2( - s.mockHistoryEngine.shard, - testlogger.New(s.Suite.T()), - we.GetRunID(), - constants.TestLocalDomainEntry, - ) - test.AddWorkflowExecutionStartedEvent(msBuilder, we, "wType", tl, []byte("input"), 100, 100, identity) - di := test.AddDecisionTaskScheduledEvent(msBuilder) - decisionStartedEvent := test.AddDecisionTaskStartedEvent(msBuilder, di.ScheduleID, tl, identity) - decisionCompletedEvent := test.AddDecisionTaskCompletedEvent(msBuilder, di.ScheduleID, - decisionStartedEvent.ID, nil, identity) - activityScheduledEvent, _ := test.AddActivityTaskScheduledEvent(msBuilder, decisionCompletedEvent.ID, activityID, - activityType, tl, activityInput, 100, 10, 1, 1) - test.AddActivityTaskStartedEvent(msBuilder, activityScheduledEvent.ID, identity) - di2 := test.AddDecisionTaskScheduledEvent(msBuilder) - test.AddDecisionTaskStartedEvent(msBuilder, di2.ScheduleID, tl, identity) - - ms := execution.CreatePersistenceMutableState(msBuilder) - gwmsResponse := &persistence.GetWorkflowExecutionResponse{State: ms} - - decisions := []*types.Decision{{ - DecisionType: types.DecisionTypeRequestCancelActivityTask.Ptr(), - RequestCancelActivityTaskDecisionAttributes: &types.RequestCancelActivityTaskDecisionAttributes{ - ActivityID: activityID, - }, - }} - - s.mockExecutionMgr.On("GetWorkflowExecution", mock.Anything, mock.Anything).Return(gwmsResponse, nil).Once() - s.mockHistoryV2Mgr.On("AppendHistoryNodes", mock.Anything, mock.Anything).Return(&persistence.AppendHistoryNodesResponse{}, nil).Once() - s.mockExecutionMgr.On("UpdateWorkflowExecution", mock.Anything, mock.Anything).Return(&persistence.UpdateWorkflowExecutionResponse{MutableStateUpdateSessionStats: &persistence.MutableStateUpdateSessionStats{}}, nil).Once() - - // load mutable state such that it already exists in memory when respond decision task is called - // this enables us to set query registry on it - ctx, release, err := s.mockHistoryEngine.executionCache.GetOrCreateWorkflowExecutionForBackground(constants.TestDomainID, we) - s.NoError(err) - loadedMS, err := ctx.LoadWorkflowExecution(context.Background()) - s.NoError(err) - qr := query.NewRegistry() - qr.BufferQuery(&types.WorkflowQuery{}) - qr.BufferQuery(&types.WorkflowQuery{}) - qr.BufferQuery(&types.WorkflowQuery{}) - loadedMS.SetQueryRegistry(qr) - release(nil) - _, err = s.mockHistoryEngine.RespondDecisionTaskCompleted(s.constructCallContext("0.0.0"), &types.HistoryRespondDecisionTaskCompletedRequest{ - DomainUUID: constants.TestDomainID, - CompleteRequest: &types.RespondDecisionTaskCompletedRequest{ - TaskToken: taskToken, - Decisions: decisions, - ExecutionContext: []byte("context"), - Identity: identity, - }, - }) - s.Nil(err) - - executionBuilder := s.getBuilder(constants.TestDomainID, we) - s.Equal(int64(11), executionBuilder.GetExecutionInfo().NextEventID) - s.Equal(int64(8), executionBuilder.GetExecutionInfo().LastProcessedEvent) - s.Equal(persistence.WorkflowStateRunning, executionBuilder.GetExecutionInfo().State) - s.False(executionBuilder.HasPendingDecision()) - s.Len(qr.GetBufferedIDs(), 0) - s.Len(qr.GetCompletedIDs(), 0) - s.Len(qr.GetUnblockedIDs(), 0) - s.Len(qr.GetFailedIDs(), 3) -} - -func (s *engineSuite) constructCallContext(featureVersion string) context.Context { - ctx := context.Background() - ctx, call := encoding.NewInboundCall(ctx) - err := call.ReadFromRequest(&transport.Request{ - Headers: transport.NewHeaders().With(common.ClientImplHeaderName, cc.GoSDK).With(common.FeatureVersionHeaderName, featureVersion), - }) - s.NoError(err) - return ctx -} - -func (s *engineSuite) TestStarTimer_DuplicateTimerID() { - - we := types.WorkflowExecution{ - WorkflowID: "wId", - RunID: constants.TestRunID, - } - tl := "testTaskList" - taskToken, _ := json.Marshal(&common.TaskToken{ - WorkflowID: we.WorkflowID, - RunID: we.RunID, - ScheduleID: 2, - }) - identity := "testIdentity" - timerID := "t1" - - msBuilder := execution.NewMutableStateBuilderWithEventV2( - s.mockHistoryEngine.shard, - testlogger.New(s.Suite.T()), - we.GetRunID(), - constants.TestLocalDomainEntry, - ) - - test.AddWorkflowExecutionStartedEvent(msBuilder, we, "wType", tl, []byte("input"), 100, 100, identity) - di := test.AddDecisionTaskScheduledEvent(msBuilder) - test.AddDecisionTaskStartedEvent(msBuilder, di.ScheduleID, tl, identity) - - ms := execution.CreatePersistenceMutableState(msBuilder) - gwmsResponse := &persistence.GetWorkflowExecutionResponse{State: ms} - - decisions := []*types.Decision{{ - DecisionType: types.DecisionTypeStartTimer.Ptr(), - StartTimerDecisionAttributes: &types.StartTimerDecisionAttributes{ - TimerID: timerID, - StartToFireTimeoutSeconds: common.Int64Ptr(1), - }, - }} - - s.mockExecutionMgr.On("GetWorkflowExecution", mock.Anything, mock.Anything).Return(gwmsResponse, nil).Once() - s.mockHistoryV2Mgr.On("AppendHistoryNodes", mock.Anything, mock.Anything).Return(&persistence.AppendHistoryNodesResponse{}, nil).Once() - s.mockExecutionMgr.On("UpdateWorkflowExecution", mock.Anything, mock.Anything).Return(&persistence.UpdateWorkflowExecutionResponse{MutableStateUpdateSessionStats: &persistence.MutableStateUpdateSessionStats{}}, nil).Once() - - _, err := s.mockHistoryEngine.RespondDecisionTaskCompleted(context.Background(), &types.HistoryRespondDecisionTaskCompletedRequest{ - DomainUUID: constants.TestDomainID, - CompleteRequest: &types.RespondDecisionTaskCompletedRequest{ - TaskToken: taskToken, - Decisions: decisions, - ExecutionContext: []byte("context"), - Identity: identity, - }, - }) - s.Nil(err) - - executionBuilder := s.getBuilder(constants.TestDomainID, we) - s.Equal(persistence.WorkflowStateRunning, executionBuilder.GetExecutionInfo().State) - - // Try to add the same timer ID again. - di2 := test.AddDecisionTaskScheduledEvent(executionBuilder) - test.AddDecisionTaskStartedEvent(executionBuilder, di2.ScheduleID, tl, identity) - taskToken2, _ := json.Marshal(&common.TaskToken{ - WorkflowID: we.WorkflowID, - RunID: we.RunID, - ScheduleID: di2.ScheduleID, - }) - - ms2 := execution.CreatePersistenceMutableState(executionBuilder) - gwmsResponse2 := &persistence.GetWorkflowExecutionResponse{State: ms2} - - decisionFailedEvent := false - s.mockExecutionMgr.On("GetWorkflowExecution", mock.Anything, mock.Anything).Return(gwmsResponse2, nil).Once() - s.mockHistoryV2Mgr.On("AppendHistoryNodes", mock.Anything, mock.Anything).Return(&persistence.AppendHistoryNodesResponse{}, nil).Run(func(arguments mock.Arguments) { - req := arguments.Get(1).(*persistence.AppendHistoryNodesRequest) - decTaskIndex := len(req.Events) - 1 - if decTaskIndex >= 0 && *req.Events[decTaskIndex].EventType == types.EventTypeDecisionTaskFailed { - decisionFailedEvent = true - } - }).Once() - s.mockExecutionMgr.On("UpdateWorkflowExecution", mock.Anything, mock.Anything).Return(&persistence.UpdateWorkflowExecutionResponse{MutableStateUpdateSessionStats: &persistence.MutableStateUpdateSessionStats{}}, nil).Once() - - _, err = s.mockHistoryEngine.RespondDecisionTaskCompleted(context.Background(), &types.HistoryRespondDecisionTaskCompletedRequest{ - DomainUUID: constants.TestDomainID, - CompleteRequest: &types.RespondDecisionTaskCompletedRequest{ - TaskToken: taskToken2, - Decisions: decisions, - ExecutionContext: []byte("context"), - Identity: identity, - }, - }) - s.Nil(err) - - s.True(decisionFailedEvent) - executionBuilder = s.getBuilder(constants.TestDomainID, we) - s.Equal(persistence.WorkflowStateRunning, executionBuilder.GetExecutionInfo().State) - s.True(executionBuilder.HasPendingDecision()) - di3, ok := executionBuilder.GetDecisionInfo(executionBuilder.GetExecutionInfo().NextEventID) - s.True(ok, "DI.ScheduleID: %v, ScheduleID: %v, StartedID: %v", di2.ScheduleID, - executionBuilder.GetExecutionInfo().DecisionScheduleID, executionBuilder.GetExecutionInfo().DecisionStartedID) - s.Equal(executionBuilder.GetExecutionInfo().NextEventID, di3.ScheduleID) - s.Equal(int64(1), di3.Attempt) -} - -func (s *engineSuite) TestUserTimer_RespondDecisionTaskCompleted() { - - we := types.WorkflowExecution{ - WorkflowID: "wId", - RunID: constants.TestRunID, - } - tl := "testTaskList" - taskToken, _ := json.Marshal(&common.TaskToken{ - WorkflowID: we.WorkflowID, - RunID: we.RunID, - ScheduleID: 6, - }) - identity := "testIdentity" - timerID := "t1" - - msBuilder := execution.NewMutableStateBuilderWithEventV2( - s.mockHistoryEngine.shard, - testlogger.New(s.Suite.T()), - we.GetRunID(), - constants.TestLocalDomainEntry, - ) - // Verify cancel timer with a start event. - test.AddWorkflowExecutionStartedEvent(msBuilder, we, "wType", tl, []byte("input"), 100, 100, identity) - di := test.AddDecisionTaskScheduledEvent(msBuilder) - decisionStartedEvent := test.AddDecisionTaskStartedEvent(msBuilder, di.ScheduleID, tl, identity) - decisionCompletedEvent := test.AddDecisionTaskCompletedEvent(msBuilder, di.ScheduleID, - decisionStartedEvent.ID, nil, identity) - test.AddTimerStartedEvent(msBuilder, decisionCompletedEvent.ID, timerID, 10) - di2 := test.AddDecisionTaskScheduledEvent(msBuilder) - test.AddDecisionTaskStartedEvent(msBuilder, di2.ScheduleID, tl, identity) - - ms := execution.CreatePersistenceMutableState(msBuilder) - gwmsResponse := &persistence.GetWorkflowExecutionResponse{State: ms} - - decisions := []*types.Decision{{ - DecisionType: types.DecisionTypeCancelTimer.Ptr(), - CancelTimerDecisionAttributes: &types.CancelTimerDecisionAttributes{ - TimerID: timerID, - }, - }} - - s.mockExecutionMgr.On("GetWorkflowExecution", mock.Anything, mock.Anything).Return(gwmsResponse, nil).Once() - s.mockHistoryV2Mgr.On("AppendHistoryNodes", mock.Anything, mock.Anything).Return(&persistence.AppendHistoryNodesResponse{}, nil).Once() - s.mockExecutionMgr.On("UpdateWorkflowExecution", mock.Anything, mock.Anything).Return(&persistence.UpdateWorkflowExecutionResponse{MutableStateUpdateSessionStats: &persistence.MutableStateUpdateSessionStats{}}, nil).Once() - - _, err := s.mockHistoryEngine.RespondDecisionTaskCompleted(context.Background(), &types.HistoryRespondDecisionTaskCompletedRequest{ - DomainUUID: constants.TestDomainID, - CompleteRequest: &types.RespondDecisionTaskCompletedRequest{ - TaskToken: taskToken, - Decisions: decisions, - ExecutionContext: []byte("context"), - Identity: identity, - }, - }) - s.Nil(err) - - executionBuilder := s.getBuilder(constants.TestDomainID, we) - s.Equal(int64(10), executionBuilder.GetExecutionInfo().NextEventID) - s.Equal(int64(7), executionBuilder.GetExecutionInfo().LastProcessedEvent) - s.Equal(persistence.WorkflowStateRunning, executionBuilder.GetExecutionInfo().State) - s.False(executionBuilder.HasPendingDecision()) -} - -func (s *engineSuite) TestCancelTimer_RespondDecisionTaskCompleted_NoStartTimer() { - - we := types.WorkflowExecution{ - WorkflowID: "wId", - RunID: constants.TestRunID, - } - tl := "testTaskList" - taskToken, _ := json.Marshal(&common.TaskToken{ - WorkflowID: we.WorkflowID, - RunID: we.RunID, - ScheduleID: 2, - }) - identity := "testIdentity" - timerID := "t1" - - msBuilder := execution.NewMutableStateBuilderWithEventV2( - s.mockHistoryEngine.shard, - testlogger.New(s.Suite.T()), - we.GetRunID(), - constants.TestLocalDomainEntry, - ) - // Verify cancel timer with a start event. - test.AddWorkflowExecutionStartedEvent(msBuilder, we, "wType", tl, []byte("input"), 100, 100, identity) - di := test.AddDecisionTaskScheduledEvent(msBuilder) - test.AddDecisionTaskStartedEvent(msBuilder, di.ScheduleID, tl, identity) - - ms := execution.CreatePersistenceMutableState(msBuilder) - gwmsResponse := &persistence.GetWorkflowExecutionResponse{State: ms} - - decisions := []*types.Decision{{ - DecisionType: types.DecisionTypeCancelTimer.Ptr(), - CancelTimerDecisionAttributes: &types.CancelTimerDecisionAttributes{ - TimerID: timerID, - }, - }} - - s.mockExecutionMgr.On("GetWorkflowExecution", mock.Anything, mock.Anything).Return(gwmsResponse, nil).Once() - s.mockHistoryV2Mgr.On("AppendHistoryNodes", mock.Anything, mock.Anything).Return(&persistence.AppendHistoryNodesResponse{}, nil).Once() - s.mockExecutionMgr.On("UpdateWorkflowExecution", mock.Anything, mock.Anything).Return(&persistence.UpdateWorkflowExecutionResponse{MutableStateUpdateSessionStats: &persistence.MutableStateUpdateSessionStats{}}, nil).Once() - - _, err := s.mockHistoryEngine.RespondDecisionTaskCompleted(context.Background(), &types.HistoryRespondDecisionTaskCompletedRequest{ - DomainUUID: constants.TestDomainID, - CompleteRequest: &types.RespondDecisionTaskCompletedRequest{ - TaskToken: taskToken, - Decisions: decisions, - ExecutionContext: []byte("context"), - Identity: identity, - }, - }) - s.Nil(err) - - executionBuilder := s.getBuilder(constants.TestDomainID, we) - s.Equal(int64(6), executionBuilder.GetExecutionInfo().NextEventID) - s.Equal(int64(3), executionBuilder.GetExecutionInfo().LastProcessedEvent) - s.Equal(persistence.WorkflowStateRunning, executionBuilder.GetExecutionInfo().State) - s.False(executionBuilder.HasPendingDecision()) -} - -func (s *engineSuite) TestCancelTimer_RespondDecisionTaskCompleted_TimerFired() { - - we := types.WorkflowExecution{ - WorkflowID: "wId", - RunID: constants.TestRunID, - } - tl := "testTaskList" - taskToken, _ := json.Marshal(&common.TaskToken{ - WorkflowID: we.WorkflowID, - RunID: we.RunID, - ScheduleID: 6, - }) - identity := "testIdentity" - timerID := "t1" - - msBuilder := execution.NewMutableStateBuilderWithEventV2( - s.mockHistoryEngine.shard, - testlogger.New(s.Suite.T()), - we.GetRunID(), - constants.TestLocalDomainEntry, - ) - // Verify cancel timer with a start event. - test.AddWorkflowExecutionStartedEvent(msBuilder, we, "wType", tl, []byte("input"), 100, 100, identity) - di := test.AddDecisionTaskScheduledEvent(msBuilder) - decisionStartedEvent := test.AddDecisionTaskStartedEvent(msBuilder, di.ScheduleID, tl, identity) - decisionCompletedEvent := test.AddDecisionTaskCompletedEvent(msBuilder, di.ScheduleID, - decisionStartedEvent.ID, nil, identity) - test.AddTimerStartedEvent(msBuilder, decisionCompletedEvent.ID, timerID, 10) - di2 := test.AddDecisionTaskScheduledEvent(msBuilder) - test.AddDecisionTaskStartedEvent(msBuilder, di2.ScheduleID, tl, identity) - test.AddTimerFiredEvent(msBuilder, timerID) - _, _, err := msBuilder.CloseTransactionAsMutation(time.Now(), execution.TransactionPolicyActive) - s.Nil(err) - - ms := execution.CreatePersistenceMutableState(msBuilder) - gwmsResponse := &persistence.GetWorkflowExecutionResponse{State: ms} - s.True(len(gwmsResponse.State.BufferedEvents) > 0) - - decisions := []*types.Decision{{ - DecisionType: types.DecisionTypeCancelTimer.Ptr(), - CancelTimerDecisionAttributes: &types.CancelTimerDecisionAttributes{ - TimerID: timerID, - }, - }} - - s.mockExecutionMgr.On("GetWorkflowExecution", mock.Anything, mock.Anything).Return(gwmsResponse, nil).Once() - s.mockHistoryV2Mgr.On("AppendHistoryNodes", mock.Anything, mock.Anything).Return(&persistence.AppendHistoryNodesResponse{}, nil).Once() - s.mockExecutionMgr.On("UpdateWorkflowExecution", mock.Anything, mock.MatchedBy(func(input *persistence.UpdateWorkflowExecutionRequest) bool { - // need to check whether the buffered events are cleared - s.True(input.UpdateWorkflowMutation.ClearBufferedEvents) - return true - })).Return(&persistence.UpdateWorkflowExecutionResponse{MutableStateUpdateSessionStats: &persistence.MutableStateUpdateSessionStats{}}, nil).Once() - - _, err = s.mockHistoryEngine.RespondDecisionTaskCompleted(context.Background(), &types.HistoryRespondDecisionTaskCompletedRequest{ - DomainUUID: constants.TestDomainID, - CompleteRequest: &types.RespondDecisionTaskCompletedRequest{ - TaskToken: taskToken, - Decisions: decisions, - ExecutionContext: []byte("context"), - Identity: identity, - }, - }) - s.Nil(err) - - executionBuilder := s.getBuilder(constants.TestDomainID, we) - s.Equal(int64(10), executionBuilder.GetExecutionInfo().NextEventID) - s.Equal(int64(7), executionBuilder.GetExecutionInfo().LastProcessedEvent) - s.Equal(persistence.WorkflowStateRunning, executionBuilder.GetExecutionInfo().State) - s.False(executionBuilder.HasPendingDecision()) - s.False(executionBuilder.HasBufferedEvents()) -} - -func (s *engineSuite) TestSignalWorkflowExecution_InvalidRequest() { - signalRequest := &types.HistorySignalWorkflowExecutionRequest{} - err := s.mockHistoryEngine.SignalWorkflowExecution(context.Background(), signalRequest) - s.Error(err) -} - -func (s *engineSuite) TestSignalWorkflowExecution() { - we := types.WorkflowExecution{ - WorkflowID: constants.TestWorkflowID, - RunID: constants.TestRunID, - } - tasklist := "testTaskList" - identity := "testIdentity" - signalName := "my signal name" - input := []byte("test input") - signalRequest := &types.HistorySignalWorkflowExecutionRequest{ - DomainUUID: constants.TestDomainID, - SignalRequest: &types.SignalWorkflowExecutionRequest{ - Domain: constants.TestDomainID, - WorkflowExecution: &we, - Identity: identity, - SignalName: signalName, - Input: input, - }, - } - - msBuilder := execution.NewMutableStateBuilderWithEventV2( - s.mockHistoryEngine.shard, - testlogger.New(s.Suite.T()), - we.GetRunID(), - constants.TestLocalDomainEntry, - ) - test.AddWorkflowExecutionStartedEvent(msBuilder, we, "wType", tasklist, []byte("input"), 100, 200, identity) - test.AddDecisionTaskScheduledEvent(msBuilder) - ms := execution.CreatePersistenceMutableState(msBuilder) - ms.ExecutionInfo.DomainID = constants.TestDomainID - gwmsResponse := &persistence.GetWorkflowExecutionResponse{State: ms} - - s.mockExecutionMgr.On("GetWorkflowExecution", mock.Anything, mock.Anything).Return(gwmsResponse, nil).Once() - s.mockHistoryV2Mgr.On("AppendHistoryNodes", mock.Anything, mock.Anything).Return(&persistence.AppendHistoryNodesResponse{}, nil).Once() - s.mockExecutionMgr.On("UpdateWorkflowExecution", mock.Anything, mock.Anything).Return(&persistence.UpdateWorkflowExecutionResponse{MutableStateUpdateSessionStats: &persistence.MutableStateUpdateSessionStats{}}, nil).Once() - - err := s.mockHistoryEngine.SignalWorkflowExecution(context.Background(), signalRequest) - s.Nil(err) -} - -// Test signal decision by adding request ID -func (s *engineSuite) TestSignalWorkflowExecution_DuplicateRequest_WorkflowOpen() { - we := types.WorkflowExecution{ - WorkflowID: constants.TestWorkflowID, - RunID: constants.TestRunID, - } - tasklist := "testTaskList" - identity := "testIdentity" - signalName := "my signal name 2" - input := []byte("test input 2") - requestID := uuid.New() - signalRequest := &types.HistorySignalWorkflowExecutionRequest{ - DomainUUID: constants.TestDomainID, - SignalRequest: &types.SignalWorkflowExecutionRequest{ - Domain: constants.TestDomainID, - WorkflowExecution: &we, - Identity: identity, - SignalName: signalName, - Input: input, - RequestID: requestID, - }, - } - - msBuilder := execution.NewMutableStateBuilderWithEventV2( - s.mockHistoryEngine.shard, - testlogger.New(s.Suite.T()), - we.GetRunID(), - constants.TestLocalDomainEntry, - ) - test.AddWorkflowExecutionStartedEvent(msBuilder, we, "wType", tasklist, []byte("input"), 100, 200, identity) - test.AddDecisionTaskScheduledEvent(msBuilder) - ms := execution.CreatePersistenceMutableState(msBuilder) - // assume duplicate request id - ms.SignalRequestedIDs = make(map[string]struct{}) - ms.SignalRequestedIDs[requestID] = struct{}{} - ms.ExecutionInfo.DomainID = constants.TestDomainID - gwmsResponse := &persistence.GetWorkflowExecutionResponse{State: ms} - - s.mockExecutionMgr.On("GetWorkflowExecution", mock.Anything, mock.Anything).Return(gwmsResponse, nil).Once() - - err := s.mockHistoryEngine.SignalWorkflowExecution(context.Background(), signalRequest) - s.Nil(err) -} - -func (s *engineSuite) TestSignalWorkflowExecution_DuplicateRequest_WorkflowCompleted() { - we := types.WorkflowExecution{ - WorkflowID: constants.TestWorkflowID, - RunID: constants.TestRunID, - } - tasklist := "testTaskList" - identity := "testIdentity" - signalName := "my signal name 2" - input := []byte("test input 2") - requestID := uuid.New() - signalRequest := &types.HistorySignalWorkflowExecutionRequest{ - DomainUUID: constants.TestDomainID, - SignalRequest: &types.SignalWorkflowExecutionRequest{ - Domain: constants.TestDomainID, - WorkflowExecution: &we, - Identity: identity, - SignalName: signalName, - Input: input, - RequestID: requestID, - }, - } - - msBuilder := execution.NewMutableStateBuilderWithEventV2( - s.mockHistoryEngine.shard, - testlogger.New(s.Suite.T()), - we.GetRunID(), - constants.TestLocalDomainEntry, - ) - test.AddWorkflowExecutionStartedEvent(msBuilder, we, "wType", tasklist, []byte("input"), 100, 200, identity) - test.AddDecisionTaskScheduledEvent(msBuilder) - ms := execution.CreatePersistenceMutableState(msBuilder) - // assume duplicate request id - ms.SignalRequestedIDs = make(map[string]struct{}) - ms.SignalRequestedIDs[requestID] = struct{}{} - ms.ExecutionInfo.DomainID = constants.TestDomainID - ms.ExecutionInfo.State = persistence.WorkflowStateCompleted - gwmsResponse := &persistence.GetWorkflowExecutionResponse{State: ms} - - s.mockExecutionMgr.On("GetWorkflowExecution", mock.Anything, mock.Anything).Return(gwmsResponse, nil).Once() - - err := s.mockHistoryEngine.SignalWorkflowExecution(context.Background(), signalRequest) - s.Nil(err) -} - -func (s *engineSuite) TestSignalWorkflowExecution_WorkflowCompleted() { - we := &types.WorkflowExecution{ - WorkflowID: constants.TestWorkflowID, - RunID: constants.TestRunID, - } - tasklist := "testTaskList" - identity := "testIdentity" - signalName := "my signal name" - input := []byte("test input") - signalRequest := &types.HistorySignalWorkflowExecutionRequest{ - DomainUUID: constants.TestDomainID, - SignalRequest: &types.SignalWorkflowExecutionRequest{ - Domain: constants.TestDomainID, - WorkflowExecution: we, - Identity: identity, - SignalName: signalName, - Input: input, - }, - } - - msBuilder := execution.NewMutableStateBuilderWithEventV2( - s.mockHistoryEngine.shard, - testlogger.New(s.Suite.T()), - we.GetRunID(), - constants.TestLocalDomainEntry, - ) - test.AddWorkflowExecutionStartedEvent(msBuilder, *we, "wType", tasklist, []byte("input"), 100, 200, identity) - test.AddDecisionTaskScheduledEvent(msBuilder) - ms := execution.CreatePersistenceMutableState(msBuilder) - ms.ExecutionInfo.State = persistence.WorkflowStateCompleted - gwmsResponse := &persistence.GetWorkflowExecutionResponse{State: ms} - - s.mockExecutionMgr.On("GetWorkflowExecution", mock.Anything, mock.Anything).Return(gwmsResponse, nil).Once() - - err := s.mockHistoryEngine.SignalWorkflowExecution(context.Background(), signalRequest) - s.EqualError(err, "workflow execution already completed") -} - -func (s *engineSuite) TestRemoveSignalMutableState() { - removeRequest := &types.RemoveSignalMutableStateRequest{} - err := s.mockHistoryEngine.RemoveSignalMutableState(context.Background(), removeRequest) - s.Error(err) - - workflowExecution := types.WorkflowExecution{ - WorkflowID: "wId", - RunID: constants.TestRunID, - } - tasklist := "testTaskList" - identity := "testIdentity" - requestID := uuid.New() - removeRequest = &types.RemoveSignalMutableStateRequest{ - DomainUUID: constants.TestDomainID, - WorkflowExecution: &workflowExecution, - RequestID: requestID, - } - - msBuilder := execution.NewMutableStateBuilderWithEventV2( - s.mockHistoryEngine.shard, - testlogger.New(s.Suite.T()), - constants.TestRunID, - constants.TestLocalDomainEntry, - ) - test.AddWorkflowExecutionStartedEvent(msBuilder, workflowExecution, "wType", tasklist, []byte("input"), 100, 200, identity) - test.AddDecisionTaskScheduledEvent(msBuilder) - ms := execution.CreatePersistenceMutableState(msBuilder) - ms.ExecutionInfo.DomainID = constants.TestDomainID - gwmsResponse := &persistence.GetWorkflowExecutionResponse{State: ms} - - s.mockExecutionMgr.On("GetWorkflowExecution", mock.Anything, mock.Anything).Return(gwmsResponse, nil).Once() - s.mockExecutionMgr.On("UpdateWorkflowExecution", mock.Anything, mock.Anything).Return(&persistence.UpdateWorkflowExecutionResponse{MutableStateUpdateSessionStats: &persistence.MutableStateUpdateSessionStats{}}, nil).Once() - - err = s.mockHistoryEngine.RemoveSignalMutableState(context.Background(), removeRequest) - s.Nil(err) -} - -func (s *engineSuite) TestReapplyEvents_ReturnSuccess() { - workflowExecution := types.WorkflowExecution{ - WorkflowID: "test-reapply", - RunID: constants.TestRunID, - } - history := []*types.HistoryEvent{ - { - ID: 1, - EventType: types.EventTypeWorkflowExecutionSignaled.Ptr(), - Version: 1, - }, - } - msBuilder := execution.NewMutableStateBuilderWithEventV2( - s.mockHistoryEngine.shard, - testlogger.New(s.Suite.T()), - workflowExecution.GetRunID(), - constants.TestLocalDomainEntry, - ) - ms := execution.CreatePersistenceMutableState(msBuilder) - gwmsResponse := &persistence.GetWorkflowExecutionResponse{State: ms} - gceResponse := &persistence.GetCurrentExecutionResponse{RunID: constants.TestRunID} - s.mockExecutionMgr.On("GetCurrentExecution", mock.Anything, mock.Anything).Return(gceResponse, nil).Once() - s.mockExecutionMgr.On("GetWorkflowExecution", mock.Anything, mock.Anything).Return(gwmsResponse, nil).Once() - s.mockEventsReapplier.EXPECT().ReapplyEvents(gomock.Any(), gomock.Any(), gomock.Any(), gomock.Any()).Times(1) - - err := s.mockHistoryEngine.ReapplyEvents( - context.Background(), - constants.TestDomainID, - workflowExecution.WorkflowID, - workflowExecution.RunID, - history, - ) - s.NoError(err) -} - -func (s *engineSuite) TestReapplyEvents_IgnoreSameVersionEvents() { - workflowExecution := types.WorkflowExecution{ - WorkflowID: "test-reapply-same-version", - RunID: constants.TestRunID, - } - history := []*types.HistoryEvent{ - { - ID: 1, - EventType: types.EventTypeTimerStarted.Ptr(), - Version: common.EmptyVersion, - }, - } - msBuilder := execution.NewMutableStateBuilderWithEventV2( - s.mockHistoryEngine.shard, - testlogger.New(s.Suite.T()), - workflowExecution.GetRunID(), - constants.TestLocalDomainEntry, - ) - - ms := execution.CreatePersistenceMutableState(msBuilder) - gwmsResponse := &persistence.GetWorkflowExecutionResponse{State: ms} - gceResponse := &persistence.GetCurrentExecutionResponse{RunID: constants.TestRunID} - s.mockExecutionMgr.On("GetCurrentExecution", mock.Anything, mock.Anything).Return(gceResponse, nil).Once() - s.mockExecutionMgr.On("GetWorkflowExecution", mock.Anything, mock.Anything).Return(gwmsResponse, nil).Once() - s.mockEventsReapplier.EXPECT().ReapplyEvents(gomock.Any(), gomock.Any(), gomock.Any(), gomock.Any()).Times(0) - - err := s.mockHistoryEngine.ReapplyEvents( - context.Background(), - constants.TestDomainID, - workflowExecution.WorkflowID, - workflowExecution.RunID, - history, - ) - s.NoError(err) -} - -func (s *engineSuite) TestReapplyEvents_ResetWorkflow() { - workflowExecution := types.WorkflowExecution{ - WorkflowID: "test-reapply-reset-workflow", - RunID: constants.TestRunID, - } - history := []*types.HistoryEvent{ - { - ID: 1, - EventType: types.EventTypeWorkflowExecutionSignaled.Ptr(), - Version: 100, - }, - } - msBuilder := execution.NewMutableStateBuilderWithEventV2( - s.mockHistoryEngine.shard, - testlogger.New(s.Suite.T()), - workflowExecution.GetRunID(), - constants.TestLocalDomainEntry, - ) - ms := execution.CreatePersistenceMutableState(msBuilder) - ms.ExecutionInfo.State = persistence.WorkflowStateCompleted - ms.ExecutionInfo.LastProcessedEvent = 1 - token, err := msBuilder.GetCurrentBranchToken() - s.NoError(err) - item := persistence.NewVersionHistoryItem(1, 1) - versionHistory := persistence.NewVersionHistory(token, []*persistence.VersionHistoryItem{item}) - ms.VersionHistories = persistence.NewVersionHistories(versionHistory) - gwmsResponse := &persistence.GetWorkflowExecutionResponse{State: ms} - gceResponse := &persistence.GetCurrentExecutionResponse{RunID: constants.TestRunID} - s.mockExecutionMgr.On("GetCurrentExecution", mock.Anything, mock.Anything).Return(gceResponse, nil).Once() - s.mockExecutionMgr.On("GetWorkflowExecution", mock.Anything, mock.Anything).Return(gwmsResponse, nil).Once() - s.mockEventsReapplier.EXPECT().ReapplyEvents(gomock.Any(), gomock.Any(), gomock.Any(), gomock.Any()).Times(0) - s.mockWorkflowResetter.EXPECT().ResetWorkflow(gomock.Any(), gomock.Any(), gomock.Any(), gomock.Any(), gomock.Any(), - gomock.Any(), gomock.Any(), gomock.Any(), gomock.Any(), gomock.Any(), gomock.Any(), gomock.Any(), gomock.Any(), - gomock.Any(), - ).Return(nil).Times(1) - err = s.mockHistoryEngine.ReapplyEvents( - context.Background(), - constants.TestDomainID, - workflowExecution.WorkflowID, - workflowExecution.RunID, - history, - ) - s.NoError(err) -} - -func (s *engineSuite) getBuilder(testDomainID string, we types.WorkflowExecution) execution.MutableState { - context, release, err := s.mockHistoryEngine.executionCache.GetOrCreateWorkflowExecutionForBackground(testDomainID, we) - if err != nil { - return nil - } - defer release(nil) - - return context.GetWorkflowExecution() -} - -func (s *engineSuite) getActivityScheduledEvent( - msBuilder execution.MutableState, - scheduleID int64, -) *types.HistoryEvent { - event, _ := msBuilder.GetActivityScheduledEvent(context.Background(), scheduleID) - return event -} - -func (s *engineSuite) printHistory(builder execution.MutableState) string { - return thrift.FromHistory(builder.GetHistoryBuilder().GetHistory()).String() -} - -func TestRecordChildExecutionCompleted(t *testing.T) { - testCases := []struct { - name string - request *types.RecordChildExecutionCompletedRequest - mockSetup func(*execution.MockMutableState) - wantErr bool - assertErr func(t *testing.T, err error) - }{ - { - name: "workflow not running", - request: &types.RecordChildExecutionCompletedRequest{ - DomainUUID: "58f7998e-9c00-4827-bbd3-6a891b3ca0ca", - InitiatedID: 1, - WorkflowExecution: &types.WorkflowExecution{ - WorkflowID: "wid", - RunID: "4353ddce-ca34-4c78-9785-dc0b83af4bbc", - }, - CompletedExecution: &types.WorkflowExecution{ - WorkflowID: "wid1", - RunID: "312b2440-2859-4e50-a59f-d92a300a072d", - }, - }, - mockSetup: func(ms *execution.MockMutableState) { - ms.EXPECT().IsWorkflowExecutionRunning().Return(false) - }, - wantErr: true, - assertErr: func(t *testing.T, err error) { - assert.Equal(t, workflow.ErrNotExists, err) - }, - }, - { - name: "stale mutable state - not containing initiated event", - request: &types.RecordChildExecutionCompletedRequest{ - DomainUUID: "58f7998e-9c00-4827-bbd3-6a891b3ca0ca", - InitiatedID: 10, - WorkflowExecution: &types.WorkflowExecution{ - WorkflowID: "wid", - RunID: "4353ddce-ca34-4c78-9785-dc0b83af4bbc", - }, - CompletedExecution: &types.WorkflowExecution{ - WorkflowID: "wid1", - RunID: "312b2440-2859-4e50-a59f-d92a300a072d", - }, - }, - mockSetup: func(ms *execution.MockMutableState) { - ms.EXPECT().IsWorkflowExecutionRunning().Return(true) - ms.EXPECT().GetChildExecutionInfo(int64(10)).Return(nil, false) - ms.EXPECT().GetNextEventID().Return(int64(10)).Times(2) - }, - wantErr: true, - assertErr: func(t *testing.T, err error) { - assert.Equal(t, workflow.ErrStaleState, err) - }, - }, - { - name: "pending child execution not found", - request: &types.RecordChildExecutionCompletedRequest{ - DomainUUID: "58f7998e-9c00-4827-bbd3-6a891b3ca0ca", - InitiatedID: 10, - WorkflowExecution: &types.WorkflowExecution{ - WorkflowID: "wid", - RunID: "4353ddce-ca34-4c78-9785-dc0b83af4bbc", - }, - CompletedExecution: &types.WorkflowExecution{ - WorkflowID: "wid1", - RunID: "312b2440-2859-4e50-a59f-d92a300a072d", - }, - }, - mockSetup: func(ms *execution.MockMutableState) { - ms.EXPECT().IsWorkflowExecutionRunning().Return(true) - ms.EXPECT().GetChildExecutionInfo(int64(10)).Return(nil, false) - ms.EXPECT().GetNextEventID().Return(int64(11)).Times(1) - }, - wantErr: true, - assertErr: func(t *testing.T, err error) { - assert.Equal(t, &types.EntityNotExistsError{Message: "Pending child execution not found."}, err) - }, - }, - { - name: "stale mutable state - not containing started event", - request: &types.RecordChildExecutionCompletedRequest{ - DomainUUID: "58f7998e-9c00-4827-bbd3-6a891b3ca0ca", - InitiatedID: 10, - WorkflowExecution: &types.WorkflowExecution{ - WorkflowID: "wid", - RunID: "4353ddce-ca34-4c78-9785-dc0b83af4bbc", - }, - CompletedExecution: &types.WorkflowExecution{ - WorkflowID: "wid1", - RunID: "312b2440-2859-4e50-a59f-d92a300a072d", - }, - StartedID: 11, - }, - mockSetup: func(ms *execution.MockMutableState) { - ms.EXPECT().IsWorkflowExecutionRunning().Return(true) - ms.EXPECT().GetChildExecutionInfo(int64(10)).Return(&persistence.ChildExecutionInfo{StartedID: common.EmptyEventID}, true) - ms.EXPECT().GetNextEventID().Return(int64(11)).Times(2) - }, - wantErr: true, - assertErr: func(t *testing.T, err error) { - assert.Equal(t, workflow.ErrStaleState, err) - }, - }, - { - name: "pending child execution not started", - request: &types.RecordChildExecutionCompletedRequest{ - DomainUUID: "58f7998e-9c00-4827-bbd3-6a891b3ca0ca", - InitiatedID: 10, - WorkflowExecution: &types.WorkflowExecution{ - WorkflowID: "wid", - RunID: "4353ddce-ca34-4c78-9785-dc0b83af4bbc", - }, - CompletedExecution: &types.WorkflowExecution{ - WorkflowID: "wid1", - RunID: "312b2440-2859-4e50-a59f-d92a300a072d", - }, - StartedID: 11, - }, - mockSetup: func(ms *execution.MockMutableState) { - ms.EXPECT().IsWorkflowExecutionRunning().Return(true) - ms.EXPECT().GetChildExecutionInfo(int64(10)).Return(&persistence.ChildExecutionInfo{StartedID: common.EmptyEventID}, true) - ms.EXPECT().GetNextEventID().Return(int64(12)).Times(1) - }, - wantErr: true, - assertErr: func(t *testing.T, err error) { - assert.Equal(t, &types.EntityNotExistsError{Message: "Pending child execution not started."}, err) - }, - }, - { - name: "pending child execution workflowID mismatch", - request: &types.RecordChildExecutionCompletedRequest{ - DomainUUID: "58f7998e-9c00-4827-bbd3-6a891b3ca0ca", - InitiatedID: 10, - WorkflowExecution: &types.WorkflowExecution{ - WorkflowID: "wid", - RunID: "4353ddce-ca34-4c78-9785-dc0b83af4bbc", - }, - CompletedExecution: &types.WorkflowExecution{ - WorkflowID: "wid1", - RunID: "312b2440-2859-4e50-a59f-d92a300a072d", - }, - StartedID: 11, - }, - mockSetup: func(ms *execution.MockMutableState) { - ms.EXPECT().IsWorkflowExecutionRunning().Return(true) - ms.EXPECT().GetChildExecutionInfo(int64(10)).Return(&persistence.ChildExecutionInfo{StartedID: 11, StartedWorkflowID: "wid0"}, true) - }, - wantErr: true, - assertErr: func(t *testing.T, err error) { - assert.Equal(t, &types.EntityNotExistsError{Message: "Pending child execution workflowID mismatch."}, err) - }, - }, - { - name: "success - child workflow completed", - request: &types.RecordChildExecutionCompletedRequest{ - DomainUUID: "58f7998e-9c00-4827-bbd3-6a891b3ca0ca", - InitiatedID: 10, - WorkflowExecution: &types.WorkflowExecution{ - WorkflowID: "wid", - RunID: "4353ddce-ca34-4c78-9785-dc0b83af4bbc", - }, - CompletedExecution: &types.WorkflowExecution{ - WorkflowID: "wid1", - RunID: "312b2440-2859-4e50-a59f-d92a300a072d", - }, - CompletionEvent: &types.HistoryEvent{ - EventType: types.EventTypeWorkflowExecutionCompleted.Ptr(), - WorkflowExecutionCompletedEventAttributes: &types.WorkflowExecutionCompletedEventAttributes{ - Result: []byte("success"), - }, - }, - StartedID: 11, - }, - mockSetup: func(ms *execution.MockMutableState) { - ms.EXPECT().IsWorkflowExecutionRunning().Return(true) - ms.EXPECT().GetChildExecutionInfo(int64(10)).Return(&persistence.ChildExecutionInfo{StartedID: 11, StartedWorkflowID: "wid1"}, true) - ms.EXPECT().AddChildWorkflowExecutionCompletedEvent(int64(10), gomock.Any(), gomock.Any()).Return(nil, nil) - }, - wantErr: false, - }, - } - - for _, tc := range testCases { - t.Run(tc.name, func(t *testing.T) { - ctrl := gomock.NewController(t) - mockShard := shard.NewTestContext(t, ctrl, &persistence.ShardInfo{}, config.NewForTest()) - mockDomainCache := mockShard.Resource.DomainCache - testDomainEntry := cache.NewLocalDomainCacheEntryForTest( - &persistence.DomainInfo{ID: constants.TestDomainID}, &persistence.DomainConfig{}, "", - ) - mockDomainCache.EXPECT().GetDomainByID(gomock.Any()).Return(testDomainEntry, nil).AnyTimes() - mockDomainCache.EXPECT().GetDomainName(gomock.Any()).Return(constants.TestDomainID, nil).AnyTimes() - ms := execution.NewMockMutableState(ctrl) - tc.mockSetup(ms) - - historyEngine := &historyEngineImpl{ - shard: mockShard, - clusterMetadata: mockShard.GetClusterMetadata(), - timeSource: mockShard.GetTimeSource(), - metricsClient: metrics.NewClient(tally.NoopScope, metrics.History), - logger: mockShard.GetLogger(), - updateWithActionFn: func(_ context.Context, _ *execution.Cache, _ string, _ types.WorkflowExecution, _ bool, _ time.Time, actionFn func(wfContext execution.Context, mutableState execution.MutableState) error) error { - return actionFn(nil, ms) - }, - } +func TestHistoryEngineStartStop(t *testing.T) { + eft := testdata.NewEngineForTest(t, NewEngineWithShardContext) + defer eft.Cleanup() - err := historyEngine.RecordChildExecutionCompleted(context.Background(), tc.request) - if tc.wantErr { - tc.assertErr(t, err) - } else { - assert.NoError(t, err) - } - }) - } + eft.Engine.Start() + eft.Engine.Stop() } diff --git a/service/history/engine/testdata/engine_for_tests.go b/service/history/engine/testdata/engine_for_tests.go new file mode 100644 index 00000000000..5bd1a1f67c0 --- /dev/null +++ b/service/history/engine/testdata/engine_for_tests.go @@ -0,0 +1,186 @@ +// Copyright (c) 2017-2020 Uber Technologies Inc. +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +// THE SOFTWARE. + +package testdata + +import ( + "testing" + + "github.com/golang/mock/gomock" + "go.uber.org/cadence/.gen/go/cadence/workflowserviceclient" + "go.uber.org/cadence/.gen/go/cadence/workflowservicetest" + + "github.com/uber/cadence/client/matching" + "github.com/uber/cadence/common/clock" + "github.com/uber/cadence/common/dynamicconfig" + "github.com/uber/cadence/common/persistence" + "github.com/uber/cadence/common/quotas" + "github.com/uber/cadence/service/history/config" + "github.com/uber/cadence/service/history/constants" + "github.com/uber/cadence/service/history/engine" + "github.com/uber/cadence/service/history/events" + "github.com/uber/cadence/service/history/failover" + "github.com/uber/cadence/service/history/queue" + "github.com/uber/cadence/service/history/replication" + "github.com/uber/cadence/service/history/shard" + "github.com/uber/cadence/service/history/task" + "github.com/uber/cadence/service/history/workflowcache" +) + +type EngineForTest struct { + Engine engine.Engine + Cleanup func() + // Add mocks or other fields here +} + +type NewEngineFn func( + shard shard.Context, + visibilityMgr persistence.VisibilityManager, + matching matching.Client, + publicClient workflowserviceclient.Interface, + historyEventNotifier events.Notifier, + config *config.Config, + crossClusterTaskFetchers task.Fetchers, + replicationTaskFetchers replication.TaskFetchers, + rawMatchingClient matching.Client, + queueTaskProcessor task.Processor, + failoverCoordinator failover.Coordinator, + wfIDCache workflowcache.WFCache, + ratelimitInternalPerWorkflowID dynamicconfig.BoolPropertyFnWithDomainFilter, + queueProcessorFactory queue.ProcessorFactory, +) engine.Engine + +func NewEngineForTest(t *testing.T, newEngineFn NewEngineFn) *EngineForTest { + t.Helper() + controller := gomock.NewController(t) + historyCfg := config.NewForTest() + shardCtx := shard.NewTestContext( + t, + controller, + &persistence.ShardInfo{ + RangeID: 1, + TransferAckLevel: 0, + }, + historyCfg, + ) + + domainCache := shardCtx.Resource.DomainCache + domainCache.EXPECT().GetDomainByID(constants.TestDomainID).Return(constants.TestLocalDomainEntry, nil).AnyTimes() + domainCache.EXPECT().GetDomainName(constants.TestDomainID).Return(constants.TestDomainName, nil).AnyTimes() + domainCache.EXPECT().GetDomain(constants.TestDomainName).Return(constants.TestLocalDomainEntry, nil).AnyTimes() + domainCache.EXPECT().GetDomainID(constants.TestDomainName).Return(constants.TestDomainID, nil).AnyTimes() + domainCache.EXPECT().RegisterDomainChangeCallback(gomock.Any(), gomock.Any(), gomock.Any(), gomock.Any()).AnyTimes() + domainCache.EXPECT().UnregisterDomainChangeCallback(gomock.Any()).Times(1) + + membershipResolver := shardCtx.Resource.MembershipResolver + membershipResolver.EXPECT().MemberCount(gomock.Any()).Return(1, nil).AnyTimes() + + eventsCache := events.NewCache( + shardCtx.GetShardID(), + shardCtx.GetHistoryManager(), + historyCfg, + shardCtx.GetLogger(), + shardCtx.GetMetricsClient(), + domainCache, + ) + shardCtx.SetEventsCache(eventsCache) + + historyEventNotifier := events.NewNotifier( + clock.NewRealTimeSource(), + shardCtx.Resource.MetricsClient, + func(workflowID string) int { + return len(workflowID) + }, + ) + + visibilityMgr := persistence.NewMockVisibilityManager(controller) + mockWFServiceClient := workflowservicetest.NewMockClient(controller) + xClusterTaskFetcher := task.NewMockFetcher(controller) + + replicatonTaskFetchers := replication.NewMockTaskFetchers(controller) + replicationTaskFetcher := replication.NewMockTaskFetcher(controller) + // TODO: this should probably return another cluster name, not current + replicationTaskFetcher.EXPECT().GetSourceCluster().Return(constants.TestClusterMetadata.GetCurrentClusterName()).AnyTimes() + replicationTaskFetcher.EXPECT().GetRateLimiter().Return(quotas.NewDynamicRateLimiter(func() float64 { return 100 })).AnyTimes() + replicationTaskFetcher.EXPECT().GetRequestChan().Return(nil).AnyTimes() + replicatonTaskFetchers.EXPECT().GetFetchers().Return([]replication.TaskFetcher{replicationTaskFetcher}).AnyTimes() + + queueTaskProcessor := task.NewMockProcessor(controller) + queueTaskProcessor.EXPECT().StopShardProcessor(gomock.Any()).Return().Times(1) + + failoverCoordinator := failover.NewMockCoordinator(controller) + wfIDCache := workflowcache.NewMockWFCache(controller) + ratelimitInternalPerWorkflowID := dynamicconfig.GetBoolPropertyFnFilteredByDomain(false) + + queueProcessorFactory := queue.NewMockProcessorFactory(controller) + timerQProcessor := queue.NewMockProcessor(controller) + timerQProcessor.EXPECT().Start().Return().Times(1) + timerQProcessor.EXPECT().NotifyNewTask(gomock.Any(), gomock.Any()).Return().AnyTimes() + timerQProcessor.EXPECT().Stop().Return().Times(1) + queueProcessorFactory.EXPECT(). + NewTimerQueueProcessor(gomock.Any(), gomock.Any(), gomock.Any(), gomock.Any(), gomock.Any(), gomock.Any()). + Return(timerQProcessor). + Times(1) + + transferQProcessor := queue.NewMockProcessor(controller) + transferQProcessor.EXPECT().Start().Return().Times(1) + transferQProcessor.EXPECT().NotifyNewTask(gomock.Any(), gomock.Any()).Return().AnyTimes() + transferQProcessor.EXPECT().Stop().Return().Times(1) + queueProcessorFactory.EXPECT(). + NewTransferQueueProcessor(gomock.Any(), gomock.Any(), gomock.Any(), gomock.Any(), gomock.Any(), gomock.Any(), gomock.Any(), gomock.Any(), gomock.Any()). + Return(transferQProcessor). + Times(1) + + xClusterQProcessor := queue.NewMockProcessor(controller) + xClusterQProcessor.EXPECT().Start().Return().Times(1) + xClusterQProcessor.EXPECT().NotifyNewTask(gomock.Any(), gomock.Any()).Return().AnyTimes() + xClusterQProcessor.EXPECT().Stop().Return().Times(1) + queueProcessorFactory.EXPECT(). + NewCrossClusterQueueProcessor(gomock.Any(), gomock.Any(), gomock.Any(), gomock.Any()). + Return(xClusterQProcessor). + Times(1) + + engine := newEngineFn( + shardCtx, + visibilityMgr, + shardCtx.Resource.MatchingClient, + mockWFServiceClient, + historyEventNotifier, + historyCfg, + task.Fetchers{xClusterTaskFetcher}, + replicatonTaskFetchers, + shardCtx.Resource.MatchingClient, + queueTaskProcessor, + failoverCoordinator, + wfIDCache, + ratelimitInternalPerWorkflowID, + queueProcessorFactory, + ) + + shardCtx.SetEngine(engine) + + historyEventNotifier.Start() + return &EngineForTest{ + Engine: engine, + Cleanup: func() { + historyEventNotifier.Stop() + }, + } +} diff --git a/service/history/handler/handler.go b/service/history/handler/handler.go index 644630a18ba..64134be5c8e 100644 --- a/service/history/handler/handler.go +++ b/service/history/handler/handler.go @@ -51,6 +51,7 @@ import ( "github.com/uber/cadence/service/history/events" "github.com/uber/cadence/service/history/failover" "github.com/uber/cadence/service/history/lookup" + "github.com/uber/cadence/service/history/queue" "github.com/uber/cadence/service/history/replication" "github.com/uber/cadence/service/history/resource" "github.com/uber/cadence/service/history/shard" @@ -80,6 +81,7 @@ type ( failoverCoordinator failover.Coordinator workflowIDCache workflowcache.WFCache ratelimitInternalPerWorkflowID dynamicconfig.BoolPropertyFnWithDomainFilter + queueProcessorFactory queue.ProcessorFactory } ) @@ -228,6 +230,7 @@ func (h *handlerImpl) CreateEngine( h.failoverCoordinator, h.workflowIDCache, h.ratelimitInternalPerWorkflowID, + queue.NewProcessorFactory(), ) } diff --git a/service/history/queue/factory.go b/service/history/queue/factory.go new file mode 100644 index 00000000000..f911d4a45af --- /dev/null +++ b/service/history/queue/factory.go @@ -0,0 +1,128 @@ +// Copyright (c) 2017-2020 Uber Technologies Inc. + +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: + +// The above copyright notice and this permission notice shall be included in all +// copies or substantial portions of the Software. + +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +// SOFTWARE. + +package queue + +import ( + "github.com/uber/cadence/common/dynamicconfig" + "github.com/uber/cadence/common/reconciliation/invariant" + "github.com/uber/cadence/service/history/engine" + "github.com/uber/cadence/service/history/execution" + "github.com/uber/cadence/service/history/reset" + "github.com/uber/cadence/service/history/shard" + "github.com/uber/cadence/service/history/task" + "github.com/uber/cadence/service/history/workflowcache" + "github.com/uber/cadence/service/worker/archiver" +) + +//go:generate mockgen -package $GOPACKAGE -source $GOFILE -destination factory_mock.go -self_package github.com/uber/cadence/service/history/queue + +type ProcessorFactory interface { + NewTransferQueueProcessor( + shard shard.Context, + historyEngine engine.Engine, + taskProcessor task.Processor, + executionCache *execution.Cache, + workflowResetter reset.WorkflowResetter, + archivalClient archiver.Client, + executionCheck invariant.Invariant, + wfIDCache workflowcache.WFCache, + ratelimitInternalPerWorkflowID dynamicconfig.BoolPropertyFnWithDomainFilter, + ) Processor + + NewTimerQueueProcessor( + shard shard.Context, + historyEngine engine.Engine, + taskProcessor task.Processor, + executionCache *execution.Cache, + archivalClient archiver.Client, + executionCheck invariant.Invariant, + ) Processor + + NewCrossClusterQueueProcessor( + shard shard.Context, + historyEngine engine.Engine, + executionCache *execution.Cache, + taskProcessor task.Processor, + ) Processor +} + +func NewProcessorFactory() ProcessorFactory { + return &factoryImpl{} +} + +type factoryImpl struct { +} + +func (f *factoryImpl) NewTransferQueueProcessor( + shard shard.Context, + historyEngine engine.Engine, + taskProcessor task.Processor, + executionCache *execution.Cache, + workflowResetter reset.WorkflowResetter, + archivalClient archiver.Client, + executionCheck invariant.Invariant, + wfIDCache workflowcache.WFCache, + ratelimitInternalPerWorkflowID dynamicconfig.BoolPropertyFnWithDomainFilter, +) Processor { + return NewTransferQueueProcessor( + shard, + historyEngine, + taskProcessor, + executionCache, + workflowResetter, + archivalClient, + executionCheck, + wfIDCache, + ratelimitInternalPerWorkflowID, + ) +} + +func (f *factoryImpl) NewTimerQueueProcessor( + shard shard.Context, + historyEngine engine.Engine, + taskProcessor task.Processor, + executionCache *execution.Cache, + archivalClient archiver.Client, + executionCheck invariant.Invariant, +) Processor { + return NewTimerQueueProcessor( + shard, + historyEngine, + taskProcessor, + executionCache, + archivalClient, + executionCheck, + ) +} + +func (f *factoryImpl) NewCrossClusterQueueProcessor( + shard shard.Context, + historyEngine engine.Engine, + executionCache *execution.Cache, + taskProcessor task.Processor, +) Processor { + return NewCrossClusterQueueProcessor( + shard, + historyEngine, + executionCache, + taskProcessor, + ) +} diff --git a/service/history/queue/factory_mock.go b/service/history/queue/factory_mock.go new file mode 100644 index 00000000000..ff321e2089a --- /dev/null +++ b/service/history/queue/factory_mock.go @@ -0,0 +1,108 @@ +// The MIT License (MIT) + +// Copyright (c) 2017-2020 Uber Technologies Inc. + +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in all +// copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +// SOFTWARE. + +// Code generated by MockGen. DO NOT EDIT. +// Source: factory.go + +// Package queue is a generated GoMock package. +package queue + +import ( + reflect "reflect" + + gomock "github.com/golang/mock/gomock" + + dynamicconfig "github.com/uber/cadence/common/dynamicconfig" + invariant "github.com/uber/cadence/common/reconciliation/invariant" + engine "github.com/uber/cadence/service/history/engine" + execution "github.com/uber/cadence/service/history/execution" + reset "github.com/uber/cadence/service/history/reset" + shard "github.com/uber/cadence/service/history/shard" + task "github.com/uber/cadence/service/history/task" + workflowcache "github.com/uber/cadence/service/history/workflowcache" + archiver "github.com/uber/cadence/service/worker/archiver" +) + +// MockProcessorFactory is a mock of ProcessorFactory interface. +type MockProcessorFactory struct { + ctrl *gomock.Controller + recorder *MockProcessorFactoryMockRecorder +} + +// MockProcessorFactoryMockRecorder is the mock recorder for MockProcessorFactory. +type MockProcessorFactoryMockRecorder struct { + mock *MockProcessorFactory +} + +// NewMockProcessorFactory creates a new mock instance. +func NewMockProcessorFactory(ctrl *gomock.Controller) *MockProcessorFactory { + mock := &MockProcessorFactory{ctrl: ctrl} + mock.recorder = &MockProcessorFactoryMockRecorder{mock} + return mock +} + +// EXPECT returns an object that allows the caller to indicate expected use. +func (m *MockProcessorFactory) EXPECT() *MockProcessorFactoryMockRecorder { + return m.recorder +} + +// NewCrossClusterQueueProcessor mocks base method. +func (m *MockProcessorFactory) NewCrossClusterQueueProcessor(shard shard.Context, historyEngine engine.Engine, executionCache *execution.Cache, taskProcessor task.Processor) Processor { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "NewCrossClusterQueueProcessor", shard, historyEngine, executionCache, taskProcessor) + ret0, _ := ret[0].(Processor) + return ret0 +} + +// NewCrossClusterQueueProcessor indicates an expected call of NewCrossClusterQueueProcessor. +func (mr *MockProcessorFactoryMockRecorder) NewCrossClusterQueueProcessor(shard, historyEngine, executionCache, taskProcessor interface{}) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "NewCrossClusterQueueProcessor", reflect.TypeOf((*MockProcessorFactory)(nil).NewCrossClusterQueueProcessor), shard, historyEngine, executionCache, taskProcessor) +} + +// NewTimerQueueProcessor mocks base method. +func (m *MockProcessorFactory) NewTimerQueueProcessor(shard shard.Context, historyEngine engine.Engine, taskProcessor task.Processor, executionCache *execution.Cache, archivalClient archiver.Client, executionCheck invariant.Invariant) Processor { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "NewTimerQueueProcessor", shard, historyEngine, taskProcessor, executionCache, archivalClient, executionCheck) + ret0, _ := ret[0].(Processor) + return ret0 +} + +// NewTimerQueueProcessor indicates an expected call of NewTimerQueueProcessor. +func (mr *MockProcessorFactoryMockRecorder) NewTimerQueueProcessor(shard, historyEngine, taskProcessor, executionCache, archivalClient, executionCheck interface{}) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "NewTimerQueueProcessor", reflect.TypeOf((*MockProcessorFactory)(nil).NewTimerQueueProcessor), shard, historyEngine, taskProcessor, executionCache, archivalClient, executionCheck) +} + +// NewTransferQueueProcessor mocks base method. +func (m *MockProcessorFactory) NewTransferQueueProcessor(shard shard.Context, historyEngine engine.Engine, taskProcessor task.Processor, executionCache *execution.Cache, workflowResetter reset.WorkflowResetter, archivalClient archiver.Client, executionCheck invariant.Invariant, wfIDCache workflowcache.WFCache, ratelimitInternalPerWorkflowID dynamicconfig.BoolPropertyFnWithDomainFilter) Processor { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "NewTransferQueueProcessor", shard, historyEngine, taskProcessor, executionCache, workflowResetter, archivalClient, executionCheck, wfIDCache, ratelimitInternalPerWorkflowID) + ret0, _ := ret[0].(Processor) + return ret0 +} + +// NewTransferQueueProcessor indicates an expected call of NewTransferQueueProcessor. +func (mr *MockProcessorFactoryMockRecorder) NewTransferQueueProcessor(shard, historyEngine, taskProcessor, executionCache, workflowResetter, archivalClient, executionCheck, wfIDCache, ratelimitInternalPerWorkflowID interface{}) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "NewTransferQueueProcessor", reflect.TypeOf((*MockProcessorFactory)(nil).NewTransferQueueProcessor), shard, historyEngine, taskProcessor, executionCache, workflowResetter, archivalClient, executionCheck, wfIDCache, ratelimitInternalPerWorkflowID) +} diff --git a/service/history/replication/task_fetcher.go b/service/history/replication/task_fetcher.go index cc76e7bd3ac..ce479d99f09 100644 --- a/service/history/replication/task_fetcher.go +++ b/service/history/replication/task_fetcher.go @@ -37,6 +37,8 @@ import ( "github.com/uber/cadence/service/history/config" ) +//go:generate mockgen -package $GOPACKAGE -source $GOFILE -destination task_fetcher_mock.go -self_package github.com/uber/cadence/service/history/replication + // TODO: reuse the interface and implementation defined in history/task package const ( diff --git a/service/history/replication/task_fetcher_mock.go b/service/history/replication/task_fetcher_mock.go new file mode 100644 index 00000000000..f429051e451 --- /dev/null +++ b/service/history/replication/task_fetcher_mock.go @@ -0,0 +1,185 @@ +// The MIT License (MIT) + +// Copyright (c) 2017-2020 Uber Technologies Inc. + +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in all +// copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +// SOFTWARE. + +// Code generated by MockGen. DO NOT EDIT. +// Source: task_fetcher.go + +// Package replication is a generated GoMock package. +package replication + +import ( + reflect "reflect" + + gomock "github.com/golang/mock/gomock" + + quotas "github.com/uber/cadence/common/quotas" +) + +// MockTaskFetcher is a mock of TaskFetcher interface. +type MockTaskFetcher struct { + ctrl *gomock.Controller + recorder *MockTaskFetcherMockRecorder +} + +// MockTaskFetcherMockRecorder is the mock recorder for MockTaskFetcher. +type MockTaskFetcherMockRecorder struct { + mock *MockTaskFetcher +} + +// NewMockTaskFetcher creates a new mock instance. +func NewMockTaskFetcher(ctrl *gomock.Controller) *MockTaskFetcher { + mock := &MockTaskFetcher{ctrl: ctrl} + mock.recorder = &MockTaskFetcherMockRecorder{mock} + return mock +} + +// EXPECT returns an object that allows the caller to indicate expected use. +func (m *MockTaskFetcher) EXPECT() *MockTaskFetcherMockRecorder { + return m.recorder +} + +// GetRateLimiter mocks base method. +func (m *MockTaskFetcher) GetRateLimiter() *quotas.DynamicRateLimiter { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "GetRateLimiter") + ret0, _ := ret[0].(*quotas.DynamicRateLimiter) + return ret0 +} + +// GetRateLimiter indicates an expected call of GetRateLimiter. +func (mr *MockTaskFetcherMockRecorder) GetRateLimiter() *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "GetRateLimiter", reflect.TypeOf((*MockTaskFetcher)(nil).GetRateLimiter)) +} + +// GetRequestChan mocks base method. +func (m *MockTaskFetcher) GetRequestChan() chan<- *request { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "GetRequestChan") + ret0, _ := ret[0].(chan<- *request) + return ret0 +} + +// GetRequestChan indicates an expected call of GetRequestChan. +func (mr *MockTaskFetcherMockRecorder) GetRequestChan() *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "GetRequestChan", reflect.TypeOf((*MockTaskFetcher)(nil).GetRequestChan)) +} + +// GetSourceCluster mocks base method. +func (m *MockTaskFetcher) GetSourceCluster() string { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "GetSourceCluster") + ret0, _ := ret[0].(string) + return ret0 +} + +// GetSourceCluster indicates an expected call of GetSourceCluster. +func (mr *MockTaskFetcherMockRecorder) GetSourceCluster() *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "GetSourceCluster", reflect.TypeOf((*MockTaskFetcher)(nil).GetSourceCluster)) +} + +// Start mocks base method. +func (m *MockTaskFetcher) Start() { + m.ctrl.T.Helper() + m.ctrl.Call(m, "Start") +} + +// Start indicates an expected call of Start. +func (mr *MockTaskFetcherMockRecorder) Start() *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Start", reflect.TypeOf((*MockTaskFetcher)(nil).Start)) +} + +// Stop mocks base method. +func (m *MockTaskFetcher) Stop() { + m.ctrl.T.Helper() + m.ctrl.Call(m, "Stop") +} + +// Stop indicates an expected call of Stop. +func (mr *MockTaskFetcherMockRecorder) Stop() *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Stop", reflect.TypeOf((*MockTaskFetcher)(nil).Stop)) +} + +// MockTaskFetchers is a mock of TaskFetchers interface. +type MockTaskFetchers struct { + ctrl *gomock.Controller + recorder *MockTaskFetchersMockRecorder +} + +// MockTaskFetchersMockRecorder is the mock recorder for MockTaskFetchers. +type MockTaskFetchersMockRecorder struct { + mock *MockTaskFetchers +} + +// NewMockTaskFetchers creates a new mock instance. +func NewMockTaskFetchers(ctrl *gomock.Controller) *MockTaskFetchers { + mock := &MockTaskFetchers{ctrl: ctrl} + mock.recorder = &MockTaskFetchersMockRecorder{mock} + return mock +} + +// EXPECT returns an object that allows the caller to indicate expected use. +func (m *MockTaskFetchers) EXPECT() *MockTaskFetchersMockRecorder { + return m.recorder +} + +// GetFetchers mocks base method. +func (m *MockTaskFetchers) GetFetchers() []TaskFetcher { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "GetFetchers") + ret0, _ := ret[0].([]TaskFetcher) + return ret0 +} + +// GetFetchers indicates an expected call of GetFetchers. +func (mr *MockTaskFetchersMockRecorder) GetFetchers() *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "GetFetchers", reflect.TypeOf((*MockTaskFetchers)(nil).GetFetchers)) +} + +// Start mocks base method. +func (m *MockTaskFetchers) Start() { + m.ctrl.T.Helper() + m.ctrl.Call(m, "Start") +} + +// Start indicates an expected call of Start. +func (mr *MockTaskFetchersMockRecorder) Start() *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Start", reflect.TypeOf((*MockTaskFetchers)(nil).Start)) +} + +// Stop mocks base method. +func (m *MockTaskFetchers) Stop() { + m.ctrl.T.Helper() + m.ctrl.Call(m, "Stop") +} + +// Stop indicates an expected call of Stop. +func (mr *MockTaskFetchersMockRecorder) Stop() *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Stop", reflect.TypeOf((*MockTaskFetchers)(nil).Stop)) +} From 4188b103402c19030c66d6ab34dfce1dc1d2c437 Mon Sep 17 00:00:00 2001 From: taylan isikdemir Date: Tue, 7 May 2024 17:30:32 -0700 Subject: [PATCH 2/4] rename to make diff smaller --- .../engineimpl/history_engine_start_test.go | 36 + .../engineimpl/history_engine_suite_test.go | 5466 ----------------- .../engine/engineimpl/history_engine_test.go | 5442 +++++++++++++++- 3 files changed, 5472 insertions(+), 5472 deletions(-) create mode 100644 service/history/engine/engineimpl/history_engine_start_test.go delete mode 100644 service/history/engine/engineimpl/history_engine_suite_test.go diff --git a/service/history/engine/engineimpl/history_engine_start_test.go b/service/history/engine/engineimpl/history_engine_start_test.go new file mode 100644 index 00000000000..3e26cd68234 --- /dev/null +++ b/service/history/engine/engineimpl/history_engine_start_test.go @@ -0,0 +1,36 @@ +// Copyright (c) 2017-2021 Uber Technologies Inc. +// Portions of the Software are attributed to Copyright (c) 2021 Temporal Technologies Inc. +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +// THE SOFTWARE. + +package engineimpl + +import ( + "testing" + + "github.com/uber/cadence/service/history/engine/testdata" +) + +func TestHistoryEngineStartStop(t *testing.T) { + eft := testdata.NewEngineForTest(t, NewEngineWithShardContext) + defer eft.Cleanup() + + eft.Engine.Start() + eft.Engine.Stop() +} diff --git a/service/history/engine/engineimpl/history_engine_suite_test.go b/service/history/engine/engineimpl/history_engine_suite_test.go deleted file mode 100644 index aed2550367f..00000000000 --- a/service/history/engine/engineimpl/history_engine_suite_test.go +++ /dev/null @@ -1,5466 +0,0 @@ -// Copyright (c) 2017-2021 Uber Technologies Inc. -// Portions of the Software are attributed to Copyright (c) 2021 Temporal Technologies Inc. -// -// Permission is hereby granted, free of charge, to any person obtaining a copy -// of this software and associated documentation files (the "Software"), to deal -// in the Software without restriction, including without limitation the rights -// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -// copies of the Software, and to permit persons to whom the Software is -// furnished to do so, subject to the following conditions: -// -// The above copyright notice and this permission notice shall be included in -// all copies or substantial portions of the Software. -// -// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN -// THE SOFTWARE. - -package engineimpl - -import ( - "context" - "encoding/json" - "errors" - "sync" - "testing" - "time" - - "github.com/golang/mock/gomock" - "github.com/pborman/uuid" - "github.com/stretchr/testify/assert" - "github.com/stretchr/testify/mock" - "github.com/stretchr/testify/require" - "github.com/stretchr/testify/suite" - "github.com/uber-go/tally" - "go.uber.org/yarpc/api/encoding" - "go.uber.org/yarpc/api/transport" - - hclient "github.com/uber/cadence/client/history" - "github.com/uber/cadence/client/matching" - "github.com/uber/cadence/common" - "github.com/uber/cadence/common/cache" - cc "github.com/uber/cadence/common/client" - "github.com/uber/cadence/common/clock" - "github.com/uber/cadence/common/cluster" - "github.com/uber/cadence/common/dynamicconfig" - "github.com/uber/cadence/common/log/testlogger" - "github.com/uber/cadence/common/metrics" - "github.com/uber/cadence/common/mocks" - "github.com/uber/cadence/common/persistence" - "github.com/uber/cadence/common/types" - "github.com/uber/cadence/common/types/mapper/thrift" - "github.com/uber/cadence/service/history/config" - "github.com/uber/cadence/service/history/constants" - "github.com/uber/cadence/service/history/decision" - "github.com/uber/cadence/service/history/events" - "github.com/uber/cadence/service/history/execution" - "github.com/uber/cadence/service/history/ndc" - "github.com/uber/cadence/service/history/query" - "github.com/uber/cadence/service/history/queue" - "github.com/uber/cadence/service/history/reset" - "github.com/uber/cadence/service/history/shard" - test "github.com/uber/cadence/service/history/testing" - "github.com/uber/cadence/service/history/workflow" -) - -type ( - engineSuite struct { - suite.Suite - *require.Assertions - - controller *gomock.Controller - mockShard *shard.TestContext - mockTxProcessor *queue.MockProcessor - mockTimerProcessor *queue.MockProcessor - mockDomainCache *cache.MockDomainCache - mockHistoryClient *hclient.MockClient - mockMatchingClient *matching.MockClient - mockEventsReapplier *ndc.MockEventsReapplier - mockWorkflowResetter *reset.MockWorkflowResetter - - mockHistoryEngine *historyEngineImpl - mockExecutionMgr *mocks.ExecutionManager - mockHistoryV2Mgr *mocks.HistoryV2Manager - mockShardManager *mocks.ShardManager - - eventsCache events.Cache - config *config.Config - } -) - -func TestEngineSuite(t *testing.T) { - s := new(engineSuite) - suite.Run(t, s) -} - -func (s *engineSuite) SetupSuite() { - s.config = config.NewForTest() -} - -func (s *engineSuite) TearDownSuite() { -} - -func (s *engineSuite) SetupTest() { - s.Assertions = require.New(s.T()) - - s.controller = gomock.NewController(s.T()) - s.mockTxProcessor = queue.NewMockProcessor(s.controller) - s.mockTimerProcessor = queue.NewMockProcessor(s.controller) - s.mockEventsReapplier = ndc.NewMockEventsReapplier(s.controller) - s.mockWorkflowResetter = reset.NewMockWorkflowResetter(s.controller) - s.mockTxProcessor.EXPECT().NotifyNewTask(gomock.Any(), gomock.Any()).AnyTimes() - s.mockTimerProcessor.EXPECT().NotifyNewTask(gomock.Any(), gomock.Any()).AnyTimes() - - s.mockShard = shard.NewTestContext( - s.T(), - s.controller, - &persistence.ShardInfo{ - RangeID: 1, - TransferAckLevel: 0, - }, - s.config, - ) - s.eventsCache = events.NewCache( - s.mockShard.GetShardID(), - s.mockShard.GetHistoryManager(), - s.config, - s.mockShard.GetLogger(), - s.mockShard.GetMetricsClient(), - s.mockDomainCache, - ) - s.mockShard.SetEventsCache(s.eventsCache) - - s.mockMatchingClient = s.mockShard.Resource.MatchingClient - s.mockHistoryClient = s.mockShard.Resource.HistoryClient - s.mockExecutionMgr = s.mockShard.Resource.ExecutionMgr - s.mockHistoryV2Mgr = s.mockShard.Resource.HistoryMgr - s.mockShardManager = s.mockShard.Resource.ShardMgr - s.mockDomainCache = s.mockShard.Resource.DomainCache - s.mockDomainCache.EXPECT().GetDomainByID(constants.TestDomainID).Return(constants.TestLocalDomainEntry, nil).AnyTimes() - s.mockDomainCache.EXPECT().GetDomainName(constants.TestDomainID).Return(constants.TestDomainName, nil).AnyTimes() - s.mockDomainCache.EXPECT().GetDomain(constants.TestDomainName).Return(constants.TestLocalDomainEntry, nil).AnyTimes() - s.mockDomainCache.EXPECT().GetDomainID(constants.TestDomainName).Return(constants.TestDomainID, nil).AnyTimes() - - historyEventNotifier := events.NewNotifier( - clock.NewRealTimeSource(), - s.mockShard.Resource.MetricsClient, - func(workflowID string) int { - return len(workflowID) - }, - ) - - h := &historyEngineImpl{ - currentClusterName: s.mockShard.GetClusterMetadata().GetCurrentClusterName(), - shard: s.mockShard, - timeSource: s.mockShard.GetTimeSource(), - clusterMetadata: s.mockShard.Resource.ClusterMetadata, - executionManager: s.mockExecutionMgr, - historyV2Mgr: s.mockHistoryV2Mgr, - executionCache: execution.NewCache(s.mockShard), - logger: s.mockShard.GetLogger(), - metricsClient: s.mockShard.GetMetricsClient(), - tokenSerializer: common.NewJSONTaskTokenSerializer(), - historyEventNotifier: historyEventNotifier, - config: config.NewForTest(), - txProcessor: s.mockTxProcessor, - timerProcessor: s.mockTimerProcessor, - clientChecker: cc.NewVersionChecker(), - eventsReapplier: s.mockEventsReapplier, - workflowResetter: s.mockWorkflowResetter, - } - s.mockShard.SetEngine(h) - h.decisionHandler = decision.NewHandler(s.mockShard, h.executionCache, h.tokenSerializer) - - h.historyEventNotifier.Start() - - s.mockHistoryEngine = h -} - -func (s *engineSuite) TearDownTest() { - s.controller.Finish() - s.mockShard.Finish(s.T()) - s.mockHistoryEngine.historyEventNotifier.Stop() -} - -func (s *engineSuite) TestGetMutableStateSync() { - ctx := context.Background() - - workflowExecution := types.WorkflowExecution{ - WorkflowID: "test-get-workflow-execution-event-id", - RunID: constants.TestRunID, - } - tasklist := "testTaskList" - identity := "testIdentity" - - msBuilder := execution.NewMutableStateBuilderWithEventV2( - s.mockHistoryEngine.shard, - testlogger.New(s.Suite.T()), - workflowExecution.GetRunID(), - constants.TestLocalDomainEntry, - ) - test.AddWorkflowExecutionStartedEvent(msBuilder, workflowExecution, "wType", tasklist, []byte("input"), 100, 200, identity) - di := test.AddDecisionTaskScheduledEvent(msBuilder) - test.AddDecisionTaskStartedEvent(msBuilder, di.ScheduleID, tasklist, identity) - ms := execution.CreatePersistenceMutableState(msBuilder) - gweResponse := &persistence.GetWorkflowExecutionResponse{State: ms} - // right now the next event ID is 4 - s.mockExecutionMgr.On("GetWorkflowExecution", mock.Anything, mock.Anything).Return(gweResponse, nil).Once() - - // test get the next event ID instantly - response, err := s.mockHistoryEngine.GetMutableState(ctx, &types.GetMutableStateRequest{ - DomainUUID: constants.TestDomainID, - Execution: &workflowExecution, - }) - s.Nil(err) - s.Equal(int64(4), response.GetNextEventID()) -} - -func (s *engineSuite) TestGetMutableState_IntestRunID() { - ctx := context.Background() - - execution := types.WorkflowExecution{ - WorkflowID: "test-get-workflow-execution-event-id", - RunID: "run-id-not-valid-uuid", - } - - _, err := s.mockHistoryEngine.GetMutableState(ctx, &types.GetMutableStateRequest{ - DomainUUID: constants.TestDomainID, - Execution: &execution, - }) - s.Equal(constants.ErrRunIDNotValid, err) -} - -func (s *engineSuite) TestGetMutableState_EmptyRunID() { - ctx := context.Background() - - execution := types.WorkflowExecution{ - WorkflowID: "test-get-workflow-execution-event-id", - } - - s.mockExecutionMgr.On("GetCurrentExecution", mock.Anything, mock.Anything).Return(nil, &types.EntityNotExistsError{}).Once() - - _, err := s.mockHistoryEngine.GetMutableState(ctx, &types.GetMutableStateRequest{ - DomainUUID: constants.TestDomainID, - Execution: &execution, - }) - s.Equal(&types.EntityNotExistsError{}, err) -} - -func (s *engineSuite) TestGetMutableStateLongPoll() { - ctx := context.Background() - - workflowExecution := types.WorkflowExecution{ - WorkflowID: "test-get-workflow-execution-event-id", - RunID: constants.TestRunID, - } - tasklist := "testTaskList" - identity := "testIdentity" - - msBuilder := execution.NewMutableStateBuilderWithEventV2( - s.mockHistoryEngine.shard, - testlogger.New(s.Suite.T()), - workflowExecution.GetRunID(), - constants.TestLocalDomainEntry, - ) - test.AddWorkflowExecutionStartedEvent(msBuilder, workflowExecution, "wType", tasklist, []byte("input"), 100, 200, identity) - di := test.AddDecisionTaskScheduledEvent(msBuilder) - test.AddDecisionTaskStartedEvent(msBuilder, di.ScheduleID, tasklist, identity) - ms := execution.CreatePersistenceMutableState(msBuilder) - gweResponse := &persistence.GetWorkflowExecutionResponse{State: ms} - // right now the next event ID is 4 - s.mockExecutionMgr.On("GetWorkflowExecution", mock.Anything, mock.Anything).Return(gweResponse, nil).Once() - - // test long poll on next event ID change - waitGroup := &sync.WaitGroup{} - waitGroup.Add(1) - asycWorkflowUpdate := func(delay time.Duration) { - taskToken, _ := json.Marshal(&common.TaskToken{ - WorkflowID: workflowExecution.WorkflowID, - RunID: workflowExecution.RunID, - ScheduleID: 2, - }) - s.mockHistoryV2Mgr.On("AppendHistoryNodes", mock.Anything, mock.Anything).Return(&persistence.AppendHistoryNodesResponse{}, nil).Once() - s.mockExecutionMgr.On("UpdateWorkflowExecution", mock.Anything, mock.Anything).Return(&persistence.UpdateWorkflowExecutionResponse{MutableStateUpdateSessionStats: &persistence.MutableStateUpdateSessionStats{}}, nil).Once() - - timer := time.NewTimer(delay) - - <-timer.C - _, err := s.mockHistoryEngine.RespondDecisionTaskCompleted(context.Background(), &types.HistoryRespondDecisionTaskCompletedRequest{ - DomainUUID: constants.TestDomainID, - CompleteRequest: &types.RespondDecisionTaskCompletedRequest{ - TaskToken: taskToken, - Identity: identity, - }, - }) - s.Nil(err) - waitGroup.Done() - // right now the next event ID is 5 - } - - // return immediately, since the expected next event ID appears - response, err := s.mockHistoryEngine.GetMutableState(ctx, &types.GetMutableStateRequest{ - DomainUUID: constants.TestDomainID, - Execution: &workflowExecution, - ExpectedNextEventID: 3, - }) - s.Nil(err) - s.Equal(int64(4), response.NextEventID) - - // long poll, new event happen before long poll timeout - go asycWorkflowUpdate(time.Second * 2) - start := time.Now() - pollResponse, err := s.mockHistoryEngine.PollMutableState(ctx, &types.PollMutableStateRequest{ - DomainUUID: constants.TestDomainID, - Execution: &workflowExecution, - ExpectedNextEventID: 4, - }) - s.True(time.Now().After(start.Add(time.Second * 1))) - s.Nil(err) - s.Equal(int64(5), pollResponse.GetNextEventID()) - waitGroup.Wait() -} - -func (s *engineSuite) TestGetMutableStateLongPoll_CurrentBranchChanged() { - ctx := context.Background() - - workflowExecution := types.WorkflowExecution{ - WorkflowID: "test-get-workflow-execution-event-id", - RunID: constants.TestRunID, - } - tasklist := "testTaskList" - identity := "testIdentity" - - msBuilder := execution.NewMutableStateBuilderWithEventV2( - s.mockHistoryEngine.shard, - testlogger.New(s.Suite.T()), - workflowExecution.GetRunID(), - constants.TestLocalDomainEntry, - ) - test.AddWorkflowExecutionStartedEvent(msBuilder, workflowExecution, "wType", tasklist, []byte("input"), 100, 200, identity) - di := test.AddDecisionTaskScheduledEvent(msBuilder) - test.AddDecisionTaskStartedEvent(msBuilder, di.ScheduleID, tasklist, identity) - ms := execution.CreatePersistenceMutableState(msBuilder) - gweResponse := &persistence.GetWorkflowExecutionResponse{State: ms} - // right now the next event ID is 4 - s.mockExecutionMgr.On("GetWorkflowExecution", mock.Anything, mock.Anything).Return(gweResponse, nil).Once() - - // test long poll on next event ID change - asyncBranchTokenUpdate := func(delay time.Duration) { - timer := time.NewTimer(delay) - <-timer.C - newExecution := &types.WorkflowExecution{ - WorkflowID: workflowExecution.WorkflowID, - RunID: workflowExecution.RunID, - } - s.mockHistoryEngine.historyEventNotifier.NotifyNewHistoryEvent(events.NewNotification( - "constants.TestDomainID", - newExecution, - int64(1), - int64(4), - int64(1), - []byte{1}, - persistence.WorkflowStateCreated, - persistence.WorkflowCloseStatusNone)) - } - - // return immediately, since the expected next event ID appears - response0, err := s.mockHistoryEngine.GetMutableState(ctx, &types.GetMutableStateRequest{ - DomainUUID: constants.TestDomainID, - Execution: &workflowExecution, - ExpectedNextEventID: 3, - }) - s.Nil(err) - s.Equal(int64(4), response0.GetNextEventID()) - - // long poll, new event happen before long poll timeout - go asyncBranchTokenUpdate(time.Second * 2) - start := time.Now() - response1, err := s.mockHistoryEngine.GetMutableState(ctx, &types.GetMutableStateRequest{ - DomainUUID: constants.TestDomainID, - Execution: &workflowExecution, - ExpectedNextEventID: 10, - }) - s.True(time.Now().After(start.Add(time.Second * 1))) - s.Nil(err) - s.Equal(response0.GetCurrentBranchToken(), response1.GetCurrentBranchToken()) -} - -func (s *engineSuite) TestGetMutableStateLongPollTimeout() { - ctx := context.Background() - - workflowExecution := types.WorkflowExecution{ - WorkflowID: "test-get-workflow-execution-event-id", - RunID: constants.TestRunID, - } - tasklist := "testTaskList" - identity := "testIdentity" - - msBuilder := execution.NewMutableStateBuilderWithEventV2( - s.mockHistoryEngine.shard, - testlogger.New(s.Suite.T()), - workflowExecution.GetRunID(), - constants.TestLocalDomainEntry, - ) - test.AddWorkflowExecutionStartedEvent(msBuilder, workflowExecution, "wType", tasklist, []byte("input"), 100, 200, identity) - di := test.AddDecisionTaskScheduledEvent(msBuilder) - test.AddDecisionTaskStartedEvent(msBuilder, di.ScheduleID, tasklist, identity) - ms := execution.CreatePersistenceMutableState(msBuilder) - gweResponse := &persistence.GetWorkflowExecutionResponse{State: ms} - // right now the next event ID is 4 - s.mockExecutionMgr.On("GetWorkflowExecution", mock.Anything, mock.Anything).Return(gweResponse, nil).Once() - - // long poll, no event happen after long poll timeout - response, err := s.mockHistoryEngine.GetMutableState(ctx, &types.GetMutableStateRequest{ - DomainUUID: constants.TestDomainID, - Execution: &workflowExecution, - ExpectedNextEventID: 4, - }) - s.Nil(err) - s.Equal(int64(4), response.GetNextEventID()) -} - -func (s *engineSuite) TestQueryWorkflow_RejectBasedOnNotEnabled() { - s.mockHistoryEngine.config.EnableConsistentQueryByDomain = dynamicconfig.GetBoolPropertyFnFilteredByDomain(false) - request := &types.HistoryQueryWorkflowRequest{ - DomainUUID: constants.TestDomainID, - Request: &types.QueryWorkflowRequest{ - QueryConsistencyLevel: types.QueryConsistencyLevelStrong.Ptr(), - }, - } - resp, err := s.mockHistoryEngine.QueryWorkflow(context.Background(), request) - s.Nil(resp) - s.Equal(workflow.ErrConsistentQueryNotEnabled, err) - - s.mockHistoryEngine.config.EnableConsistentQueryByDomain = dynamicconfig.GetBoolPropertyFnFilteredByDomain(true) - s.mockHistoryEngine.config.EnableConsistentQuery = dynamicconfig.GetBoolPropertyFn(false) - resp, err = s.mockHistoryEngine.QueryWorkflow(context.Background(), request) - s.Nil(resp) - s.Equal(workflow.ErrConsistentQueryNotEnabled, err) -} - -func (s *engineSuite) TestQueryWorkflow_RejectBasedOnCompleted() { - workflowExecution := types.WorkflowExecution{ - WorkflowID: "TestQueryWorkflow_RejectBasedOnCompleted", - RunID: constants.TestRunID, - } - tasklist := "testTaskList" - identity := "testIdentity" - - msBuilder := execution.NewMutableStateBuilderWithEventV2( - s.mockHistoryEngine.shard, - testlogger.New(s.Suite.T()), - workflowExecution.GetRunID(), - constants.TestLocalDomainEntry, - ) - test.AddWorkflowExecutionStartedEvent(msBuilder, workflowExecution, "wType", tasklist, []byte("input"), 100, 200, identity) - di := test.AddDecisionTaskScheduledEvent(msBuilder) - event := test.AddDecisionTaskStartedEvent(msBuilder, di.ScheduleID, tasklist, identity) - di.StartedID = event.ID - event = test.AddDecisionTaskCompletedEvent(msBuilder, di.ScheduleID, di.StartedID, nil, "some random identity") - test.AddCompleteWorkflowEvent(msBuilder, event.ID, nil) - ms := execution.CreatePersistenceMutableState(msBuilder) - gweResponse := &persistence.GetWorkflowExecutionResponse{State: ms} - s.mockExecutionMgr.On("GetWorkflowExecution", mock.Anything, mock.Anything).Return(gweResponse, nil).Once() - - request := &types.HistoryQueryWorkflowRequest{ - DomainUUID: constants.TestDomainID, - Request: &types.QueryWorkflowRequest{ - Execution: &workflowExecution, - Query: &types.WorkflowQuery{}, - QueryRejectCondition: types.QueryRejectConditionNotOpen.Ptr(), - }, - } - resp, err := s.mockHistoryEngine.QueryWorkflow(context.Background(), request) - s.NoError(err) - s.Nil(resp.GetResponse().QueryResult) - s.NotNil(resp.GetResponse().QueryRejected) - s.Equal(types.WorkflowExecutionCloseStatusCompleted.Ptr(), resp.GetResponse().GetQueryRejected().CloseStatus) -} - -func (s *engineSuite) TestQueryWorkflow_RejectBasedOnFailed() { - workflowExecution := types.WorkflowExecution{ - WorkflowID: "TestQueryWorkflow_RejectBasedOnFailed", - RunID: constants.TestRunID, - } - tasklist := "testTaskList" - identity := "testIdentity" - - msBuilder := execution.NewMutableStateBuilderWithEventV2( - s.mockHistoryEngine.shard, - testlogger.New(s.Suite.T()), - workflowExecution.GetRunID(), - constants.TestLocalDomainEntry, - ) - test.AddWorkflowExecutionStartedEvent(msBuilder, workflowExecution, "wType", tasklist, []byte("input"), 100, 200, identity) - di := test.AddDecisionTaskScheduledEvent(msBuilder) - event := test.AddDecisionTaskStartedEvent(msBuilder, di.ScheduleID, tasklist, identity) - di.StartedID = event.ID - event = test.AddDecisionTaskCompletedEvent(msBuilder, di.ScheduleID, di.StartedID, nil, "some random identity") - test.AddFailWorkflowEvent(msBuilder, event.ID, "failure reason", []byte{1, 2, 3}) - ms := execution.CreatePersistenceMutableState(msBuilder) - gweResponse := &persistence.GetWorkflowExecutionResponse{State: ms} - s.mockExecutionMgr.On("GetWorkflowExecution", mock.Anything, mock.Anything).Return(gweResponse, nil).Once() - - request := &types.HistoryQueryWorkflowRequest{ - DomainUUID: constants.TestDomainID, - Request: &types.QueryWorkflowRequest{ - Execution: &workflowExecution, - Query: &types.WorkflowQuery{}, - QueryRejectCondition: types.QueryRejectConditionNotOpen.Ptr(), - }, - } - resp, err := s.mockHistoryEngine.QueryWorkflow(context.Background(), request) - s.NoError(err) - s.Nil(resp.GetResponse().QueryResult) - s.NotNil(resp.GetResponse().QueryRejected) - s.Equal(types.WorkflowExecutionCloseStatusFailed.Ptr(), resp.GetResponse().GetQueryRejected().CloseStatus) - - request = &types.HistoryQueryWorkflowRequest{ - DomainUUID: constants.TestDomainID, - Request: &types.QueryWorkflowRequest{ - Execution: &workflowExecution, - Query: &types.WorkflowQuery{}, - QueryRejectCondition: types.QueryRejectConditionNotCompletedCleanly.Ptr(), - }, - } - resp, err = s.mockHistoryEngine.QueryWorkflow(context.Background(), request) - s.NoError(err) - s.Nil(resp.GetResponse().QueryResult) - s.NotNil(resp.GetResponse().QueryRejected) - s.Equal(types.WorkflowExecutionCloseStatusFailed.Ptr(), resp.GetResponse().GetQueryRejected().CloseStatus) -} - -func (s *engineSuite) TestQueryWorkflow_FirstDecisionNotCompleted() { - workflowExecution := types.WorkflowExecution{ - WorkflowID: "TestQueryWorkflow_FirstDecisionNotCompleted", - RunID: constants.TestRunID, - } - tasklist := "testTaskList" - identity := "testIdentity" - - msBuilder := execution.NewMutableStateBuilderWithEventV2( - s.mockHistoryEngine.shard, - testlogger.New(s.Suite.T()), - workflowExecution.GetRunID(), - constants.TestLocalDomainEntry, - ) - test.AddWorkflowExecutionStartedEvent(msBuilder, workflowExecution, "wType", tasklist, []byte("input"), 100, 200, identity) - di := test.AddDecisionTaskScheduledEvent(msBuilder) - test.AddDecisionTaskStartedEvent(msBuilder, di.ScheduleID, tasklist, identity) - ms := execution.CreatePersistenceMutableState(msBuilder) - gweResponse := &persistence.GetWorkflowExecutionResponse{State: ms} - s.mockExecutionMgr.On("GetWorkflowExecution", mock.Anything, mock.Anything).Return(gweResponse, nil).Once() - - request := &types.HistoryQueryWorkflowRequest{ - DomainUUID: constants.TestDomainID, - Request: &types.QueryWorkflowRequest{ - Execution: &workflowExecution, - Query: &types.WorkflowQuery{}, - }, - } - resp, err := s.mockHistoryEngine.QueryWorkflow(context.Background(), request) - s.Equal(workflow.ErrQueryWorkflowBeforeFirstDecision, err) - s.Nil(resp) -} - -func (s *engineSuite) TestQueryWorkflow_DirectlyThroughMatching() { - workflowExecution := types.WorkflowExecution{ - WorkflowID: "TestQueryWorkflow_DirectlyThroughMatching", - RunID: constants.TestRunID, - } - tasklist := "testTaskList" - identity := "testIdentity" - - msBuilder := execution.NewMutableStateBuilderWithEventV2( - s.mockHistoryEngine.shard, - testlogger.New(s.Suite.T()), - workflowExecution.GetRunID(), - constants.TestLocalDomainEntry, - ) - test.AddWorkflowExecutionStartedEvent(msBuilder, workflowExecution, "wType", tasklist, []byte("input"), 100, 200, identity) - di := test.AddDecisionTaskScheduledEvent(msBuilder) - startedEvent := test.AddDecisionTaskStartedEvent(msBuilder, di.ScheduleID, tasklist, identity) - test.AddDecisionTaskCompletedEvent(msBuilder, di.ScheduleID, startedEvent.ID, nil, identity) - di = test.AddDecisionTaskScheduledEvent(msBuilder) - test.AddDecisionTaskStartedEvent(msBuilder, di.ScheduleID, tasklist, identity) - - ms := execution.CreatePersistenceMutableState(msBuilder) - gweResponse := &persistence.GetWorkflowExecutionResponse{State: ms} - s.mockExecutionMgr.On("GetWorkflowExecution", mock.Anything, mock.Anything).Return(gweResponse, nil).Once() - s.mockMatchingClient.EXPECT().QueryWorkflow(gomock.Any(), gomock.Any()).Return(&types.QueryWorkflowResponse{QueryResult: []byte{1, 2, 3}}, nil) - s.mockHistoryEngine.matchingClient = s.mockMatchingClient - request := &types.HistoryQueryWorkflowRequest{ - DomainUUID: constants.TestDomainID, - Request: &types.QueryWorkflowRequest{ - Execution: &workflowExecution, - Query: &types.WorkflowQuery{}, - // since workflow is open this filter does not reject query - QueryRejectCondition: types.QueryRejectConditionNotOpen.Ptr(), - QueryConsistencyLevel: types.QueryConsistencyLevelEventual.Ptr(), - }, - } - resp, err := s.mockHistoryEngine.QueryWorkflow(context.Background(), request) - s.NoError(err) - s.NotNil(resp.GetResponse().QueryResult) - s.Nil(resp.GetResponse().QueryRejected) - s.Equal([]byte{1, 2, 3}, resp.GetResponse().GetQueryResult()) -} - -func (s *engineSuite) TestQueryWorkflow_DecisionTaskDispatch_Timeout() { - workflowExecution := types.WorkflowExecution{ - WorkflowID: "TestQueryWorkflow_DecisionTaskDispatch_Timeout", - RunID: constants.TestRunID, - } - tasklist := "testTaskList" - identity := "testIdentity" - msBuilder := execution.NewMutableStateBuilderWithEventV2( - s.mockHistoryEngine.shard, - testlogger.New(s.Suite.T()), - workflowExecution.GetRunID(), - constants.TestLocalDomainEntry, - ) - test.AddWorkflowExecutionStartedEvent(msBuilder, workflowExecution, "wType", tasklist, []byte("input"), 100, 200, identity) - di := test.AddDecisionTaskScheduledEvent(msBuilder) - startedEvent := test.AddDecisionTaskStartedEvent(msBuilder, di.ScheduleID, tasklist, identity) - test.AddDecisionTaskCompletedEvent(msBuilder, di.ScheduleID, startedEvent.ID, nil, identity) - di = test.AddDecisionTaskScheduledEvent(msBuilder) - test.AddDecisionTaskStartedEvent(msBuilder, di.ScheduleID, tasklist, identity) - - ms := execution.CreatePersistenceMutableState(msBuilder) - gweResponse := &persistence.GetWorkflowExecutionResponse{State: ms} - s.mockExecutionMgr.On("GetWorkflowExecution", mock.Anything, mock.Anything).Return(gweResponse, nil).Once() - request := &types.HistoryQueryWorkflowRequest{ - DomainUUID: constants.TestDomainID, - Request: &types.QueryWorkflowRequest{ - Execution: &workflowExecution, - Query: &types.WorkflowQuery{}, - // since workflow is open this filter does not reject query - QueryRejectCondition: types.QueryRejectConditionNotOpen.Ptr(), - QueryConsistencyLevel: types.QueryConsistencyLevelStrong.Ptr(), - }, - } - - wg := &sync.WaitGroup{} - wg.Add(1) - go func() { - ctx, cancel := context.WithTimeout(context.Background(), time.Second*2) - defer cancel() - resp, err := s.mockHistoryEngine.QueryWorkflow(ctx, request) - s.Error(err) - s.Nil(resp) - wg.Done() - }() - - <-time.After(time.Second) - builder := s.getBuilder(constants.TestDomainID, workflowExecution) - s.NotNil(builder) - qr := builder.GetQueryRegistry() - s.True(qr.HasBufferedQuery()) - s.False(qr.HasCompletedQuery()) - s.False(qr.HasUnblockedQuery()) - s.False(qr.HasFailedQuery()) - wg.Wait() - s.False(qr.HasBufferedQuery()) - s.False(qr.HasCompletedQuery()) - s.False(qr.HasUnblockedQuery()) - s.False(qr.HasFailedQuery()) -} - -func (s *engineSuite) TestQueryWorkflow_ConsistentQueryBufferFull() { - workflowExecution := types.WorkflowExecution{ - WorkflowID: "TestQueryWorkflow_ConsistentQueryBufferFull", - RunID: constants.TestRunID, - } - tasklist := "testTaskList" - identity := "testIdentity" - msBuilder := execution.NewMutableStateBuilderWithEventV2( - s.mockHistoryEngine.shard, - testlogger.New(s.Suite.T()), - workflowExecution.GetRunID(), - constants.TestLocalDomainEntry, - ) - test.AddWorkflowExecutionStartedEvent(msBuilder, workflowExecution, "wType", tasklist, []byte("input"), 100, 200, identity) - di := test.AddDecisionTaskScheduledEvent(msBuilder) - startedEvent := test.AddDecisionTaskStartedEvent(msBuilder, di.ScheduleID, tasklist, identity) - test.AddDecisionTaskCompletedEvent(msBuilder, di.ScheduleID, startedEvent.ID, nil, identity) - di = test.AddDecisionTaskScheduledEvent(msBuilder) - test.AddDecisionTaskStartedEvent(msBuilder, di.ScheduleID, tasklist, identity) - - ms := execution.CreatePersistenceMutableState(msBuilder) - gweResponse := &persistence.GetWorkflowExecutionResponse{State: ms} - s.mockExecutionMgr.On("GetWorkflowExecution", mock.Anything, mock.Anything).Return(gweResponse, nil).Once() - - // buffer query so that when types.QueryWorkflow is called buffer is already full - ctx, release, err := s.mockHistoryEngine.executionCache.GetOrCreateWorkflowExecutionForBackground(constants.TestDomainID, workflowExecution) - s.NoError(err) - loadedMS, err := ctx.LoadWorkflowExecution(context.Background()) - s.NoError(err) - qr := query.NewRegistry() - qr.BufferQuery(&types.WorkflowQuery{}) - loadedMS.SetQueryRegistry(qr) - release(nil) - - request := &types.HistoryQueryWorkflowRequest{ - DomainUUID: constants.TestDomainID, - Request: &types.QueryWorkflowRequest{ - Execution: &workflowExecution, - Query: &types.WorkflowQuery{}, - QueryConsistencyLevel: types.QueryConsistencyLevelStrong.Ptr(), - }, - } - resp, err := s.mockHistoryEngine.QueryWorkflow(context.Background(), request) - s.Nil(resp) - s.Equal(workflow.ErrConsistentQueryBufferExceeded, err) -} - -func (s *engineSuite) TestQueryWorkflow_DecisionTaskDispatch_Complete() { - workflowExecution := types.WorkflowExecution{ - WorkflowID: "TestQueryWorkflow_DecisionTaskDispatch_Complete", - RunID: constants.TestRunID, - } - tasklist := "testTaskList" - identity := "testIdentity" - msBuilder := execution.NewMutableStateBuilderWithEventV2( - s.mockHistoryEngine.shard, - testlogger.New(s.Suite.T()), - workflowExecution.GetRunID(), - constants.TestLocalDomainEntry, - ) - test.AddWorkflowExecutionStartedEvent(msBuilder, workflowExecution, "wType", tasklist, []byte("input"), 100, 200, identity) - di := test.AddDecisionTaskScheduledEvent(msBuilder) - startedEvent := test.AddDecisionTaskStartedEvent(msBuilder, di.ScheduleID, tasklist, identity) - test.AddDecisionTaskCompletedEvent(msBuilder, di.ScheduleID, startedEvent.ID, nil, identity) - di = test.AddDecisionTaskScheduledEvent(msBuilder) - test.AddDecisionTaskStartedEvent(msBuilder, di.ScheduleID, tasklist, identity) - - ms := execution.CreatePersistenceMutableState(msBuilder) - gweResponse := &persistence.GetWorkflowExecutionResponse{State: ms} - s.mockExecutionMgr.On("GetWorkflowExecution", mock.Anything, mock.Anything).Return(gweResponse, nil).Once() - - waitGroup := &sync.WaitGroup{} - waitGroup.Add(1) - asyncQueryUpdate := func(delay time.Duration, answer []byte) { - defer waitGroup.Done() - <-time.After(delay) - builder := s.getBuilder(constants.TestDomainID, workflowExecution) - s.NotNil(builder) - qr := builder.GetQueryRegistry() - buffered := qr.GetBufferedIDs() - for _, id := range buffered { - resultType := types.QueryResultTypeAnswered - completedTerminationState := &query.TerminationState{ - TerminationType: query.TerminationTypeCompleted, - QueryResult: &types.WorkflowQueryResult{ - ResultType: &resultType, - Answer: answer, - }, - } - err := qr.SetTerminationState(id, completedTerminationState) - s.NoError(err) - state, err := qr.GetTerminationState(id) - s.NoError(err) - s.Equal(query.TerminationTypeCompleted, state.TerminationType) - } - } - - request := &types.HistoryQueryWorkflowRequest{ - DomainUUID: constants.TestDomainID, - Request: &types.QueryWorkflowRequest{ - Execution: &workflowExecution, - Query: &types.WorkflowQuery{}, - QueryConsistencyLevel: types.QueryConsistencyLevelStrong.Ptr(), - }, - } - go asyncQueryUpdate(time.Second*2, []byte{1, 2, 3}) - start := time.Now() - resp, err := s.mockHistoryEngine.QueryWorkflow(context.Background(), request) - s.True(time.Now().After(start.Add(time.Second))) - s.NoError(err) - s.Equal([]byte{1, 2, 3}, resp.GetResponse().GetQueryResult()) - builder := s.getBuilder(constants.TestDomainID, workflowExecution) - s.NotNil(builder) - qr := builder.GetQueryRegistry() - s.False(qr.HasBufferedQuery()) - s.False(qr.HasCompletedQuery()) - waitGroup.Wait() -} - -func (s *engineSuite) TestQueryWorkflow_DecisionTaskDispatch_Unblocked() { - workflowExecution := types.WorkflowExecution{ - WorkflowID: "TestQueryWorkflow_DecisionTaskDispatch_Unblocked", - RunID: constants.TestRunID, - } - tasklist := "testTaskList" - identity := "testIdentity" - msBuilder := execution.NewMutableStateBuilderWithEventV2( - s.mockHistoryEngine.shard, - testlogger.New(s.Suite.T()), - workflowExecution.GetRunID(), - constants.TestLocalDomainEntry, - ) - test.AddWorkflowExecutionStartedEvent(msBuilder, workflowExecution, "wType", tasklist, []byte("input"), 100, 200, identity) - di := test.AddDecisionTaskScheduledEvent(msBuilder) - startedEvent := test.AddDecisionTaskStartedEvent(msBuilder, di.ScheduleID, tasklist, identity) - test.AddDecisionTaskCompletedEvent(msBuilder, di.ScheduleID, startedEvent.ID, nil, identity) - di = test.AddDecisionTaskScheduledEvent(msBuilder) - test.AddDecisionTaskStartedEvent(msBuilder, di.ScheduleID, tasklist, identity) - - ms := execution.CreatePersistenceMutableState(msBuilder) - gweResponse := &persistence.GetWorkflowExecutionResponse{State: ms} - s.mockExecutionMgr.On("GetWorkflowExecution", mock.Anything, mock.Anything).Return(gweResponse, nil).Once() - s.mockMatchingClient.EXPECT().QueryWorkflow(gomock.Any(), gomock.Any()).Return(&types.QueryWorkflowResponse{QueryResult: []byte{1, 2, 3}}, nil) - s.mockHistoryEngine.matchingClient = s.mockMatchingClient - waitGroup := &sync.WaitGroup{} - waitGroup.Add(1) - asyncQueryUpdate := func(delay time.Duration, answer []byte) { - defer waitGroup.Done() - <-time.After(delay) - builder := s.getBuilder(constants.TestDomainID, workflowExecution) - s.NotNil(builder) - qr := builder.GetQueryRegistry() - buffered := qr.GetBufferedIDs() - for _, id := range buffered { - s.NoError(qr.SetTerminationState(id, &query.TerminationState{TerminationType: query.TerminationTypeUnblocked})) - state, err := qr.GetTerminationState(id) - s.NoError(err) - s.Equal(query.TerminationTypeUnblocked, state.TerminationType) - } - } - - request := &types.HistoryQueryWorkflowRequest{ - DomainUUID: constants.TestDomainID, - Request: &types.QueryWorkflowRequest{ - Execution: &workflowExecution, - Query: &types.WorkflowQuery{}, - QueryConsistencyLevel: types.QueryConsistencyLevelStrong.Ptr(), - }, - } - go asyncQueryUpdate(time.Second*2, []byte{1, 2, 3}) - start := time.Now() - resp, err := s.mockHistoryEngine.QueryWorkflow(context.Background(), request) - s.True(time.Now().After(start.Add(time.Second))) - s.NoError(err) - s.Equal([]byte{1, 2, 3}, resp.GetResponse().GetQueryResult()) - builder := s.getBuilder(constants.TestDomainID, workflowExecution) - s.NotNil(builder) - qr := builder.GetQueryRegistry() - s.False(qr.HasBufferedQuery()) - s.False(qr.HasCompletedQuery()) - s.False(qr.HasUnblockedQuery()) - waitGroup.Wait() -} - -func (s *engineSuite) TestRespondDecisionTaskCompletedInvalidToken() { - - invalidToken, _ := json.Marshal("bad token") - identity := "testIdentity" - - _, err := s.mockHistoryEngine.RespondDecisionTaskCompleted(context.Background(), &types.HistoryRespondDecisionTaskCompletedRequest{ - DomainUUID: constants.TestDomainID, - CompleteRequest: &types.RespondDecisionTaskCompletedRequest{ - TaskToken: invalidToken, - Decisions: nil, - ExecutionContext: nil, - Identity: identity, - }, - }) - - s.NotNil(err) - s.IsType(&types.BadRequestError{}, err) -} - -func (s *engineSuite) TestRespondDecisionTaskCompletedIfNoExecution() { - - taskToken, _ := json.Marshal(&common.TaskToken{ - WorkflowID: "wId", - RunID: constants.TestRunID, - ScheduleID: 2, - }) - identity := "testIdentity" - - s.mockExecutionMgr.On("GetWorkflowExecution", mock.Anything, mock.Anything).Return(nil, &types.EntityNotExistsError{}).Once() - - _, err := s.mockHistoryEngine.RespondDecisionTaskCompleted(context.Background(), &types.HistoryRespondDecisionTaskCompletedRequest{ - DomainUUID: constants.TestDomainID, - CompleteRequest: &types.RespondDecisionTaskCompletedRequest{ - TaskToken: taskToken, - Identity: identity, - }, - }) - s.NotNil(err) - s.IsType(&types.EntityNotExistsError{}, err) -} - -func (s *engineSuite) TestRespondDecisionTaskCompletedIfGetExecutionFailed() { - - taskToken, _ := json.Marshal(&common.TaskToken{ - WorkflowID: "wId", - RunID: constants.TestRunID, - ScheduleID: 2, - }) - identity := "testIdentity" - - s.mockExecutionMgr.On("GetWorkflowExecution", mock.Anything, mock.Anything).Return(nil, errors.New("FAILED")).Once() - - _, err := s.mockHistoryEngine.RespondDecisionTaskCompleted(context.Background(), &types.HistoryRespondDecisionTaskCompletedRequest{ - DomainUUID: constants.TestDomainID, - CompleteRequest: &types.RespondDecisionTaskCompletedRequest{ - TaskToken: taskToken, - Identity: identity, - }, - }) - s.EqualError(err, "FAILED") -} - -func (s *engineSuite) TestRespondDecisionTaskCompletedUpdateExecutionFailed() { - - we := types.WorkflowExecution{ - WorkflowID: "wId", - RunID: constants.TestRunID, - } - tl := "testTaskList" - - taskToken, _ := json.Marshal(&common.TaskToken{ - WorkflowID: we.WorkflowID, - RunID: we.RunID, - ScheduleID: 2, - }) - identity := "testIdentity" - - msBuilder := execution.NewMutableStateBuilderWithEventV2( - s.mockHistoryEngine.shard, - testlogger.New(s.Suite.T()), - we.GetRunID(), - constants.TestLocalDomainEntry, - ) - test.AddWorkflowExecutionStartedEvent(msBuilder, we, "wType", tl, []byte("input"), 100, 200, identity) - di := test.AddDecisionTaskScheduledEvent(msBuilder) - test.AddDecisionTaskStartedEvent(msBuilder, di.ScheduleID, tl, identity) - - ms := execution.CreatePersistenceMutableState(msBuilder) - gwmsResponse := &persistence.GetWorkflowExecutionResponse{State: ms} - - s.mockExecutionMgr.On("GetWorkflowExecution", mock.Anything, mock.Anything).Return(gwmsResponse, nil).Once() - s.mockHistoryV2Mgr.On("AppendHistoryNodes", mock.Anything, mock.Anything).Return(&persistence.AppendHistoryNodesResponse{}, nil).Once() - s.mockExecutionMgr.On("UpdateWorkflowExecution", mock.Anything, mock.Anything).Return(&persistence.UpdateWorkflowExecutionResponse{MutableStateUpdateSessionStats: &persistence.MutableStateUpdateSessionStats{}}, errors.New("FAILED")).Once() - s.mockShardManager.On("UpdateShard", mock.Anything, mock.Anything).Return(nil).Once() - - _, err := s.mockHistoryEngine.RespondDecisionTaskCompleted(context.Background(), &types.HistoryRespondDecisionTaskCompletedRequest{ - DomainUUID: constants.TestDomainID, - CompleteRequest: &types.RespondDecisionTaskCompletedRequest{ - TaskToken: taskToken, - Identity: identity, - }, - }) - s.NotNil(err) - s.EqualError(err, "FAILED") -} - -func (s *engineSuite) TestRespondDecisionTaskCompletedIfTaskCompleted() { - - we := types.WorkflowExecution{ - WorkflowID: "wId", - RunID: constants.TestRunID, - } - tl := "testTaskList" - taskToken, _ := json.Marshal(&common.TaskToken{ - WorkflowID: we.WorkflowID, - RunID: we.RunID, - ScheduleID: 2, - }) - identity := "testIdentity" - - msBuilder := execution.NewMutableStateBuilderWithEventV2( - s.mockHistoryEngine.shard, - testlogger.New(s.Suite.T()), - we.GetRunID(), - constants.TestLocalDomainEntry, - ) - test.AddWorkflowExecutionStartedEvent(msBuilder, we, "wType", tl, []byte("input"), 100, 200, identity) - di := test.AddDecisionTaskScheduledEvent(msBuilder) - startedEvent := test.AddDecisionTaskStartedEvent(msBuilder, di.ScheduleID, tl, identity) - test.AddDecisionTaskCompletedEvent(msBuilder, di.ScheduleID, startedEvent.ID, nil, identity) - - ms := execution.CreatePersistenceMutableState(msBuilder) - gwmsResponse := &persistence.GetWorkflowExecutionResponse{State: ms} - - s.mockExecutionMgr.On("GetWorkflowExecution", mock.Anything, mock.Anything).Return(gwmsResponse, nil).Once() - - _, err := s.mockHistoryEngine.RespondDecisionTaskCompleted(context.Background(), &types.HistoryRespondDecisionTaskCompletedRequest{ - DomainUUID: constants.TestDomainID, - CompleteRequest: &types.RespondDecisionTaskCompletedRequest{ - TaskToken: taskToken, - Identity: identity, - }, - }) - s.NotNil(err) - s.IsType(&types.EntityNotExistsError{}, err) -} - -func (s *engineSuite) TestRespondDecisionTaskCompletedIfTaskNotStarted() { - - we := types.WorkflowExecution{ - WorkflowID: "wId", - RunID: constants.TestRunID, - } - tl := "testTaskList" - taskToken, _ := json.Marshal(&common.TaskToken{ - WorkflowID: we.WorkflowID, - RunID: we.RunID, - ScheduleID: 2, - }) - identity := "testIdentity" - - msBuilder := execution.NewMutableStateBuilderWithEventV2( - s.mockHistoryEngine.shard, - testlogger.New(s.Suite.T()), - we.GetRunID(), - constants.TestLocalDomainEntry, - ) - test.AddWorkflowExecutionStartedEvent(msBuilder, we, "wType", tl, []byte("input"), 100, 200, identity) - test.AddDecisionTaskScheduledEvent(msBuilder) - - ms := execution.CreatePersistenceMutableState(msBuilder) - gwmsResponse := &persistence.GetWorkflowExecutionResponse{State: ms} - - s.mockExecutionMgr.On("GetWorkflowExecution", mock.Anything, mock.Anything).Return(gwmsResponse, nil).Once() - - _, err := s.mockHistoryEngine.RespondDecisionTaskCompleted(context.Background(), &types.HistoryRespondDecisionTaskCompletedRequest{ - DomainUUID: constants.TestDomainID, - CompleteRequest: &types.RespondDecisionTaskCompletedRequest{ - TaskToken: taskToken, - }, - }) - s.NotNil(err) - s.IsType(&types.EntityNotExistsError{}, err) -} - -func (s *engineSuite) TestRespondDecisionTaskCompletedConflictOnUpdate() { - - we := types.WorkflowExecution{ - WorkflowID: "wId", - RunID: constants.TestRunID, - } - tl := "testTaskList" - identity := "testIdentity" - executionContext := []byte("context") - activity1ID := "activity1" - activity1Type := "activity_type1" - activity1Input := []byte("input1") - activity1Result := []byte("activity1_result") - activity2ID := "activity2" - activity2Type := "activity_type2" - activity2Input := []byte("input2") - activity2Result := []byte("activity2_result") - activity3ID := "activity3" - activity3Type := "activity_type3" - activity3Input := []byte("input3") - - msBuilder := execution.NewMutableStateBuilderWithEventV2( - s.mockHistoryEngine.shard, - testlogger.New(s.Suite.T()), - we.GetRunID(), - constants.TestLocalDomainEntry, - ) - test.AddWorkflowExecutionStartedEvent(msBuilder, we, "wType", tl, []byte("input"), 100, 100, identity) - di1 := test.AddDecisionTaskScheduledEvent(msBuilder) - decisionStartedEvent1 := test.AddDecisionTaskStartedEvent(msBuilder, di1.ScheduleID, tl, identity) - decisionCompletedEvent1 := test.AddDecisionTaskCompletedEvent(msBuilder, di1.ScheduleID, - decisionStartedEvent1.ID, nil, identity) - activity1ScheduledEvent, _ := test.AddActivityTaskScheduledEvent(msBuilder, decisionCompletedEvent1.ID, - activity1ID, activity1Type, tl, activity1Input, 100, 10, 1, 5) - activity2ScheduledEvent, _ := test.AddActivityTaskScheduledEvent(msBuilder, decisionCompletedEvent1.ID, - activity2ID, activity2Type, tl, activity2Input, 100, 10, 1, 5) - activity1StartedEvent := test.AddActivityTaskStartedEvent(msBuilder, activity1ScheduledEvent.ID, identity) - activity2StartedEvent := test.AddActivityTaskStartedEvent(msBuilder, activity2ScheduledEvent.ID, identity) - test.AddActivityTaskCompletedEvent(msBuilder, activity1ScheduledEvent.ID, - activity1StartedEvent.ID, activity1Result, identity) - di2 := test.AddDecisionTaskScheduledEvent(msBuilder) - decisionStartedEvent2 := test.AddDecisionTaskStartedEvent(msBuilder, di2.ScheduleID, tl, identity) - - taskToken, _ := json.Marshal(&common.TaskToken{ - WorkflowID: "wId", - RunID: we.GetRunID(), - ScheduleID: di2.ScheduleID, - }) - - decisions := []*types.Decision{{ - DecisionType: types.DecisionTypeScheduleActivityTask.Ptr(), - ScheduleActivityTaskDecisionAttributes: &types.ScheduleActivityTaskDecisionAttributes{ - ActivityID: activity3ID, - ActivityType: &types.ActivityType{Name: activity3Type}, - TaskList: &types.TaskList{Name: tl}, - Input: activity3Input, - ScheduleToCloseTimeoutSeconds: common.Int32Ptr(100), - ScheduleToStartTimeoutSeconds: common.Int32Ptr(10), - StartToCloseTimeoutSeconds: common.Int32Ptr(50), - HeartbeatTimeoutSeconds: common.Int32Ptr(5), - }, - }} - - ms := execution.CreatePersistenceMutableState(msBuilder) - gwmsResponse := &persistence.GetWorkflowExecutionResponse{State: ms} - - test.AddActivityTaskCompletedEvent(msBuilder, activity2ScheduledEvent.ID, - activity2StartedEvent.ID, activity2Result, identity) - - ms2 := execution.CreatePersistenceMutableState(msBuilder) - gwmsResponse2 := &persistence.GetWorkflowExecutionResponse{State: ms2} - - s.mockExecutionMgr.On("GetWorkflowExecution", mock.Anything, mock.Anything).Return(gwmsResponse, nil).Once() - s.mockHistoryV2Mgr.On("AppendHistoryNodes", mock.Anything, mock.Anything).Return(&persistence.AppendHistoryNodesResponse{}, nil).Once() - s.mockExecutionMgr.On("UpdateWorkflowExecution", mock.Anything, mock.Anything).Return(&persistence.UpdateWorkflowExecutionResponse{MutableStateUpdateSessionStats: &persistence.MutableStateUpdateSessionStats{}}, - &persistence.ConditionFailedError{}).Once() - - s.mockExecutionMgr.On("GetWorkflowExecution", mock.Anything, mock.Anything).Return(gwmsResponse2, nil).Once() - s.mockHistoryV2Mgr.On("AppendHistoryNodes", mock.Anything, mock.Anything).Return(&persistence.AppendHistoryNodesResponse{}, nil).Once() - s.mockExecutionMgr.On("UpdateWorkflowExecution", mock.Anything, mock.Anything).Return(&persistence.UpdateWorkflowExecutionResponse{MutableStateUpdateSessionStats: &persistence.MutableStateUpdateSessionStats{}}, nil).Once() - - _, err := s.mockHistoryEngine.RespondDecisionTaskCompleted(context.Background(), &types.HistoryRespondDecisionTaskCompletedRequest{ - DomainUUID: constants.TestDomainID, - CompleteRequest: &types.RespondDecisionTaskCompletedRequest{ - TaskToken: taskToken, - Decisions: decisions, - ExecutionContext: executionContext, - Identity: identity, - }, - }) - s.Nil(err, s.printHistory(msBuilder)) - s.Equal(int64(16), ms2.ExecutionInfo.NextEventID) - s.Equal(decisionStartedEvent2.ID, ms2.ExecutionInfo.LastProcessedEvent) - s.Equal(executionContext, ms2.ExecutionInfo.ExecutionContext) - - executionBuilder := s.getBuilder(constants.TestDomainID, we) - activity3Attributes := s.getActivityScheduledEvent(executionBuilder, 13).ActivityTaskScheduledEventAttributes - s.Equal(activity3ID, activity3Attributes.ActivityID) - s.Equal(activity3Type, activity3Attributes.ActivityType.Name) - s.Equal(int64(12), activity3Attributes.DecisionTaskCompletedEventID) - s.Equal(tl, activity3Attributes.TaskList.Name) - s.Equal(activity3Input, activity3Attributes.Input) - s.Equal(int32(100), *activity3Attributes.ScheduleToCloseTimeoutSeconds) - s.Equal(int32(10), *activity3Attributes.ScheduleToStartTimeoutSeconds) - s.Equal(int32(50), *activity3Attributes.StartToCloseTimeoutSeconds) - s.Equal(int32(5), *activity3Attributes.HeartbeatTimeoutSeconds) - - di, ok := executionBuilder.GetDecisionInfo(15) - s.True(ok) - s.Equal(int32(100), di.DecisionTimeout) -} - -func (s *engineSuite) TestValidateSignalRequest() { - workflowType := "testType" - input := []byte("input") - startRequest := &types.StartWorkflowExecutionRequest{ - WorkflowID: "ID", - WorkflowType: &types.WorkflowType{Name: workflowType}, - TaskList: &types.TaskList{Name: "taskptr"}, - Input: input, - ExecutionStartToCloseTimeoutSeconds: common.Int32Ptr(10), - TaskStartToCloseTimeoutSeconds: common.Int32Ptr(10), - Identity: "identity", - } - - err := s.mockHistoryEngine.validateStartWorkflowExecutionRequest(startRequest, 0) - s.Error(err, "startRequest doesn't have request id, it should error out") -} - -func (s *engineSuite) TestRespondDecisionTaskCompletedMaxAttemptsExceeded() { - - we := types.WorkflowExecution{ - WorkflowID: "wId", - RunID: constants.TestRunID, - } - tl := "testTaskList" - taskToken, _ := json.Marshal(&common.TaskToken{ - WorkflowID: we.WorkflowID, - RunID: we.RunID, - ScheduleID: 2, - }) - identity := "testIdentity" - executionContext := []byte("context") - input := []byte("input") - - msBuilder := execution.NewMutableStateBuilderWithEventV2( - s.mockHistoryEngine.shard, - testlogger.New(s.Suite.T()), - we.GetRunID(), - constants.TestLocalDomainEntry, - ) - test.AddWorkflowExecutionStartedEvent(msBuilder, we, "wType", tl, []byte("input"), 100, 200, identity) - di := test.AddDecisionTaskScheduledEvent(msBuilder) - test.AddDecisionTaskStartedEvent(msBuilder, di.ScheduleID, tl, identity) - - decisions := []*types.Decision{{ - DecisionType: types.DecisionTypeScheduleActivityTask.Ptr(), - ScheduleActivityTaskDecisionAttributes: &types.ScheduleActivityTaskDecisionAttributes{ - ActivityID: "activity1", - ActivityType: &types.ActivityType{Name: "activity_type1"}, - TaskList: &types.TaskList{Name: tl}, - Input: input, - ScheduleToCloseTimeoutSeconds: common.Int32Ptr(100), - ScheduleToStartTimeoutSeconds: common.Int32Ptr(10), - StartToCloseTimeoutSeconds: common.Int32Ptr(50), - HeartbeatTimeoutSeconds: common.Int32Ptr(5), - }, - }} - - for i := 0; i < workflow.ConditionalRetryCount; i++ { - ms := execution.CreatePersistenceMutableState(msBuilder) - gwmsResponse := &persistence.GetWorkflowExecutionResponse{State: ms} - - s.mockExecutionMgr.On("GetWorkflowExecution", mock.Anything, mock.Anything).Return(gwmsResponse, nil).Once() - s.mockHistoryV2Mgr.On("AppendHistoryNodes", mock.Anything, mock.Anything).Return(&persistence.AppendHistoryNodesResponse{}, nil).Once() - s.mockExecutionMgr.On("UpdateWorkflowExecution", mock.Anything, mock.Anything).Return(&persistence.UpdateWorkflowExecutionResponse{MutableStateUpdateSessionStats: &persistence.MutableStateUpdateSessionStats{}}, - &persistence.ConditionFailedError{}).Once() - } - - _, err := s.mockHistoryEngine.RespondDecisionTaskCompleted(context.Background(), &types.HistoryRespondDecisionTaskCompletedRequest{ - DomainUUID: constants.TestDomainID, - CompleteRequest: &types.RespondDecisionTaskCompletedRequest{ - TaskToken: taskToken, - Decisions: decisions, - ExecutionContext: executionContext, - Identity: identity, - }, - }) - s.NotNil(err) - s.Equal(workflow.ErrMaxAttemptsExceeded, err) -} - -func (s *engineSuite) TestRespondDecisionTaskCompletedCompleteWorkflowFailed() { - - we := types.WorkflowExecution{ - WorkflowID: "wId", - RunID: constants.TestRunID, - } - tl := "testTaskList" - identity := "testIdentity" - executionContext := []byte("context") - activity1ID := "activity1" - activity1Type := "activity_type1" - activity1Input := []byte("input1") - activity1Result := []byte("activity1_result") - activity2ID := "activity2" - activity2Type := "activity_type2" - activity2Input := []byte("input2") - activity2Result := []byte("activity2_result") - workflowResult := []byte("workflow result") - - msBuilder := execution.NewMutableStateBuilderWithEventV2( - s.mockHistoryEngine.shard, - testlogger.New(s.Suite.T()), - we.GetRunID(), - constants.TestLocalDomainEntry, - ) - test.AddWorkflowExecutionStartedEvent(msBuilder, we, "wType", tl, []byte("input"), 25, 200, identity) - di1 := test.AddDecisionTaskScheduledEvent(msBuilder) - decisionStartedEvent1 := test.AddDecisionTaskStartedEvent(msBuilder, di1.ScheduleID, tl, identity) - decisionCompletedEvent1 := test.AddDecisionTaskCompletedEvent(msBuilder, di1.ScheduleID, - decisionStartedEvent1.ID, nil, identity) - activity1ScheduledEvent, _ := test.AddActivityTaskScheduledEvent(msBuilder, decisionCompletedEvent1.ID, - activity1ID, activity1Type, tl, activity1Input, 100, 10, 1, 5) - activity2ScheduledEvent, _ := test.AddActivityTaskScheduledEvent(msBuilder, decisionCompletedEvent1.ID, - activity2ID, activity2Type, tl, activity2Input, 100, 10, 1, 5) - activity1StartedEvent := test.AddActivityTaskStartedEvent(msBuilder, activity1ScheduledEvent.ID, identity) - activity2StartedEvent := test.AddActivityTaskStartedEvent(msBuilder, activity2ScheduledEvent.ID, identity) - test.AddActivityTaskCompletedEvent(msBuilder, activity1ScheduledEvent.ID, - activity1StartedEvent.ID, activity1Result, identity) - di2 := test.AddDecisionTaskScheduledEvent(msBuilder) - test.AddDecisionTaskStartedEvent(msBuilder, di2.ScheduleID, tl, identity) - test.AddActivityTaskCompletedEvent(msBuilder, activity2ScheduledEvent.ID, - activity2StartedEvent.ID, activity2Result, identity) - - taskToken, _ := json.Marshal(&common.TaskToken{ - WorkflowID: we.WorkflowID, - RunID: we.RunID, - ScheduleID: di2.ScheduleID, - }) - - decisions := []*types.Decision{{ - DecisionType: types.DecisionTypeCompleteWorkflowExecution.Ptr(), - CompleteWorkflowExecutionDecisionAttributes: &types.CompleteWorkflowExecutionDecisionAttributes{ - Result: workflowResult, - }, - }} - - for i := 0; i < 2; i++ { - ms := execution.CreatePersistenceMutableState(msBuilder) - gwmsResponse := &persistence.GetWorkflowExecutionResponse{State: ms} - s.mockExecutionMgr.On("GetWorkflowExecution", mock.Anything, mock.Anything).Return(gwmsResponse, nil).Once() - } - - s.mockHistoryV2Mgr.On("AppendHistoryNodes", mock.Anything, mock.Anything).Return(&persistence.AppendHistoryNodesResponse{}, nil).Once() - s.mockExecutionMgr.On("UpdateWorkflowExecution", mock.Anything, mock.Anything).Return(&persistence.UpdateWorkflowExecutionResponse{MutableStateUpdateSessionStats: &persistence.MutableStateUpdateSessionStats{}}, nil).Once() - - _, err := s.mockHistoryEngine.RespondDecisionTaskCompleted(context.Background(), &types.HistoryRespondDecisionTaskCompletedRequest{ - DomainUUID: constants.TestDomainID, - CompleteRequest: &types.RespondDecisionTaskCompletedRequest{ - TaskToken: taskToken, - Decisions: decisions, - ExecutionContext: executionContext, - Identity: identity, - }, - }) - s.Nil(err, s.printHistory(msBuilder)) - executionBuilder := s.getBuilder(constants.TestDomainID, we) - s.Equal(int64(15), executionBuilder.GetExecutionInfo().NextEventID) - s.Equal(decisionStartedEvent1.ID, executionBuilder.GetExecutionInfo().LastProcessedEvent) - s.Empty(executionBuilder.GetExecutionInfo().ExecutionContext) - s.Equal(persistence.WorkflowStateRunning, executionBuilder.GetExecutionInfo().State) - s.True(executionBuilder.HasPendingDecision()) - di3, ok := executionBuilder.GetDecisionInfo(executionBuilder.GetExecutionInfo().NextEventID - 1) - s.True(ok) - s.Equal(executionBuilder.GetExecutionInfo().NextEventID-1, di3.ScheduleID) - s.Equal(int64(0), di3.Attempt) -} - -func (s *engineSuite) TestRespondDecisionTaskCompletedFailWorkflowFailed() { - - we := types.WorkflowExecution{ - WorkflowID: "wId", - RunID: constants.TestRunID, - } - tl := "testTaskList" - identity := "testIdentity" - executionContext := []byte("context") - activity1ID := "activity1" - activity1Type := "activity_type1" - activity1Input := []byte("input1") - activity1Result := []byte("activity1_result") - activity2ID := "activity2" - activity2Type := "activity_type2" - activity2Input := []byte("input2") - activity2Result := []byte("activity2_result") - reason := "workflow fail reason" - details := []byte("workflow fail details") - - msBuilder := execution.NewMutableStateBuilderWithEventV2( - s.mockHistoryEngine.shard, - testlogger.New(s.Suite.T()), - we.GetRunID(), - constants.TestLocalDomainEntry, - ) - test.AddWorkflowExecutionStartedEvent(msBuilder, we, "wType", tl, []byte("input"), 25, 200, identity) - di1 := test.AddDecisionTaskScheduledEvent(msBuilder) - decisionStartedEvent1 := test.AddDecisionTaskStartedEvent(msBuilder, di1.ScheduleID, tl, identity) - decisionCompletedEvent1 := test.AddDecisionTaskCompletedEvent(msBuilder, di1.ScheduleID, - decisionStartedEvent1.ID, nil, identity) - activity1ScheduledEvent, _ := test.AddActivityTaskScheduledEvent(msBuilder, decisionCompletedEvent1.ID, activity1ID, - activity1Type, tl, activity1Input, 100, 10, 1, 5) - activity2ScheduledEvent, _ := test.AddActivityTaskScheduledEvent(msBuilder, decisionCompletedEvent1.ID, activity2ID, - activity2Type, tl, activity2Input, 100, 10, 1, 5) - activity1StartedEvent := test.AddActivityTaskStartedEvent(msBuilder, activity1ScheduledEvent.ID, identity) - activity2StartedEvent := test.AddActivityTaskStartedEvent(msBuilder, activity2ScheduledEvent.ID, identity) - test.AddActivityTaskCompletedEvent(msBuilder, activity1ScheduledEvent.ID, - activity1StartedEvent.ID, activity1Result, identity) - di2 := test.AddDecisionTaskScheduledEvent(msBuilder) - test.AddDecisionTaskStartedEvent(msBuilder, di2.ScheduleID, tl, identity) - test.AddActivityTaskCompletedEvent(msBuilder, activity2ScheduledEvent.ID, - activity2StartedEvent.ID, activity2Result, identity) - - taskToken, _ := json.Marshal(&common.TaskToken{ - WorkflowID: we.WorkflowID, - RunID: we.RunID, - ScheduleID: di2.ScheduleID, - }) - - decisions := []*types.Decision{{ - DecisionType: types.DecisionTypeFailWorkflowExecution.Ptr(), - FailWorkflowExecutionDecisionAttributes: &types.FailWorkflowExecutionDecisionAttributes{ - Reason: &reason, - Details: details, - }, - }} - - for i := 0; i < 2; i++ { - ms := execution.CreatePersistenceMutableState(msBuilder) - gwmsResponse := &persistence.GetWorkflowExecutionResponse{State: ms} - s.mockExecutionMgr.On("GetWorkflowExecution", mock.Anything, mock.Anything).Return(gwmsResponse, nil).Once() - } - - s.mockHistoryV2Mgr.On("AppendHistoryNodes", mock.Anything, mock.Anything).Return(&persistence.AppendHistoryNodesResponse{}, nil).Once() - s.mockExecutionMgr.On("UpdateWorkflowExecution", mock.Anything, mock.Anything).Return(&persistence.UpdateWorkflowExecutionResponse{MutableStateUpdateSessionStats: &persistence.MutableStateUpdateSessionStats{}}, nil).Once() - - _, err := s.mockHistoryEngine.RespondDecisionTaskCompleted(context.Background(), &types.HistoryRespondDecisionTaskCompletedRequest{ - DomainUUID: constants.TestDomainID, - CompleteRequest: &types.RespondDecisionTaskCompletedRequest{ - TaskToken: taskToken, - Decisions: decisions, - ExecutionContext: executionContext, - Identity: identity, - }, - }) - s.Nil(err, s.printHistory(msBuilder)) - executionBuilder := s.getBuilder(constants.TestDomainID, we) - s.Equal(int64(15), executionBuilder.GetExecutionInfo().NextEventID) - s.Equal(decisionStartedEvent1.ID, executionBuilder.GetExecutionInfo().LastProcessedEvent) - s.Empty(executionBuilder.GetExecutionInfo().ExecutionContext) - s.Equal(persistence.WorkflowStateRunning, executionBuilder.GetExecutionInfo().State) - s.True(executionBuilder.HasPendingDecision()) - di3, ok := executionBuilder.GetDecisionInfo(executionBuilder.GetExecutionInfo().NextEventID - 1) - s.True(ok) - s.Equal(executionBuilder.GetExecutionInfo().NextEventID-1, di3.ScheduleID) - s.Equal(int64(0), di3.Attempt) -} - -func (s *engineSuite) TestRespondDecisionTaskCompletedBadDecisionAttributes() { - - we := types.WorkflowExecution{ - WorkflowID: "wId", - RunID: constants.TestRunID, - } - tl := "testTaskList" - identity := "testIdentity" - executionContext := []byte("context") - activity1ID := "activity1" - activity1Type := "activity_type1" - activity1Input := []byte("input1") - activity1Result := []byte("activity1_result") - - msBuilder := execution.NewMutableStateBuilderWithEventV2( - s.mockHistoryEngine.shard, - testlogger.New(s.Suite.T()), - we.GetRunID(), - constants.TestLocalDomainEntry, - ) - test.AddWorkflowExecutionStartedEvent(msBuilder, we, "wType", tl, []byte("input"), 25, 200, identity) - di1 := test.AddDecisionTaskScheduledEvent(msBuilder) - decisionStartedEvent1 := test.AddDecisionTaskStartedEvent(msBuilder, di1.ScheduleID, tl, identity) - decisionCompletedEvent1 := test.AddDecisionTaskCompletedEvent(msBuilder, di1.ScheduleID, - decisionStartedEvent1.ID, nil, identity) - activity1ScheduledEvent, _ := test.AddActivityTaskScheduledEvent(msBuilder, decisionCompletedEvent1.ID, activity1ID, - activity1Type, tl, activity1Input, 100, 10, 1, 5) - activity1StartedEvent := test.AddActivityTaskStartedEvent(msBuilder, activity1ScheduledEvent.ID, identity) - test.AddActivityTaskCompletedEvent(msBuilder, activity1ScheduledEvent.ID, - activity1StartedEvent.ID, activity1Result, identity) - di2 := test.AddDecisionTaskScheduledEvent(msBuilder) - test.AddDecisionTaskStartedEvent(msBuilder, di2.ScheduleID, tl, identity) - - taskToken, _ := json.Marshal(&common.TaskToken{ - WorkflowID: we.WorkflowID, - RunID: we.RunID, - ScheduleID: di2.ScheduleID, - }) - - // Decision with nil attributes - decisions := []*types.Decision{{ - DecisionType: types.DecisionTypeCompleteWorkflowExecution.Ptr(), - }} - - gwmsResponse1 := &persistence.GetWorkflowExecutionResponse{State: execution.CreatePersistenceMutableState(msBuilder)} - gwmsResponse2 := &persistence.GetWorkflowExecutionResponse{State: execution.CreatePersistenceMutableState(msBuilder)} - s.mockExecutionMgr.On("GetWorkflowExecution", mock.Anything, mock.Anything).Return(gwmsResponse1, nil).Once() - s.mockExecutionMgr.On("GetWorkflowExecution", mock.Anything, mock.Anything).Return(gwmsResponse2, nil).Once() - - s.mockHistoryV2Mgr.On("AppendHistoryNodes", mock.Anything, mock.Anything).Return(&persistence.AppendHistoryNodesResponse{}, nil).Once() - s.mockExecutionMgr.On("UpdateWorkflowExecution", mock.Anything, mock.Anything).Return(&persistence.UpdateWorkflowExecutionResponse{ - MutableStateUpdateSessionStats: &persistence.MutableStateUpdateSessionStats{}}, nil, - ).Once() - - _, err := s.mockHistoryEngine.RespondDecisionTaskCompleted(context.Background(), &types.HistoryRespondDecisionTaskCompletedRequest{ - DomainUUID: constants.TestDomainID, - CompleteRequest: &types.RespondDecisionTaskCompletedRequest{ - TaskToken: taskToken, - Decisions: decisions, - ExecutionContext: executionContext, - Identity: identity, - }, - }) - s.Nil(err) -} - -// This test unit tests the activity schedule timeout validation logic of HistoryEngine's RespondDecisionTaskComplete function. -// An scheduled activity decision has 3 timeouts: ScheduleToClose, ScheduleToStart and StartToClose. -// This test verifies that when either ScheduleToClose or ScheduleToStart and StartToClose are specified, -// HistoryEngine's validateActivityScheduleAttribute will deduce the missing timeout and fill it in -// instead of returning a BadRequest error and only when all three are missing should a BadRequest be returned. -func (s *engineSuite) TestRespondDecisionTaskCompletedSingleActivityScheduledAttribute() { - workflowTimeout := int32(100) - testIterationVariables := []struct { - scheduleToClose *int32 - scheduleToStart *int32 - startToClose *int32 - heartbeat *int32 - expectedScheduleToClose int32 - expectedScheduleToStart int32 - expectedStartToClose int32 - expectDecisionFail bool - }{ - // No ScheduleToClose timeout, will use ScheduleToStart + StartToClose - {nil, common.Int32Ptr(3), common.Int32Ptr(7), nil, - 3 + 7, 3, 7, false}, - // Has ScheduleToClose timeout but not ScheduleToStart or StartToClose, - // will use ScheduleToClose for ScheduleToStart and StartToClose - {common.Int32Ptr(7), nil, nil, nil, - 7, 7, 7, false}, - // No ScheduleToClose timeout, ScheduleToStart or StartToClose, expect error return - {nil, nil, nil, nil, - 0, 0, 0, true}, - // Negative ScheduleToClose, expect error return - {common.Int32Ptr(-1), nil, nil, nil, - 0, 0, 0, true}, - // Negative ScheduleToStart, expect error return - {nil, common.Int32Ptr(-1), nil, nil, - 0, 0, 0, true}, - // Negative StartToClose, expect error return - {nil, nil, common.Int32Ptr(-1), nil, - 0, 0, 0, true}, - // Negative HeartBeat, expect error return - {nil, nil, nil, common.Int32Ptr(-1), - 0, 0, 0, true}, - // Use workflow timeout - {common.Int32Ptr(workflowTimeout), nil, nil, nil, - workflowTimeout, workflowTimeout, workflowTimeout, false}, - // Timeout larger than workflow timeout - {common.Int32Ptr(workflowTimeout + 1), nil, nil, nil, - workflowTimeout, workflowTimeout, workflowTimeout, false}, - {nil, common.Int32Ptr(workflowTimeout + 1), nil, nil, - 0, 0, 0, true}, - {nil, nil, common.Int32Ptr(workflowTimeout + 1), nil, - 0, 0, 0, true}, - {nil, nil, nil, common.Int32Ptr(workflowTimeout + 1), - 0, 0, 0, true}, - // No ScheduleToClose timeout, will use ScheduleToStart + StartToClose, but exceed limit - {nil, common.Int32Ptr(workflowTimeout), common.Int32Ptr(10), nil, - workflowTimeout, workflowTimeout, 10, false}, - } - - for _, iVar := range testIterationVariables { - - we := types.WorkflowExecution{ - WorkflowID: "wId", - RunID: constants.TestRunID, - } - tl := "testTaskList" - taskToken, _ := json.Marshal(&common.TaskToken{ - WorkflowID: "wId", - RunID: we.GetRunID(), - ScheduleID: 2, - }) - identity := "testIdentity" - executionContext := []byte("context") - input := []byte("input") - - msBuilder := execution.NewMutableStateBuilderWithEventV2( - s.mockHistoryEngine.shard, - testlogger.New(s.Suite.T()), - we.GetRunID(), - constants.TestLocalDomainEntry, - ) - test.AddWorkflowExecutionStartedEvent(msBuilder, we, "wType", tl, []byte("input"), workflowTimeout, 200, identity) - di := test.AddDecisionTaskScheduledEvent(msBuilder) - test.AddDecisionTaskStartedEvent(msBuilder, di.ScheduleID, tl, identity) - - decisions := []*types.Decision{{ - DecisionType: types.DecisionTypeScheduleActivityTask.Ptr(), - ScheduleActivityTaskDecisionAttributes: &types.ScheduleActivityTaskDecisionAttributes{ - ActivityID: "activity1", - ActivityType: &types.ActivityType{Name: "activity_type1"}, - TaskList: &types.TaskList{Name: tl}, - Input: input, - ScheduleToCloseTimeoutSeconds: iVar.scheduleToClose, - ScheduleToStartTimeoutSeconds: iVar.scheduleToStart, - StartToCloseTimeoutSeconds: iVar.startToClose, - HeartbeatTimeoutSeconds: iVar.heartbeat, - }, - }} - - gwmsResponse1 := &persistence.GetWorkflowExecutionResponse{State: execution.CreatePersistenceMutableState(msBuilder)} - s.mockExecutionMgr.On("GetWorkflowExecution", mock.Anything, mock.Anything).Return(gwmsResponse1, nil).Once() - if iVar.expectDecisionFail { - gwmsResponse2 := &persistence.GetWorkflowExecutionResponse{State: execution.CreatePersistenceMutableState(msBuilder)} - s.mockExecutionMgr.On("GetWorkflowExecution", mock.Anything, mock.Anything).Return(gwmsResponse2, nil).Once() - } - - s.mockHistoryV2Mgr.On("AppendHistoryNodes", mock.Anything, mock.Anything).Return(&persistence.AppendHistoryNodesResponse{}, nil).Once() - s.mockExecutionMgr.On("UpdateWorkflowExecution", mock.Anything, mock.Anything).Return(&persistence.UpdateWorkflowExecutionResponse{MutableStateUpdateSessionStats: &persistence.MutableStateUpdateSessionStats{}}, nil).Once() - - _, err := s.mockHistoryEngine.RespondDecisionTaskCompleted(context.Background(), &types.HistoryRespondDecisionTaskCompletedRequest{ - DomainUUID: constants.TestDomainID, - CompleteRequest: &types.RespondDecisionTaskCompletedRequest{ - TaskToken: taskToken, - Decisions: decisions, - ExecutionContext: executionContext, - Identity: identity, - }, - }) - - s.Nil(err, s.printHistory(msBuilder)) - executionBuilder := s.getBuilder(constants.TestDomainID, we) - if !iVar.expectDecisionFail { - s.Equal(int64(6), executionBuilder.GetExecutionInfo().NextEventID) - s.Equal(int64(3), executionBuilder.GetExecutionInfo().LastProcessedEvent) - s.Equal(persistence.WorkflowStateRunning, executionBuilder.GetExecutionInfo().State) - s.False(executionBuilder.HasPendingDecision()) - - activity1Attributes := s.getActivityScheduledEvent(executionBuilder, int64(5)).ActivityTaskScheduledEventAttributes - s.Equal(iVar.expectedScheduleToClose, activity1Attributes.GetScheduleToCloseTimeoutSeconds()) - s.Equal(iVar.expectedScheduleToStart, activity1Attributes.GetScheduleToStartTimeoutSeconds()) - s.Equal(iVar.expectedStartToClose, activity1Attributes.GetStartToCloseTimeoutSeconds()) - } else { - s.Equal(int64(5), executionBuilder.GetExecutionInfo().NextEventID) - s.Equal(common.EmptyEventID, executionBuilder.GetExecutionInfo().LastProcessedEvent) - s.Equal(persistence.WorkflowStateRunning, executionBuilder.GetExecutionInfo().State) - s.True(executionBuilder.HasPendingDecision()) - } - s.TearDownTest() - s.SetupTest() - } -} - -func (s *engineSuite) TestRespondDecisionTaskCompletedBadBinary() { - domainID := uuid.New() - we := types.WorkflowExecution{ - WorkflowID: "wId", - RunID: constants.TestRunID, - } - tl := "testTaskList" - taskToken, _ := json.Marshal(&common.TaskToken{ - WorkflowID: "wId", - RunID: we.GetRunID(), - ScheduleID: 2, - }) - identity := "testIdentity" - executionContext := []byte("context") - domainEntry := cache.NewLocalDomainCacheEntryForTest( - &persistence.DomainInfo{ID: domainID, Name: constants.TestDomainName}, - &persistence.DomainConfig{ - Retention: 2, - BadBinaries: types.BadBinaries{ - Binaries: map[string]*types.BadBinaryInfo{ - "test-bad-binary": {}, - }, - }, - }, - cluster.TestCurrentClusterName, - ) - - msBuilder := execution.NewMutableStateBuilderWithEventV2( - s.mockHistoryEngine.shard, - testlogger.New(s.Suite.T()), - we.GetRunID(), - domainEntry, - ) - test.AddWorkflowExecutionStartedEvent(msBuilder, we, "wType", tl, []byte("input"), 100, 200, identity) - di := test.AddDecisionTaskScheduledEvent(msBuilder) - test.AddDecisionTaskStartedEvent(msBuilder, di.ScheduleID, tl, identity) - - var decisions []*types.Decision - - gwmsResponse1 := &persistence.GetWorkflowExecutionResponse{State: execution.CreatePersistenceMutableState(msBuilder)} - gwmsResponse2 := &persistence.GetWorkflowExecutionResponse{State: execution.CreatePersistenceMutableState(msBuilder)} - - s.mockExecutionMgr.On("GetWorkflowExecution", mock.Anything, mock.Anything).Return(gwmsResponse1, nil).Once() - s.mockExecutionMgr.On("GetWorkflowExecution", mock.Anything, mock.Anything).Return(gwmsResponse2, nil).Once() - s.mockHistoryV2Mgr.On("AppendHistoryNodes", mock.Anything, mock.Anything).Return(&persistence.AppendHistoryNodesResponse{}, nil).Once() - s.mockExecutionMgr.On("UpdateWorkflowExecution", mock.Anything, mock.Anything).Return(&persistence.UpdateWorkflowExecutionResponse{MutableStateUpdateSessionStats: &persistence.MutableStateUpdateSessionStats{}}, nil).Once() - s.mockDomainCache.EXPECT().GetDomainByID(domainID).Return(domainEntry, nil).AnyTimes() - s.mockDomainCache.EXPECT().GetDomainName(domainID).Return(constants.TestDomainName, nil).AnyTimes() - - _, err := s.mockHistoryEngine.RespondDecisionTaskCompleted(context.Background(), &types.HistoryRespondDecisionTaskCompletedRequest{ - DomainUUID: domainID, - CompleteRequest: &types.RespondDecisionTaskCompletedRequest{ - TaskToken: taskToken, - Decisions: decisions, - ExecutionContext: executionContext, - Identity: identity, - BinaryChecksum: "test-bad-binary", - }, - }) - s.Nil(err, s.printHistory(msBuilder)) - executionBuilder := s.getBuilder(domainID, we) - s.Equal(int64(5), executionBuilder.GetExecutionInfo().NextEventID) - s.Equal(common.EmptyEventID, executionBuilder.GetExecutionInfo().LastProcessedEvent) - s.Empty(executionBuilder.GetExecutionInfo().ExecutionContext) - s.Equal(persistence.WorkflowStateRunning, executionBuilder.GetExecutionInfo().State) - s.True(executionBuilder.HasPendingDecision()) -} - -func (s *engineSuite) TestRespondDecisionTaskCompletedSingleActivityScheduledDecision() { - - we := types.WorkflowExecution{ - WorkflowID: "wId", - RunID: constants.TestRunID, - } - tl := "testTaskList" - taskToken, _ := json.Marshal(&common.TaskToken{ - WorkflowID: "wId", - RunID: we.GetRunID(), - ScheduleID: 2, - }) - identity := "testIdentity" - executionContext := []byte("context") - input := []byte("input") - - msBuilder := execution.NewMutableStateBuilderWithEventV2( - s.mockHistoryEngine.shard, - testlogger.New(s.Suite.T()), - we.GetRunID(), - constants.TestLocalDomainEntry, - ) - test.AddWorkflowExecutionStartedEvent(msBuilder, we, "wType", tl, []byte("input"), 100, 200, identity) - di := test.AddDecisionTaskScheduledEvent(msBuilder) - test.AddDecisionTaskStartedEvent(msBuilder, di.ScheduleID, tl, identity) - - decisions := []*types.Decision{{ - DecisionType: types.DecisionTypeScheduleActivityTask.Ptr(), - ScheduleActivityTaskDecisionAttributes: &types.ScheduleActivityTaskDecisionAttributes{ - ActivityID: "activity1", - ActivityType: &types.ActivityType{Name: "activity_type1"}, - TaskList: &types.TaskList{Name: tl}, - Input: input, - ScheduleToCloseTimeoutSeconds: common.Int32Ptr(100), - ScheduleToStartTimeoutSeconds: common.Int32Ptr(10), - StartToCloseTimeoutSeconds: common.Int32Ptr(50), - HeartbeatTimeoutSeconds: common.Int32Ptr(5), - }, - }} - - ms := execution.CreatePersistenceMutableState(msBuilder) - gwmsResponse := &persistence.GetWorkflowExecutionResponse{State: ms} - - s.mockExecutionMgr.On("GetWorkflowExecution", mock.Anything, mock.Anything).Return(gwmsResponse, nil).Once() - s.mockHistoryV2Mgr.On("AppendHistoryNodes", mock.Anything, mock.Anything).Return(&persistence.AppendHistoryNodesResponse{}, nil).Once() - s.mockExecutionMgr.On("UpdateWorkflowExecution", mock.Anything, mock.Anything).Return(&persistence.UpdateWorkflowExecutionResponse{MutableStateUpdateSessionStats: &persistence.MutableStateUpdateSessionStats{}}, nil).Once() - - _, err := s.mockHistoryEngine.RespondDecisionTaskCompleted(context.Background(), &types.HistoryRespondDecisionTaskCompletedRequest{ - DomainUUID: constants.TestDomainID, - CompleteRequest: &types.RespondDecisionTaskCompletedRequest{ - TaskToken: taskToken, - Decisions: decisions, - ExecutionContext: executionContext, - Identity: identity, - }, - }) - s.Nil(err, s.printHistory(msBuilder)) - executionBuilder := s.getBuilder(constants.TestDomainID, we) - s.Equal(int64(6), executionBuilder.GetExecutionInfo().NextEventID) - s.Equal(int64(3), executionBuilder.GetExecutionInfo().LastProcessedEvent) - s.Equal(executionContext, executionBuilder.GetExecutionInfo().ExecutionContext) - s.Equal(persistence.WorkflowStateRunning, executionBuilder.GetExecutionInfo().State) - s.False(executionBuilder.HasPendingDecision()) - - activity1Attributes := s.getActivityScheduledEvent(executionBuilder, int64(5)).ActivityTaskScheduledEventAttributes - s.Equal("activity1", activity1Attributes.ActivityID) - s.Equal("activity_type1", activity1Attributes.ActivityType.Name) - s.Equal(int64(4), activity1Attributes.DecisionTaskCompletedEventID) - s.Equal(tl, activity1Attributes.TaskList.Name) - s.Equal(input, activity1Attributes.Input) - s.Equal(int32(100), *activity1Attributes.ScheduleToCloseTimeoutSeconds) - s.Equal(int32(10), *activity1Attributes.ScheduleToStartTimeoutSeconds) - s.Equal(int32(50), *activity1Attributes.StartToCloseTimeoutSeconds) - s.Equal(int32(5), *activity1Attributes.HeartbeatTimeoutSeconds) -} - -func (s *engineSuite) TestRespondDecisionTaskCompleted_DecisionHeartbeatTimeout() { - - we := types.WorkflowExecution{ - WorkflowID: "wId", - RunID: constants.TestRunID, - } - tl := "testTaskList" - taskToken, _ := json.Marshal(&common.TaskToken{ - WorkflowID: we.WorkflowID, - RunID: we.RunID, - ScheduleID: 2, - }) - identity := "testIdentity" - executionContext := []byte("context") - - msBuilder := execution.NewMutableStateBuilderWithEventV2( - s.mockHistoryEngine.shard, - testlogger.New(s.Suite.T()), - we.GetRunID(), - constants.TestLocalDomainEntry, - ) - test.AddWorkflowExecutionStartedEvent(msBuilder, we, "wType", tl, []byte("input"), 100, 200, identity) - di := test.AddDecisionTaskScheduledEvent(msBuilder) - test.AddDecisionTaskStartedEvent(msBuilder, di.ScheduleID, tl, identity) - msBuilder.GetExecutionInfo().DecisionOriginalScheduledTimestamp = time.Now().Add(-time.Hour).UnixNano() - - decisions := []*types.Decision{} - - ms := execution.CreatePersistenceMutableState(msBuilder) - gwmsResponse := &persistence.GetWorkflowExecutionResponse{State: ms} - - s.mockExecutionMgr.On("GetWorkflowExecution", mock.Anything, mock.Anything).Return(gwmsResponse, nil).Once() - s.mockHistoryV2Mgr.On("AppendHistoryNodes", mock.Anything, mock.Anything).Return(&persistence.AppendHistoryNodesResponse{}, nil).Once() - s.mockExecutionMgr.On("UpdateWorkflowExecution", mock.Anything, mock.Anything).Return(&persistence.UpdateWorkflowExecutionResponse{MutableStateUpdateSessionStats: &persistence.MutableStateUpdateSessionStats{}}, nil).Once() - - _, err := s.mockHistoryEngine.RespondDecisionTaskCompleted(context.Background(), &types.HistoryRespondDecisionTaskCompletedRequest{ - DomainUUID: constants.TestDomainID, - CompleteRequest: &types.RespondDecisionTaskCompletedRequest{ - ForceCreateNewDecisionTask: true, - TaskToken: taskToken, - Decisions: decisions, - ExecutionContext: executionContext, - Identity: identity, - }, - }) - s.Error(err, "decision heartbeat timeout") -} - -func (s *engineSuite) TestRespondDecisionTaskCompleted_DecisionHeartbeatNotTimeout() { - - we := types.WorkflowExecution{ - WorkflowID: "wId", - RunID: constants.TestRunID, - } - tl := "testTaskList" - taskToken, _ := json.Marshal(&common.TaskToken{ - WorkflowID: we.WorkflowID, - RunID: we.RunID, - ScheduleID: 2, - }) - identity := "testIdentity" - executionContext := []byte("context") - - msBuilder := execution.NewMutableStateBuilderWithEventV2( - s.mockHistoryEngine.shard, - testlogger.New(s.Suite.T()), - we.GetRunID(), - constants.TestLocalDomainEntry, - ) - test.AddWorkflowExecutionStartedEvent(msBuilder, we, "wType", tl, []byte("input"), 100, 200, identity) - di := test.AddDecisionTaskScheduledEvent(msBuilder) - test.AddDecisionTaskStartedEvent(msBuilder, di.ScheduleID, tl, identity) - msBuilder.GetExecutionInfo().DecisionOriginalScheduledTimestamp = time.Now().Add(-time.Minute).UnixNano() - - decisions := []*types.Decision{} - - ms := execution.CreatePersistenceMutableState(msBuilder) - gwmsResponse := &persistence.GetWorkflowExecutionResponse{State: ms} - - s.mockExecutionMgr.On("GetWorkflowExecution", mock.Anything, mock.Anything).Return(gwmsResponse, nil).Once() - s.mockHistoryV2Mgr.On("AppendHistoryNodes", mock.Anything, mock.Anything).Return(&persistence.AppendHistoryNodesResponse{}, nil).Once() - s.mockExecutionMgr.On("UpdateWorkflowExecution", mock.Anything, mock.Anything).Return(&persistence.UpdateWorkflowExecutionResponse{MutableStateUpdateSessionStats: &persistence.MutableStateUpdateSessionStats{}}, nil).Once() - - _, err := s.mockHistoryEngine.RespondDecisionTaskCompleted(context.Background(), &types.HistoryRespondDecisionTaskCompletedRequest{ - DomainUUID: constants.TestDomainID, - CompleteRequest: &types.RespondDecisionTaskCompletedRequest{ - ForceCreateNewDecisionTask: true, - TaskToken: taskToken, - Decisions: decisions, - ExecutionContext: executionContext, - Identity: identity, - }, - }) - s.Nil(err) -} - -func (s *engineSuite) TestRespondDecisionTaskCompleted_DecisionHeartbeatNotTimeout_ZeroOrignalScheduledTime() { - - we := types.WorkflowExecution{ - WorkflowID: "wId", - RunID: constants.TestRunID, - } - tl := "testTaskList" - taskToken, _ := json.Marshal(&common.TaskToken{ - WorkflowID: we.WorkflowID, - RunID: we.RunID, - ScheduleID: 2, - }) - identity := "testIdentity" - executionContext := []byte("context") - - msBuilder := execution.NewMutableStateBuilderWithEventV2( - s.mockHistoryEngine.shard, - testlogger.New(s.Suite.T()), - we.GetRunID(), - constants.TestLocalDomainEntry, - ) - test.AddWorkflowExecutionStartedEvent(msBuilder, we, "wType", tl, []byte("input"), 100, 200, identity) - di := test.AddDecisionTaskScheduledEvent(msBuilder) - test.AddDecisionTaskStartedEvent(msBuilder, di.ScheduleID, tl, identity) - msBuilder.GetExecutionInfo().DecisionOriginalScheduledTimestamp = 0 - - decisions := []*types.Decision{} - - ms := execution.CreatePersistenceMutableState(msBuilder) - gwmsResponse := &persistence.GetWorkflowExecutionResponse{State: ms} - - s.mockExecutionMgr.On("GetWorkflowExecution", mock.Anything, mock.Anything).Return(gwmsResponse, nil).Once() - s.mockHistoryV2Mgr.On("AppendHistoryNodes", mock.Anything, mock.Anything).Return(&persistence.AppendHistoryNodesResponse{}, nil).Once() - s.mockExecutionMgr.On("UpdateWorkflowExecution", mock.Anything, mock.Anything).Return(&persistence.UpdateWorkflowExecutionResponse{MutableStateUpdateSessionStats: &persistence.MutableStateUpdateSessionStats{}}, nil).Once() - - _, err := s.mockHistoryEngine.RespondDecisionTaskCompleted(context.Background(), &types.HistoryRespondDecisionTaskCompletedRequest{ - DomainUUID: constants.TestDomainID, - CompleteRequest: &types.RespondDecisionTaskCompletedRequest{ - ForceCreateNewDecisionTask: true, - TaskToken: taskToken, - Decisions: decisions, - ExecutionContext: executionContext, - Identity: identity, - }, - }) - s.Nil(err) -} - -func (s *engineSuite) TestRespondDecisionTaskCompletedCompleteWorkflowSuccess() { - - we := types.WorkflowExecution{ - WorkflowID: "wId", - RunID: constants.TestRunID, - } - tl := "testTaskList" - taskToken, _ := json.Marshal(&common.TaskToken{ - WorkflowID: we.WorkflowID, - RunID: we.RunID, - ScheduleID: 2, - }) - identity := "testIdentity" - executionContext := []byte("context") - workflowResult := []byte("success") - - msBuilder := execution.NewMutableStateBuilderWithEventV2( - s.mockHistoryEngine.shard, - testlogger.New(s.Suite.T()), - we.GetRunID(), - constants.TestLocalDomainEntry, - ) - test.AddWorkflowExecutionStartedEvent(msBuilder, we, "wType", tl, []byte("input"), 100, 200, identity) - di := test.AddDecisionTaskScheduledEvent(msBuilder) - test.AddDecisionTaskStartedEvent(msBuilder, di.ScheduleID, tl, identity) - - decisions := []*types.Decision{{ - DecisionType: types.DecisionTypeCompleteWorkflowExecution.Ptr(), - CompleteWorkflowExecutionDecisionAttributes: &types.CompleteWorkflowExecutionDecisionAttributes{ - Result: workflowResult, - }, - }} - - ms := execution.CreatePersistenceMutableState(msBuilder) - gwmsResponse := &persistence.GetWorkflowExecutionResponse{State: ms} - - s.mockExecutionMgr.On("GetWorkflowExecution", mock.Anything, mock.Anything).Return(gwmsResponse, nil).Once() - s.mockHistoryV2Mgr.On("AppendHistoryNodes", mock.Anything, mock.Anything).Return(&persistence.AppendHistoryNodesResponse{}, nil).Once() - s.mockExecutionMgr.On("UpdateWorkflowExecution", mock.Anything, mock.Anything).Return(&persistence.UpdateWorkflowExecutionResponse{MutableStateUpdateSessionStats: &persistence.MutableStateUpdateSessionStats{}}, nil).Once() - - _, err := s.mockHistoryEngine.RespondDecisionTaskCompleted(context.Background(), &types.HistoryRespondDecisionTaskCompletedRequest{ - DomainUUID: constants.TestDomainID, - CompleteRequest: &types.RespondDecisionTaskCompletedRequest{ - TaskToken: taskToken, - Decisions: decisions, - ExecutionContext: executionContext, - Identity: identity, - }, - }) - s.Nil(err, s.printHistory(msBuilder)) - executionBuilder := s.getBuilder(constants.TestDomainID, we) - s.Equal(int64(6), executionBuilder.GetExecutionInfo().NextEventID) - s.Equal(int64(3), executionBuilder.GetExecutionInfo().LastProcessedEvent) - s.Equal(executionContext, executionBuilder.GetExecutionInfo().ExecutionContext) - s.Equal(persistence.WorkflowStateCompleted, executionBuilder.GetExecutionInfo().State) - s.False(executionBuilder.HasPendingDecision()) -} - -func (s *engineSuite) TestRespondDecisionTaskCompletedFailWorkflowSuccess() { - - we := types.WorkflowExecution{ - WorkflowID: "wId", - RunID: constants.TestRunID, - } - tl := "testTaskList" - taskToken, _ := json.Marshal(&common.TaskToken{ - WorkflowID: we.WorkflowID, - RunID: we.RunID, - ScheduleID: 2, - }) - identity := "testIdentity" - executionContext := []byte("context") - details := []byte("fail workflow details") - reason := "fail workflow reason" - - msBuilder := execution.NewMutableStateBuilderWithEventV2( - s.mockHistoryEngine.shard, - testlogger.New(s.Suite.T()), - we.GetRunID(), - constants.TestLocalDomainEntry, - ) - test.AddWorkflowExecutionStartedEvent(msBuilder, we, "wType", tl, []byte("input"), 100, 200, identity) - di := test.AddDecisionTaskScheduledEvent(msBuilder) - test.AddDecisionTaskStartedEvent(msBuilder, di.ScheduleID, tl, identity) - - decisions := []*types.Decision{{ - DecisionType: types.DecisionTypeFailWorkflowExecution.Ptr(), - FailWorkflowExecutionDecisionAttributes: &types.FailWorkflowExecutionDecisionAttributes{ - Reason: &reason, - Details: details, - }, - }} - - ms := execution.CreatePersistenceMutableState(msBuilder) - gwmsResponse := &persistence.GetWorkflowExecutionResponse{State: ms} - - s.mockExecutionMgr.On("GetWorkflowExecution", mock.Anything, mock.Anything).Return(gwmsResponse, nil).Once() - s.mockHistoryV2Mgr.On("AppendHistoryNodes", mock.Anything, mock.Anything).Return(&persistence.AppendHistoryNodesResponse{}, nil).Once() - s.mockExecutionMgr.On("UpdateWorkflowExecution", mock.Anything, mock.Anything).Return(&persistence.UpdateWorkflowExecutionResponse{MutableStateUpdateSessionStats: &persistence.MutableStateUpdateSessionStats{}}, nil).Once() - - _, err := s.mockHistoryEngine.RespondDecisionTaskCompleted(context.Background(), &types.HistoryRespondDecisionTaskCompletedRequest{ - DomainUUID: constants.TestDomainID, - CompleteRequest: &types.RespondDecisionTaskCompletedRequest{ - TaskToken: taskToken, - Decisions: decisions, - ExecutionContext: executionContext, - Identity: identity, - }, - }) - s.Nil(err, s.printHistory(msBuilder)) - executionBuilder := s.getBuilder(constants.TestDomainID, we) - s.Equal(int64(6), executionBuilder.GetExecutionInfo().NextEventID) - s.Equal(int64(3), executionBuilder.GetExecutionInfo().LastProcessedEvent) - s.Equal(executionContext, executionBuilder.GetExecutionInfo().ExecutionContext) - s.Equal(persistence.WorkflowStateCompleted, executionBuilder.GetExecutionInfo().State) - s.False(executionBuilder.HasPendingDecision()) -} - -func (s *engineSuite) TestRespondDecisionTaskCompletedSignalExternalWorkflowSuccess() { - - we := types.WorkflowExecution{ - WorkflowID: "wId", - RunID: constants.TestRunID, - } - tl := "testTaskList" - taskToken, _ := json.Marshal(&common.TaskToken{ - WorkflowID: we.WorkflowID, - RunID: we.RunID, - ScheduleID: 2, - }) - identity := "testIdentity" - executionContext := []byte("context") - - msBuilder := execution.NewMutableStateBuilderWithEventV2( - s.mockHistoryEngine.shard, - testlogger.New(s.Suite.T()), - we.GetRunID(), - constants.TestLocalDomainEntry, - ) - test.AddWorkflowExecutionStartedEvent(msBuilder, we, "wType", tl, []byte("input"), 100, 200, identity) - di := test.AddDecisionTaskScheduledEvent(msBuilder) - test.AddDecisionTaskStartedEvent(msBuilder, di.ScheduleID, tl, identity) - - decisions := []*types.Decision{{ - DecisionType: types.DecisionTypeSignalExternalWorkflowExecution.Ptr(), - SignalExternalWorkflowExecutionDecisionAttributes: &types.SignalExternalWorkflowExecutionDecisionAttributes{ - Domain: constants.TestDomainName, - Execution: &types.WorkflowExecution{ - WorkflowID: we.WorkflowID, - RunID: we.RunID, - }, - SignalName: "signal", - Input: []byte("test input"), - }, - }} - - ms := execution.CreatePersistenceMutableState(msBuilder) - gwmsResponse := &persistence.GetWorkflowExecutionResponse{State: ms} - - s.mockExecutionMgr.On("GetWorkflowExecution", mock.Anything, mock.Anything).Return(gwmsResponse, nil).Once() - s.mockHistoryV2Mgr.On("AppendHistoryNodes", mock.Anything, mock.Anything).Return(&persistence.AppendHistoryNodesResponse{}, nil).Once() - s.mockExecutionMgr.On("UpdateWorkflowExecution", mock.Anything, mock.Anything).Return(&persistence.UpdateWorkflowExecutionResponse{MutableStateUpdateSessionStats: &persistence.MutableStateUpdateSessionStats{}}, nil).Once() - - _, err := s.mockHistoryEngine.RespondDecisionTaskCompleted(context.Background(), &types.HistoryRespondDecisionTaskCompletedRequest{ - DomainUUID: constants.TestDomainID, - CompleteRequest: &types.RespondDecisionTaskCompletedRequest{ - TaskToken: taskToken, - Decisions: decisions, - ExecutionContext: executionContext, - Identity: identity, - }, - }) - s.Nil(err, s.printHistory(msBuilder)) - executionBuilder := s.getBuilder(constants.TestDomainID, we) - s.Equal(int64(6), executionBuilder.GetExecutionInfo().NextEventID) - s.Equal(int64(3), executionBuilder.GetExecutionInfo().LastProcessedEvent) - s.Equal(executionContext, executionBuilder.GetExecutionInfo().ExecutionContext) -} - -func (s *engineSuite) TestRespondDecisionTaskCompletedStartChildWorkflowWithAbandonPolicy() { - - we := types.WorkflowExecution{ - WorkflowID: "wId", - RunID: constants.TestRunID, - } - tl := "testTaskList" - taskToken, _ := json.Marshal(&common.TaskToken{ - WorkflowID: we.WorkflowID, - RunID: we.RunID, - ScheduleID: 2, - }) - identity := "testIdentity" - executionContext := []byte("context") - - msBuilder := execution.NewMutableStateBuilderWithEventV2( - s.mockHistoryEngine.shard, - testlogger.New(s.Suite.T()), - we.GetRunID(), - constants.TestLocalDomainEntry, - ) - test.AddWorkflowExecutionStartedEvent(msBuilder, we, "wType", tl, []byte("input"), 100, 200, identity) - di := test.AddDecisionTaskScheduledEvent(msBuilder) - test.AddDecisionTaskStartedEvent(msBuilder, di.ScheduleID, tl, identity) - - abandon := types.ParentClosePolicyAbandon - decisions := []*types.Decision{{ - DecisionType: types.DecisionTypeStartChildWorkflowExecution.Ptr(), - StartChildWorkflowExecutionDecisionAttributes: &types.StartChildWorkflowExecutionDecisionAttributes{ - Domain: constants.TestDomainName, - WorkflowID: "child-workflow-id", - WorkflowType: &types.WorkflowType{ - Name: "child-workflow-type", - }, - ParentClosePolicy: &abandon, - }, - }} - - ms := execution.CreatePersistenceMutableState(msBuilder) - gwmsResponse := &persistence.GetWorkflowExecutionResponse{State: ms} - - s.mockExecutionMgr.On("GetWorkflowExecution", mock.Anything, mock.Anything).Return(gwmsResponse, nil).Once() - s.mockHistoryV2Mgr.On("AppendHistoryNodes", mock.Anything, mock.Anything).Return(&persistence.AppendHistoryNodesResponse{}, nil).Once() - s.mockExecutionMgr.On("UpdateWorkflowExecution", mock.Anything, mock.Anything).Return(&persistence.UpdateWorkflowExecutionResponse{MutableStateUpdateSessionStats: &persistence.MutableStateUpdateSessionStats{}}, nil).Once() - - _, err := s.mockHistoryEngine.RespondDecisionTaskCompleted(context.Background(), &types.HistoryRespondDecisionTaskCompletedRequest{ - DomainUUID: constants.TestDomainID, - CompleteRequest: &types.RespondDecisionTaskCompletedRequest{ - TaskToken: taskToken, - Decisions: decisions, - ExecutionContext: executionContext, - Identity: identity, - }, - }) - s.Nil(err, s.printHistory(msBuilder)) - executionBuilder := s.getBuilder(constants.TestDomainID, we) - s.Equal(int64(6), executionBuilder.GetExecutionInfo().NextEventID) - s.Equal(int64(3), executionBuilder.GetExecutionInfo().LastProcessedEvent) - s.Equal(executionContext, executionBuilder.GetExecutionInfo().ExecutionContext) - s.Equal(int(1), len(executionBuilder.GetPendingChildExecutionInfos())) - var childID int64 - for c := range executionBuilder.GetPendingChildExecutionInfos() { - childID = c - break - } - s.Equal("child-workflow-id", executionBuilder.GetPendingChildExecutionInfos()[childID].StartedWorkflowID) - s.Equal(types.ParentClosePolicyAbandon, executionBuilder.GetPendingChildExecutionInfos()[childID].ParentClosePolicy) -} - -func (s *engineSuite) TestRespondDecisionTaskCompletedStartChildWorkflowWithTerminatePolicy() { - - we := types.WorkflowExecution{ - WorkflowID: "wId", - RunID: constants.TestRunID, - } - tl := "testTaskList" - taskToken, _ := json.Marshal(&common.TaskToken{ - WorkflowID: we.WorkflowID, - RunID: we.RunID, - ScheduleID: 2, - }) - identity := "testIdentity" - executionContext := []byte("context") - - msBuilder := execution.NewMutableStateBuilderWithEventV2( - s.mockHistoryEngine.shard, - testlogger.New(s.Suite.T()), - we.GetRunID(), - constants.TestLocalDomainEntry, - ) - test.AddWorkflowExecutionStartedEvent(msBuilder, we, "wType", tl, []byte("input"), 100, 200, identity) - di := test.AddDecisionTaskScheduledEvent(msBuilder) - test.AddDecisionTaskStartedEvent(msBuilder, di.ScheduleID, tl, identity) - - terminate := types.ParentClosePolicyTerminate - decisions := []*types.Decision{{ - DecisionType: types.DecisionTypeStartChildWorkflowExecution.Ptr(), - StartChildWorkflowExecutionDecisionAttributes: &types.StartChildWorkflowExecutionDecisionAttributes{ - Domain: constants.TestDomainName, - WorkflowID: "child-workflow-id", - WorkflowType: &types.WorkflowType{ - Name: "child-workflow-type", - }, - ParentClosePolicy: &terminate, - }, - }} - - ms := execution.CreatePersistenceMutableState(msBuilder) - gwmsResponse := &persistence.GetWorkflowExecutionResponse{State: ms} - - s.mockExecutionMgr.On("GetWorkflowExecution", mock.Anything, mock.Anything).Return(gwmsResponse, nil).Once() - s.mockHistoryV2Mgr.On("AppendHistoryNodes", mock.Anything, mock.Anything).Return(&persistence.AppendHistoryNodesResponse{}, nil).Once() - s.mockExecutionMgr.On("UpdateWorkflowExecution", mock.Anything, mock.Anything).Return(&persistence.UpdateWorkflowExecutionResponse{MutableStateUpdateSessionStats: &persistence.MutableStateUpdateSessionStats{}}, nil).Once() - - _, err := s.mockHistoryEngine.RespondDecisionTaskCompleted(context.Background(), &types.HistoryRespondDecisionTaskCompletedRequest{ - DomainUUID: constants.TestDomainID, - CompleteRequest: &types.RespondDecisionTaskCompletedRequest{ - TaskToken: taskToken, - Decisions: decisions, - ExecutionContext: executionContext, - Identity: identity, - }, - }) - s.Nil(err, s.printHistory(msBuilder)) - executionBuilder := s.getBuilder(constants.TestDomainID, we) - s.Equal(int64(6), executionBuilder.GetExecutionInfo().NextEventID) - s.Equal(int64(3), executionBuilder.GetExecutionInfo().LastProcessedEvent) - s.Equal(executionContext, executionBuilder.GetExecutionInfo().ExecutionContext) - s.Equal(int(1), len(executionBuilder.GetPendingChildExecutionInfos())) - var childID int64 - for c := range executionBuilder.GetPendingChildExecutionInfos() { - childID = c - break - } - s.Equal("child-workflow-id", executionBuilder.GetPendingChildExecutionInfos()[childID].StartedWorkflowID) - s.Equal(types.ParentClosePolicyTerminate, executionBuilder.GetPendingChildExecutionInfos()[childID].ParentClosePolicy) -} - -func (s *engineSuite) TestRespondDecisionTaskCompletedSignalExternalWorkflowFailed() { - - we := types.WorkflowExecution{ - WorkflowID: "wId", - RunID: "invalid run id", - } - tl := "testTaskList" - taskToken, _ := json.Marshal(&common.TaskToken{ - WorkflowID: we.GetWorkflowID(), - RunID: we.GetRunID(), - ScheduleID: 2, - }) - identity := "testIdentity" - executionContext := []byte("context") - - msBuilder := execution.NewMutableStateBuilderWithEventV2( - s.mockHistoryEngine.shard, - testlogger.New(s.Suite.T()), - we.GetRunID(), - constants.TestLocalDomainEntry, - ) - test.AddWorkflowExecutionStartedEvent(msBuilder, we, "wType", tl, []byte("input"), 100, 200, identity) - di := test.AddDecisionTaskScheduledEvent(msBuilder) - test.AddDecisionTaskStartedEvent(msBuilder, di.ScheduleID, tl, identity) - - decisions := []*types.Decision{{ - DecisionType: types.DecisionTypeSignalExternalWorkflowExecution.Ptr(), - SignalExternalWorkflowExecutionDecisionAttributes: &types.SignalExternalWorkflowExecutionDecisionAttributes{ - Domain: constants.TestDomainID, - Execution: &types.WorkflowExecution{ - WorkflowID: we.WorkflowID, - RunID: we.RunID, - }, - SignalName: "signal", - Input: []byte("test input"), - }, - }} - - _, err := s.mockHistoryEngine.RespondDecisionTaskCompleted(context.Background(), &types.HistoryRespondDecisionTaskCompletedRequest{ - DomainUUID: constants.TestDomainID, - CompleteRequest: &types.RespondDecisionTaskCompletedRequest{ - TaskToken: taskToken, - Decisions: decisions, - ExecutionContext: executionContext, - Identity: identity, - }, - }) - - s.EqualError(err, "RunID is not valid UUID.") -} - -func (s *engineSuite) TestRespondDecisionTaskCompletedSignalExternalWorkflowFailed_UnKnownDomain() { - - we := types.WorkflowExecution{ - WorkflowID: "wId", - RunID: constants.TestRunID, - } - tl := "testTaskList" - taskToken, _ := json.Marshal(&common.TaskToken{ - WorkflowID: we.WorkflowID, - RunID: we.RunID, - ScheduleID: 2, - }) - identity := "testIdentity" - executionContext := []byte("context") - foreignDomain := "unknown domain" - - msBuilder := execution.NewMutableStateBuilderWithEventV2( - s.mockHistoryEngine.shard, - testlogger.New(s.Suite.T()), - we.GetRunID(), - constants.TestLocalDomainEntry, - ) - test.AddWorkflowExecutionStartedEvent(msBuilder, we, "wType", tl, []byte("input"), 100, 200, identity) - di := test.AddDecisionTaskScheduledEvent(msBuilder) - test.AddDecisionTaskStartedEvent(msBuilder, di.ScheduleID, tl, identity) - - decisions := []*types.Decision{{ - DecisionType: types.DecisionTypeSignalExternalWorkflowExecution.Ptr(), - SignalExternalWorkflowExecutionDecisionAttributes: &types.SignalExternalWorkflowExecutionDecisionAttributes{ - Domain: foreignDomain, - Execution: &types.WorkflowExecution{ - WorkflowID: we.WorkflowID, - RunID: we.RunID, - }, - SignalName: "signal", - Input: []byte("test input"), - }, - }} - - ms := execution.CreatePersistenceMutableState(msBuilder) - gwmsResponse := &persistence.GetWorkflowExecutionResponse{State: ms} - - s.mockExecutionMgr.On("GetWorkflowExecution", mock.Anything, mock.Anything).Return(gwmsResponse, nil).Once() - s.mockDomainCache.EXPECT().GetDomain(foreignDomain).Return( - nil, errors.New("get foreign domain error"), - ).Times(1) - - _, err := s.mockHistoryEngine.RespondDecisionTaskCompleted(context.Background(), &types.HistoryRespondDecisionTaskCompletedRequest{ - DomainUUID: constants.TestDomainID, - CompleteRequest: &types.RespondDecisionTaskCompletedRequest{ - TaskToken: taskToken, - Decisions: decisions, - ExecutionContext: executionContext, - Identity: identity, - }, - }) - - s.NotNil(err) -} - -func (s *engineSuite) TestRespondActivityTaskCompletedInvalidToken() { - - invalidToken, _ := json.Marshal("bad token") - identity := "testIdentity" - - err := s.mockHistoryEngine.RespondActivityTaskCompleted(context.Background(), &types.HistoryRespondActivityTaskCompletedRequest{ - DomainUUID: constants.TestDomainID, - CompleteRequest: &types.RespondActivityTaskCompletedRequest{ - TaskToken: invalidToken, - Result: nil, - Identity: identity, - }, - }) - - s.NotNil(err) - s.IsType(&types.BadRequestError{}, err) -} - -func (s *engineSuite) TestRespondActivityTaskCompletedIfNoExecution() { - - taskToken, _ := json.Marshal(&common.TaskToken{ - WorkflowID: "wId", - RunID: constants.TestRunID, - ScheduleID: 2, - }) - identity := "testIdentity" - - s.mockExecutionMgr.On("GetWorkflowExecution", mock.Anything, mock.Anything).Return(nil, &types.EntityNotExistsError{}).Once() - - err := s.mockHistoryEngine.RespondActivityTaskCompleted(context.Background(), &types.HistoryRespondActivityTaskCompletedRequest{ - DomainUUID: constants.TestDomainID, - CompleteRequest: &types.RespondActivityTaskCompletedRequest{ - TaskToken: taskToken, - Identity: identity, - }, - }) - s.NotNil(err) - s.IsType(&types.EntityNotExistsError{}, err) -} - -func (s *engineSuite) TestRespondActivityTaskCompletedIfNoRunID() { - - taskToken, _ := json.Marshal(&common.TaskToken{ - WorkflowID: "wId", - ScheduleID: 2, - }) - identity := "testIdentity" - - s.mockExecutionMgr.On("GetCurrentExecution", mock.Anything, mock.Anything).Return(nil, &types.EntityNotExistsError{}).Once() - - err := s.mockHistoryEngine.RespondActivityTaskCompleted(context.Background(), &types.HistoryRespondActivityTaskCompletedRequest{ - DomainUUID: constants.TestDomainID, - CompleteRequest: &types.RespondActivityTaskCompletedRequest{ - TaskToken: taskToken, - Identity: identity, - }, - }) - s.NotNil(err) - s.IsType(&types.EntityNotExistsError{}, err) -} - -func (s *engineSuite) TestRespondActivityTaskCompletedIfGetExecutionFailed() { - - taskToken, _ := json.Marshal(&common.TaskToken{ - WorkflowID: "wId", - RunID: constants.TestRunID, - ScheduleID: 2, - }) - identity := "testIdentity" - - s.mockExecutionMgr.On("GetWorkflowExecution", mock.Anything, mock.Anything).Return(nil, errors.New("FAILED")).Once() - - err := s.mockHistoryEngine.RespondActivityTaskCompleted(context.Background(), &types.HistoryRespondActivityTaskCompletedRequest{ - DomainUUID: constants.TestDomainID, - CompleteRequest: &types.RespondActivityTaskCompletedRequest{ - TaskToken: taskToken, - Identity: identity, - }, - }) - s.EqualError(err, "FAILED") -} - -func (s *engineSuite) TestRespondActivityTaskCompletedIfNoAIdProvided() { - - workflowExecution := types.WorkflowExecution{ - WorkflowID: "wId", - RunID: constants.TestRunID, - } - tasklist := "testTaskList" - identity := "testIdentity" - taskToken, _ := json.Marshal(&common.TaskToken{ - WorkflowID: "wId", - ScheduleID: common.EmptyEventID, - }) - - msBuilder := execution.NewMutableStateBuilderWithEventV2( - s.mockHistoryEngine.shard, - testlogger.New(s.Suite.T()), - constants.TestRunID, - constants.TestLocalDomainEntry, - ) - test.AddWorkflowExecutionStartedEvent(msBuilder, workflowExecution, "wType", tasklist, []byte("input"), 100, 200, identity) - test.AddDecisionTaskScheduledEvent(msBuilder) - ms := execution.CreatePersistenceMutableState(msBuilder) - gwmsResponse := &persistence.GetWorkflowExecutionResponse{State: ms} - gceResponse := &persistence.GetCurrentExecutionResponse{RunID: constants.TestRunID} - - s.mockExecutionMgr.On("GetCurrentExecution", mock.Anything, mock.Anything).Return(gceResponse, nil).Once() - s.mockExecutionMgr.On("GetWorkflowExecution", mock.Anything, mock.Anything).Return(gwmsResponse, nil).Once() - - err := s.mockHistoryEngine.RespondActivityTaskCompleted(context.Background(), &types.HistoryRespondActivityTaskCompletedRequest{ - DomainUUID: constants.TestDomainID, - CompleteRequest: &types.RespondActivityTaskCompletedRequest{ - TaskToken: taskToken, - Identity: identity, - }, - }) - s.EqualError(err, "Neither ActivityID nor ScheduleID is provided") -} - -func (s *engineSuite) TestRespondActivityTaskCompletedIfNotFound() { - - taskToken, _ := json.Marshal(&common.TaskToken{ - WorkflowID: "wId", - ScheduleID: common.EmptyEventID, - ActivityID: "aid", - }) - workflowExecution := types.WorkflowExecution{ - WorkflowID: "wId", - RunID: constants.TestRunID, - } - tasklist := "testTaskList" - identity := "testIdentity" - - msBuilder := execution.NewMutableStateBuilderWithEventV2( - s.mockHistoryEngine.shard, - testlogger.New(s.Suite.T()), - constants.TestRunID, - constants.TestLocalDomainEntry, - ) - test.AddWorkflowExecutionStartedEvent(msBuilder, workflowExecution, "wType", tasklist, []byte("input"), 100, 200, identity) - test.AddDecisionTaskScheduledEvent(msBuilder) - ms := execution.CreatePersistenceMutableState(msBuilder) - gwmsResponse := &persistence.GetWorkflowExecutionResponse{State: ms} - gceResponse := &persistence.GetCurrentExecutionResponse{RunID: constants.TestRunID} - - s.mockExecutionMgr.On("GetCurrentExecution", mock.Anything, mock.Anything).Return(gceResponse, nil).Once() - s.mockExecutionMgr.On("GetWorkflowExecution", mock.Anything, mock.Anything).Return(gwmsResponse, nil).Once() - - err := s.mockHistoryEngine.RespondActivityTaskCompleted(context.Background(), &types.HistoryRespondActivityTaskCompletedRequest{ - DomainUUID: constants.TestDomainID, - CompleteRequest: &types.RespondActivityTaskCompletedRequest{ - TaskToken: taskToken, - Identity: identity, - }, - }) - s.Error(err) -} - -func (s *engineSuite) TestRespondActivityTaskCompletedUpdateExecutionFailed() { - - we := types.WorkflowExecution{ - WorkflowID: "wId", - RunID: constants.TestRunID, - } - tl := "testTaskList" - taskToken, _ := json.Marshal(&common.TaskToken{ - WorkflowID: we.WorkflowID, - RunID: we.RunID, - ScheduleID: 5, - }) - identity := "testIdentity" - activityID := "activity1_id" - activityType := "activity_type1" - activityInput := []byte("input1") - activityResult := []byte("activity result") - - msBuilder := execution.NewMutableStateBuilderWithEventV2( - s.mockHistoryEngine.shard, - testlogger.New(s.Suite.T()), - we.GetRunID(), - constants.TestLocalDomainEntry, - ) - test.AddWorkflowExecutionStartedEvent(msBuilder, we, "wType", tl, []byte("input"), 100, 200, identity) - di := test.AddDecisionTaskScheduledEvent(msBuilder) - decisionStartedEvent := test.AddDecisionTaskStartedEvent(msBuilder, di.ScheduleID, tl, identity) - decisionCompletedEvent := test.AddDecisionTaskCompletedEvent(msBuilder, di.ScheduleID, - decisionStartedEvent.ID, nil, identity) - activityScheduledEvent, _ := test.AddActivityTaskScheduledEvent(msBuilder, decisionCompletedEvent.ID, activityID, - activityType, tl, activityInput, 100, 10, 1, 5) - test.AddActivityTaskStartedEvent(msBuilder, activityScheduledEvent.ID, identity) - - ms := execution.CreatePersistenceMutableState(msBuilder) - gwmsResponse := &persistence.GetWorkflowExecutionResponse{State: ms} - - s.mockExecutionMgr.On("GetWorkflowExecution", mock.Anything, mock.Anything).Return(gwmsResponse, nil).Once() - s.mockHistoryV2Mgr.On("AppendHistoryNodes", mock.Anything, mock.Anything).Return(&persistence.AppendHistoryNodesResponse{}, nil).Once() - s.mockExecutionMgr.On("UpdateWorkflowExecution", mock.Anything, mock.Anything).Return(&persistence.UpdateWorkflowExecutionResponse{MutableStateUpdateSessionStats: &persistence.MutableStateUpdateSessionStats{}}, errors.New("FAILED")).Once() - s.mockShardManager.On("UpdateShard", mock.Anything, mock.Anything).Return(nil).Once() - - err := s.mockHistoryEngine.RespondActivityTaskCompleted(context.Background(), &types.HistoryRespondActivityTaskCompletedRequest{ - DomainUUID: constants.TestDomainID, - CompleteRequest: &types.RespondActivityTaskCompletedRequest{ - TaskToken: taskToken, - Result: activityResult, - Identity: identity, - }, - }) - s.EqualError(err, "FAILED") -} - -func (s *engineSuite) TestRespondActivityTaskCompletedIfTaskCompleted() { - - we := types.WorkflowExecution{ - WorkflowID: "wId", - RunID: constants.TestRunID, - } - tl := "testTaskList" - taskToken, _ := json.Marshal(&common.TaskToken{ - WorkflowID: we.WorkflowID, - RunID: we.RunID, - ScheduleID: 5, - }) - identity := "testIdentity" - activityID := "activity1_id" - activityType := "activity_type1" - activityInput := []byte("input1") - activityResult := []byte("activity result") - - msBuilder := execution.NewMutableStateBuilderWithEventV2( - s.mockHistoryEngine.shard, - testlogger.New(s.Suite.T()), - we.GetRunID(), - constants.TestLocalDomainEntry, - ) - test.AddWorkflowExecutionStartedEvent(msBuilder, we, "wType", tl, []byte("input"), 100, 200, identity) - di := test.AddDecisionTaskScheduledEvent(msBuilder) - decisionStartedEvent := test.AddDecisionTaskStartedEvent(msBuilder, di.ScheduleID, tl, identity) - decisionCompletedEvent := test.AddDecisionTaskCompletedEvent(msBuilder, di.ScheduleID, - decisionStartedEvent.ID, nil, identity) - activityScheduledEvent, _ := test.AddActivityTaskScheduledEvent(msBuilder, decisionCompletedEvent.ID, activityID, - activityType, tl, activityInput, 100, 10, 1, 5) - activityStartedEvent := test.AddActivityTaskStartedEvent(msBuilder, activityScheduledEvent.ID, identity) - test.AddActivityTaskCompletedEvent(msBuilder, activityScheduledEvent.ID, activityStartedEvent.ID, - activityResult, identity) - test.AddDecisionTaskScheduledEvent(msBuilder) - - ms := execution.CreatePersistenceMutableState(msBuilder) - gwmsResponse := &persistence.GetWorkflowExecutionResponse{State: ms} - - s.mockExecutionMgr.On("GetWorkflowExecution", mock.Anything, mock.Anything).Return(gwmsResponse, nil).Once() - - err := s.mockHistoryEngine.RespondActivityTaskCompleted(context.Background(), &types.HistoryRespondActivityTaskCompletedRequest{ - DomainUUID: constants.TestDomainID, - CompleteRequest: &types.RespondActivityTaskCompletedRequest{ - TaskToken: taskToken, - Result: activityResult, - Identity: identity, - }, - }) - s.NotNil(err) - s.IsType(&types.EntityNotExistsError{}, err) -} - -func (s *engineSuite) TestRespondActivityTaskCompletedIfTaskNotStarted() { - - we := types.WorkflowExecution{ - WorkflowID: "wId", - RunID: constants.TestRunID, - } - tl := "testTaskList" - taskToken, _ := json.Marshal(&common.TaskToken{ - WorkflowID: we.WorkflowID, - RunID: we.RunID, - ScheduleID: 5, - }) - identity := "testIdentity" - activityID := "activity1_id" - activityType := "activity_type1" - activityInput := []byte("input1") - activityResult := []byte("activity result") - - msBuilder := execution.NewMutableStateBuilderWithEventV2( - s.mockHistoryEngine.shard, - testlogger.New(s.Suite.T()), - we.GetRunID(), - constants.TestLocalDomainEntry, - ) - test.AddWorkflowExecutionStartedEvent(msBuilder, we, "wType", tl, []byte("input"), 100, 200, identity) - di := test.AddDecisionTaskScheduledEvent(msBuilder) - decisionStartedEvent := test.AddDecisionTaskStartedEvent(msBuilder, di.ScheduleID, tl, identity) - decisionCompletedEvent := test.AddDecisionTaskCompletedEvent(msBuilder, di.ScheduleID, - decisionStartedEvent.ID, nil, identity) - test.AddActivityTaskScheduledEvent(msBuilder, decisionCompletedEvent.ID, activityID, - activityType, tl, activityInput, 100, 10, 1, 5) - - ms := execution.CreatePersistenceMutableState(msBuilder) - gwmsResponse := &persistence.GetWorkflowExecutionResponse{State: ms} - - s.mockExecutionMgr.On("GetWorkflowExecution", mock.Anything, mock.Anything).Return(gwmsResponse, nil).Once() - - err := s.mockHistoryEngine.RespondActivityTaskCompleted(context.Background(), &types.HistoryRespondActivityTaskCompletedRequest{ - DomainUUID: constants.TestDomainID, - CompleteRequest: &types.RespondActivityTaskCompletedRequest{ - TaskToken: taskToken, - Result: activityResult, - Identity: identity, - }, - }) - s.NotNil(err) - s.IsType(&types.EntityNotExistsError{}, err) -} - -func (s *engineSuite) TestRespondActivityTaskCompletedConflictOnUpdate() { - - we := types.WorkflowExecution{ - WorkflowID: "wId", - RunID: constants.TestRunID, - } - tl := "testTaskList" - taskToken, _ := json.Marshal(&common.TaskToken{ - WorkflowID: we.WorkflowID, - RunID: we.RunID, - ScheduleID: 5, - }) - identity := "testIdentity" - activity1ID := "activity1" - activity1Type := "activity_type1" - activity1Input := []byte("input1") - activity1Result := []byte("activity1_result") - activity2ID := "activity2" - activity2Type := "activity_type2" - activity2Input := []byte("input2") - - msBuilder := execution.NewMutableStateBuilderWithEventV2( - s.mockHistoryEngine.shard, - testlogger.New(s.Suite.T()), - we.GetRunID(), - constants.TestLocalDomainEntry, - ) - test.AddWorkflowExecutionStartedEvent(msBuilder, we, "wType", tl, []byte("input"), 100, 100, identity) - di := test.AddDecisionTaskScheduledEvent(msBuilder) - decisionStartedEvent1 := test.AddDecisionTaskStartedEvent(msBuilder, di.ScheduleID, tl, identity) - decisionCompletedEvent1 := test.AddDecisionTaskCompletedEvent(msBuilder, di.ScheduleID, - decisionStartedEvent1.ID, nil, identity) - activity1ScheduledEvent, _ := test.AddActivityTaskScheduledEvent(msBuilder, decisionCompletedEvent1.ID, activity1ID, - activity1Type, tl, activity1Input, 100, 10, 1, 5) - activity2ScheduledEvent, _ := test.AddActivityTaskScheduledEvent(msBuilder, decisionCompletedEvent1.ID, activity2ID, - activity2Type, tl, activity2Input, 100, 10, 1, 5) - test.AddActivityTaskStartedEvent(msBuilder, activity1ScheduledEvent.ID, identity) - test.AddActivityTaskStartedEvent(msBuilder, activity2ScheduledEvent.ID, identity) - - ms1 := execution.CreatePersistenceMutableState(msBuilder) - gwmsResponse1 := &persistence.GetWorkflowExecutionResponse{State: ms1} - - ms2 := execution.CreatePersistenceMutableState(msBuilder) - gwmsResponse2 := &persistence.GetWorkflowExecutionResponse{State: ms2} - - s.mockExecutionMgr.On("GetWorkflowExecution", mock.Anything, mock.Anything).Return(gwmsResponse1, nil).Once() - s.mockHistoryV2Mgr.On("AppendHistoryNodes", mock.Anything, mock.Anything).Return(&persistence.AppendHistoryNodesResponse{}, nil).Once() - s.mockExecutionMgr.On("UpdateWorkflowExecution", mock.Anything, mock.Anything).Return(&persistence.UpdateWorkflowExecutionResponse{MutableStateUpdateSessionStats: &persistence.MutableStateUpdateSessionStats{}}, &persistence.ConditionFailedError{}).Once() - - s.mockExecutionMgr.On("GetWorkflowExecution", mock.Anything, mock.Anything).Return(gwmsResponse2, nil).Once() - s.mockHistoryV2Mgr.On("AppendHistoryNodes", mock.Anything, mock.Anything).Return(&persistence.AppendHistoryNodesResponse{}, nil).Once() - s.mockExecutionMgr.On("UpdateWorkflowExecution", mock.Anything, mock.Anything).Return(&persistence.UpdateWorkflowExecutionResponse{MutableStateUpdateSessionStats: &persistence.MutableStateUpdateSessionStats{}}, nil).Once() - - err := s.mockHistoryEngine.RespondActivityTaskCompleted(context.Background(), &types.HistoryRespondActivityTaskCompletedRequest{ - DomainUUID: constants.TestDomainID, - CompleteRequest: &types.RespondActivityTaskCompletedRequest{ - TaskToken: taskToken, - Result: activity1Result, - Identity: identity, - }, - }) - s.Nil(err, s.printHistory(msBuilder)) - executionBuilder := s.getBuilder(constants.TestDomainID, we) - s.Equal(int64(11), executionBuilder.GetExecutionInfo().NextEventID) - s.Equal(int64(3), executionBuilder.GetExecutionInfo().LastProcessedEvent) - s.Equal(persistence.WorkflowStateRunning, executionBuilder.GetExecutionInfo().State) - - s.True(executionBuilder.HasPendingDecision()) - di, ok := executionBuilder.GetDecisionInfo(int64(10)) - s.True(ok) - s.Equal(int32(100), di.DecisionTimeout) - s.Equal(int64(10), di.ScheduleID) - s.Equal(common.EmptyEventID, di.StartedID) -} - -func (s *engineSuite) TestRespondActivityTaskCompletedMaxAttemptsExceeded() { - - we := types.WorkflowExecution{ - WorkflowID: "wId", - RunID: constants.TestRunID, - } - tl := "testTaskList" - taskToken, _ := json.Marshal(&common.TaskToken{ - WorkflowID: we.WorkflowID, - RunID: we.RunID, - ScheduleID: 5, - }) - identity := "testIdentity" - activityID := "activity1_id" - activityType := "activity_type1" - activityInput := []byte("input1") - activityResult := []byte("activity result") - - msBuilder := execution.NewMutableStateBuilderWithEventV2( - s.mockHistoryEngine.shard, - testlogger.New(s.Suite.T()), - we.GetRunID(), - constants.TestLocalDomainEntry, - ) - test.AddWorkflowExecutionStartedEvent(msBuilder, we, "wType", tl, []byte("input"), 100, 100, identity) - di := test.AddDecisionTaskScheduledEvent(msBuilder) - decisionStartedEvent := test.AddDecisionTaskStartedEvent(msBuilder, di.ScheduleID, tl, identity) - decisionCompletedEvent := test.AddDecisionTaskCompletedEvent(msBuilder, di.ScheduleID, - decisionStartedEvent.ID, nil, identity) - activityScheduledEvent, _ := test.AddActivityTaskScheduledEvent(msBuilder, decisionCompletedEvent.ID, activityID, - activityType, tl, activityInput, 100, 10, 1, 5) - test.AddActivityTaskStartedEvent(msBuilder, activityScheduledEvent.ID, identity) - - for i := 0; i < workflow.ConditionalRetryCount; i++ { - ms := execution.CreatePersistenceMutableState(msBuilder) - gwmsResponse := &persistence.GetWorkflowExecutionResponse{State: ms} - - s.mockExecutionMgr.On("GetWorkflowExecution", mock.Anything, mock.Anything).Return(gwmsResponse, nil).Once() - s.mockHistoryV2Mgr.On("AppendHistoryNodes", mock.Anything, mock.Anything).Return(&persistence.AppendHistoryNodesResponse{}, nil).Once() - s.mockExecutionMgr.On("UpdateWorkflowExecution", mock.Anything, mock.Anything).Return(&persistence.UpdateWorkflowExecutionResponse{MutableStateUpdateSessionStats: &persistence.MutableStateUpdateSessionStats{}}, &persistence.ConditionFailedError{}).Once() - } - - err := s.mockHistoryEngine.RespondActivityTaskCompleted(context.Background(), &types.HistoryRespondActivityTaskCompletedRequest{ - DomainUUID: constants.TestDomainID, - CompleteRequest: &types.RespondActivityTaskCompletedRequest{ - TaskToken: taskToken, - Result: activityResult, - Identity: identity, - }, - }) - s.Equal(workflow.ErrMaxAttemptsExceeded, err) -} - -func (s *engineSuite) TestRespondActivityTaskCompletedSuccess() { - - we := types.WorkflowExecution{ - WorkflowID: "wId", - RunID: constants.TestRunID, - } - tl := "testTaskList" - taskToken, _ := json.Marshal(&common.TaskToken{ - WorkflowID: we.WorkflowID, - RunID: we.RunID, - ScheduleID: 5, - }) - identity := "testIdentity" - activityID := "activity1_id" - activityType := "activity_type1" - activityInput := []byte("input1") - activityResult := []byte("activity result") - - msBuilder := execution.NewMutableStateBuilderWithEventV2( - s.mockHistoryEngine.shard, - testlogger.New(s.Suite.T()), - we.GetRunID(), - constants.TestLocalDomainEntry, - ) - test.AddWorkflowExecutionStartedEvent(msBuilder, we, "wType", tl, []byte("input"), 100, 100, identity) - di := test.AddDecisionTaskScheduledEvent(msBuilder) - decisionStartedEvent := test.AddDecisionTaskStartedEvent(msBuilder, di.ScheduleID, tl, identity) - decisionCompletedEvent := test.AddDecisionTaskCompletedEvent(msBuilder, di.ScheduleID, - decisionStartedEvent.ID, nil, identity) - activityScheduledEvent, _ := test.AddActivityTaskScheduledEvent(msBuilder, decisionCompletedEvent.ID, activityID, - activityType, tl, activityInput, 100, 10, 1, 5) - test.AddActivityTaskStartedEvent(msBuilder, activityScheduledEvent.ID, identity) - - ms := execution.CreatePersistenceMutableState(msBuilder) - gwmsResponse := &persistence.GetWorkflowExecutionResponse{State: ms} - - s.mockExecutionMgr.On("GetWorkflowExecution", mock.Anything, mock.Anything).Return(gwmsResponse, nil).Once() - s.mockHistoryV2Mgr.On("AppendHistoryNodes", mock.Anything, mock.Anything).Return(&persistence.AppendHistoryNodesResponse{}, nil).Once() - s.mockExecutionMgr.On("UpdateWorkflowExecution", mock.Anything, mock.Anything).Return(&persistence.UpdateWorkflowExecutionResponse{MutableStateUpdateSessionStats: &persistence.MutableStateUpdateSessionStats{}}, nil).Once() - - err := s.mockHistoryEngine.RespondActivityTaskCompleted(context.Background(), &types.HistoryRespondActivityTaskCompletedRequest{ - DomainUUID: constants.TestDomainID, - CompleteRequest: &types.RespondActivityTaskCompletedRequest{ - TaskToken: taskToken, - Result: activityResult, - Identity: identity, - }, - }) - s.Nil(err, s.printHistory(msBuilder)) - executionBuilder := s.getBuilder(constants.TestDomainID, we) - s.Equal(int64(9), executionBuilder.GetExecutionInfo().NextEventID) - s.Equal(int64(3), executionBuilder.GetExecutionInfo().LastProcessedEvent) - s.Equal(persistence.WorkflowStateRunning, executionBuilder.GetExecutionInfo().State) - - s.True(executionBuilder.HasPendingDecision()) - di, ok := executionBuilder.GetDecisionInfo(int64(8)) - s.True(ok) - s.Equal(int32(100), di.DecisionTimeout) - s.Equal(int64(8), di.ScheduleID) - s.Equal(common.EmptyEventID, di.StartedID) -} - -func (s *engineSuite) TestRespondActivityTaskCompletedByIdSuccess() { - - we := types.WorkflowExecution{ - WorkflowID: "wId", - RunID: constants.TestRunID, - } - tl := "testTaskList" - - identity := "testIdentity" - activityID := "activity1_id" - activityType := "activity_type1" - activityInput := []byte("input1") - activityResult := []byte("activity result") - taskToken, _ := json.Marshal(&common.TaskToken{ - WorkflowID: we.WorkflowID, - ScheduleID: common.EmptyEventID, - ActivityID: activityID, - }) - - msBuilder := execution.NewMutableStateBuilderWithEventV2( - s.mockHistoryEngine.shard, - testlogger.New(s.Suite.T()), - we.GetRunID(), - constants.TestLocalDomainEntry, - ) - test.AddWorkflowExecutionStartedEvent(msBuilder, we, "wType", tl, []byte("input"), 100, 100, identity) - decisionScheduledEvent := test.AddDecisionTaskScheduledEvent(msBuilder) - decisionStartedEvent := test.AddDecisionTaskStartedEvent(msBuilder, decisionScheduledEvent.ScheduleID, tl, identity) - decisionCompletedEvent := test.AddDecisionTaskCompletedEvent(msBuilder, decisionScheduledEvent.ScheduleID, - decisionStartedEvent.ID, nil, identity) - activityScheduledEvent, _ := test.AddActivityTaskScheduledEvent(msBuilder, decisionCompletedEvent.ID, activityID, - activityType, tl, activityInput, 100, 10, 1, 5) - test.AddActivityTaskStartedEvent(msBuilder, activityScheduledEvent.ID, identity) - - ms := execution.CreatePersistenceMutableState(msBuilder) - gwmsResponse := &persistence.GetWorkflowExecutionResponse{State: ms} - gceResponse := &persistence.GetCurrentExecutionResponse{RunID: we.RunID} - - s.mockExecutionMgr.On("GetCurrentExecution", mock.Anything, mock.Anything).Return(gceResponse, nil).Once() - s.mockExecutionMgr.On("GetWorkflowExecution", mock.Anything, mock.Anything).Return(gwmsResponse, nil).Once() - s.mockHistoryV2Mgr.On("AppendHistoryNodes", mock.Anything, mock.Anything).Return(&persistence.AppendHistoryNodesResponse{}, nil).Once() - s.mockExecutionMgr.On("UpdateWorkflowExecution", mock.Anything, mock.Anything).Return(&persistence.UpdateWorkflowExecutionResponse{MutableStateUpdateSessionStats: &persistence.MutableStateUpdateSessionStats{}}, nil).Once() - - err := s.mockHistoryEngine.RespondActivityTaskCompleted(context.Background(), &types.HistoryRespondActivityTaskCompletedRequest{ - DomainUUID: constants.TestDomainID, - CompleteRequest: &types.RespondActivityTaskCompletedRequest{ - TaskToken: taskToken, - Result: activityResult, - Identity: identity, - }, - }) - s.Nil(err, s.printHistory(msBuilder)) - executionBuilder := s.getBuilder(constants.TestDomainID, we) - s.Equal(int64(9), executionBuilder.GetExecutionInfo().NextEventID) - s.Equal(int64(3), executionBuilder.GetExecutionInfo().LastProcessedEvent) - s.Equal(persistence.WorkflowStateRunning, executionBuilder.GetExecutionInfo().State) - - s.True(executionBuilder.HasPendingDecision()) - di, ok := executionBuilder.GetDecisionInfo(int64(8)) - s.True(ok) - s.Equal(int32(100), di.DecisionTimeout) - s.Equal(int64(8), di.ScheduleID) - s.Equal(common.EmptyEventID, di.StartedID) -} - -func (s *engineSuite) TestRespondActivityTaskFailedInvalidToken() { - - invalidToken, _ := json.Marshal("bad token") - identity := "testIdentity" - - err := s.mockHistoryEngine.RespondActivityTaskFailed(context.Background(), &types.HistoryRespondActivityTaskFailedRequest{ - DomainUUID: constants.TestDomainID, - FailedRequest: &types.RespondActivityTaskFailedRequest{ - TaskToken: invalidToken, - Identity: identity, - }, - }) - - s.NotNil(err) - s.IsType(&types.BadRequestError{}, err) -} - -func (s *engineSuite) TestRespondActivityTaskFailedIfNoExecution() { - - taskToken, _ := json.Marshal(&common.TaskToken{ - WorkflowID: "wId", - RunID: constants.TestRunID, - ScheduleID: 2, - }) - identity := "testIdentity" - - s.mockExecutionMgr.On("GetWorkflowExecution", mock.Anything, mock.Anything).Return(nil, - &types.EntityNotExistsError{}).Once() - - err := s.mockHistoryEngine.RespondActivityTaskFailed(context.Background(), &types.HistoryRespondActivityTaskFailedRequest{ - DomainUUID: constants.TestDomainID, - FailedRequest: &types.RespondActivityTaskFailedRequest{ - TaskToken: taskToken, - Identity: identity, - }, - }) - s.NotNil(err) - s.IsType(&types.EntityNotExistsError{}, err) -} - -func (s *engineSuite) TestRespondActivityTaskFailedIfNoRunID() { - - taskToken, _ := json.Marshal(&common.TaskToken{ - WorkflowID: "wId", - ScheduleID: 2, - }) - identity := "testIdentity" - - s.mockExecutionMgr.On("GetCurrentExecution", mock.Anything, mock.Anything).Return(nil, - &types.EntityNotExistsError{}).Once() - - err := s.mockHistoryEngine.RespondActivityTaskFailed(context.Background(), &types.HistoryRespondActivityTaskFailedRequest{ - DomainUUID: constants.TestDomainID, - FailedRequest: &types.RespondActivityTaskFailedRequest{ - TaskToken: taskToken, - Identity: identity, - }, - }) - s.NotNil(err) - s.IsType(&types.EntityNotExistsError{}, err) -} - -func (s *engineSuite) TestRespondActivityTaskFailedIfGetExecutionFailed() { - - taskToken, _ := json.Marshal(&common.TaskToken{ - WorkflowID: "wId", - RunID: constants.TestRunID, - ScheduleID: 2, - }) - identity := "testIdentity" - - s.mockExecutionMgr.On("GetWorkflowExecution", mock.Anything, mock.Anything).Return(nil, - errors.New("FAILED")).Once() - - err := s.mockHistoryEngine.RespondActivityTaskFailed(context.Background(), &types.HistoryRespondActivityTaskFailedRequest{ - DomainUUID: constants.TestDomainID, - FailedRequest: &types.RespondActivityTaskFailedRequest{ - TaskToken: taskToken, - Identity: identity, - }, - }) - s.EqualError(err, "FAILED") -} - -func (s *engineSuite) TestRespondActivityTaskFailededIfNoAIdProvided() { - - taskToken, _ := json.Marshal(&common.TaskToken{ - WorkflowID: "wId", - ScheduleID: common.EmptyEventID, - }) - workflowExecution := types.WorkflowExecution{ - WorkflowID: "wId", - RunID: constants.TestRunID, - } - tasklist := "testTaskList" - identity := "testIdentity" - - msBuilder := execution.NewMutableStateBuilderWithEventV2( - s.mockHistoryEngine.shard, - testlogger.New(s.Suite.T()), - constants.TestRunID, - constants.TestLocalDomainEntry, - ) - test.AddWorkflowExecutionStartedEvent(msBuilder, workflowExecution, "wType", tasklist, []byte("input"), 100, 200, identity) - test.AddDecisionTaskScheduledEvent(msBuilder) - ms := execution.CreatePersistenceMutableState(msBuilder) - gwmsResponse := &persistence.GetWorkflowExecutionResponse{State: ms} - gceResponse := &persistence.GetCurrentExecutionResponse{RunID: constants.TestRunID} - - s.mockExecutionMgr.On("GetCurrentExecution", mock.Anything, mock.Anything).Return(gceResponse, nil).Once() - s.mockExecutionMgr.On("GetWorkflowExecution", mock.Anything, mock.Anything).Return(gwmsResponse, nil).Once() - - err := s.mockHistoryEngine.RespondActivityTaskFailed(context.Background(), &types.HistoryRespondActivityTaskFailedRequest{ - DomainUUID: constants.TestDomainID, - FailedRequest: &types.RespondActivityTaskFailedRequest{ - TaskToken: taskToken, - Identity: identity, - }, - }) - s.EqualError(err, "Neither ActivityID nor ScheduleID is provided") -} - -func (s *engineSuite) TestRespondActivityTaskFailededIfNotFound() { - - taskToken, _ := json.Marshal(&common.TaskToken{ - WorkflowID: "wId", - ScheduleID: common.EmptyEventID, - ActivityID: "aid", - }) - workflowExecution := types.WorkflowExecution{ - WorkflowID: "wId", - RunID: constants.TestRunID, - } - tasklist := "testTaskList" - identity := "testIdentity" - - msBuilder := execution.NewMutableStateBuilderWithEventV2( - s.mockHistoryEngine.shard, - testlogger.New(s.Suite.T()), - constants.TestRunID, - constants.TestLocalDomainEntry, - ) - test.AddWorkflowExecutionStartedEvent(msBuilder, workflowExecution, "wType", tasklist, []byte("input"), 100, 200, identity) - test.AddDecisionTaskScheduledEvent(msBuilder) - ms := execution.CreatePersistenceMutableState(msBuilder) - gwmsResponse := &persistence.GetWorkflowExecutionResponse{State: ms} - gceResponse := &persistence.GetCurrentExecutionResponse{RunID: constants.TestRunID} - - s.mockExecutionMgr.On("GetCurrentExecution", mock.Anything, mock.Anything).Return(gceResponse, nil).Once() - s.mockExecutionMgr.On("GetWorkflowExecution", mock.Anything, mock.Anything).Return(gwmsResponse, nil).Once() - - err := s.mockHistoryEngine.RespondActivityTaskFailed(context.Background(), &types.HistoryRespondActivityTaskFailedRequest{ - DomainUUID: constants.TestDomainID, - FailedRequest: &types.RespondActivityTaskFailedRequest{ - TaskToken: taskToken, - Identity: identity, - }, - }) - s.Error(err) -} - -func (s *engineSuite) TestRespondActivityTaskFailedUpdateExecutionFailed() { - - we := types.WorkflowExecution{ - WorkflowID: "wId", - RunID: constants.TestRunID, - } - tl := "testTaskList" - taskToken, _ := json.Marshal(&common.TaskToken{ - WorkflowID: we.WorkflowID, - RunID: we.RunID, - ScheduleID: 5, - }) - identity := "testIdentity" - activityID := "activity1_id" - activityType := "activity_type1" - activityInput := []byte("input1") - - msBuilder := execution.NewMutableStateBuilderWithEventV2( - s.mockHistoryEngine.shard, - testlogger.New(s.Suite.T()), - we.GetRunID(), - constants.TestLocalDomainEntry, - ) - test.AddWorkflowExecutionStartedEvent(msBuilder, we, "wType", tl, []byte("input"), 100, 100, identity) - di := test.AddDecisionTaskScheduledEvent(msBuilder) - decisionStartedEvent := test.AddDecisionTaskStartedEvent(msBuilder, di.ScheduleID, tl, identity) - decisionCompletedEvent := test.AddDecisionTaskCompletedEvent(msBuilder, di.ScheduleID, - decisionStartedEvent.ID, nil, identity) - activityScheduledEvent, _ := test.AddActivityTaskScheduledEvent(msBuilder, decisionCompletedEvent.ID, activityID, - activityType, tl, activityInput, 100, 10, 1, 5) - test.AddActivityTaskStartedEvent(msBuilder, activityScheduledEvent.ID, identity) - - ms := execution.CreatePersistenceMutableState(msBuilder) - gwmsResponse := &persistence.GetWorkflowExecutionResponse{State: ms} - - s.mockExecutionMgr.On("GetWorkflowExecution", mock.Anything, mock.Anything).Return(gwmsResponse, nil).Once() - s.mockHistoryV2Mgr.On("AppendHistoryNodes", mock.Anything, mock.Anything).Return(&persistence.AppendHistoryNodesResponse{}, nil).Once() - s.mockExecutionMgr.On("UpdateWorkflowExecution", mock.Anything, mock.Anything).Return(&persistence.UpdateWorkflowExecutionResponse{MutableStateUpdateSessionStats: &persistence.MutableStateUpdateSessionStats{}}, errors.New("FAILED")).Once() - s.mockShardManager.On("UpdateShard", mock.Anything, mock.Anything).Return(nil).Once() - - err := s.mockHistoryEngine.RespondActivityTaskFailed(context.Background(), &types.HistoryRespondActivityTaskFailedRequest{ - DomainUUID: constants.TestDomainID, - FailedRequest: &types.RespondActivityTaskFailedRequest{ - TaskToken: taskToken, - Identity: identity, - }, - }) - s.EqualError(err, "FAILED") -} - -func (s *engineSuite) TestRespondActivityTaskFailedIfTaskCompleted() { - - we := types.WorkflowExecution{ - WorkflowID: "wId", - RunID: constants.TestRunID, - } - tl := "testTaskList" - taskToken, _ := json.Marshal(&common.TaskToken{ - WorkflowID: we.WorkflowID, - RunID: we.RunID, - ScheduleID: 5, - }) - identity := "testIdentity" - activityID := "activity1_id" - activityType := "activity_type1" - activityInput := []byte("input1") - failReason := "fail reason" - details := []byte("fail details") - - msBuilder := execution.NewMutableStateBuilderWithEventV2( - s.mockHistoryEngine.shard, - testlogger.New(s.Suite.T()), - we.GetRunID(), - constants.TestLocalDomainEntry, - ) - test.AddWorkflowExecutionStartedEvent(msBuilder, we, "wType", tl, []byte("input"), 100, 100, identity) - di := test.AddDecisionTaskScheduledEvent(msBuilder) - decisionStartedEvent := test.AddDecisionTaskStartedEvent(msBuilder, di.ScheduleID, tl, identity) - decisionCompletedEvent := test.AddDecisionTaskCompletedEvent(msBuilder, di.ScheduleID, - decisionStartedEvent.ID, nil, identity) - activityScheduledEvent, _ := test.AddActivityTaskScheduledEvent(msBuilder, decisionCompletedEvent.ID, activityID, - activityType, tl, activityInput, 100, 10, 1, 5) - activityStartedEvent := test.AddActivityTaskStartedEvent(msBuilder, activityScheduledEvent.ID, identity) - test.AddActivityTaskFailedEvent(msBuilder, activityScheduledEvent.ID, activityStartedEvent.ID, - failReason, details, identity) - test.AddDecisionTaskScheduledEvent(msBuilder) - - ms := execution.CreatePersistenceMutableState(msBuilder) - gwmsResponse := &persistence.GetWorkflowExecutionResponse{State: ms} - - s.mockExecutionMgr.On("GetWorkflowExecution", mock.Anything, mock.Anything).Return(gwmsResponse, nil).Once() - - err := s.mockHistoryEngine.RespondActivityTaskFailed(context.Background(), &types.HistoryRespondActivityTaskFailedRequest{ - DomainUUID: constants.TestDomainID, - FailedRequest: &types.RespondActivityTaskFailedRequest{ - TaskToken: taskToken, - Reason: &failReason, - Details: details, - Identity: identity, - }, - }) - s.NotNil(err) - s.IsType(&types.EntityNotExistsError{}, err) -} - -func (s *engineSuite) TestRespondActivityTaskFailedIfTaskNotStarted() { - - we := types.WorkflowExecution{ - WorkflowID: "wId", - RunID: constants.TestRunID, - } - tl := "testTaskList" - taskToken, _ := json.Marshal(&common.TaskToken{ - WorkflowID: we.WorkflowID, - RunID: we.RunID, - ScheduleID: 5, - }) - identity := "testIdentity" - activityID := "activity1_id" - activityType := "activity_type1" - activityInput := []byte("input1") - - msBuilder := execution.NewMutableStateBuilderWithEventV2( - s.mockHistoryEngine.shard, - testlogger.New(s.Suite.T()), - we.GetRunID(), - constants.TestLocalDomainEntry, - ) - test.AddWorkflowExecutionStartedEvent(msBuilder, we, "wType", tl, []byte("input"), 100, 100, identity) - di := test.AddDecisionTaskScheduledEvent(msBuilder) - decisionStartedEvent := test.AddDecisionTaskStartedEvent(msBuilder, di.ScheduleID, tl, identity) - decisionCompletedEvent := test.AddDecisionTaskCompletedEvent(msBuilder, di.ScheduleID, - decisionStartedEvent.ID, nil, identity) - test.AddActivityTaskScheduledEvent(msBuilder, decisionCompletedEvent.ID, activityID, - activityType, tl, activityInput, 100, 10, 1, 5) - - ms := execution.CreatePersistenceMutableState(msBuilder) - gwmsResponse := &persistence.GetWorkflowExecutionResponse{State: ms} - - s.mockExecutionMgr.On("GetWorkflowExecution", mock.Anything, mock.Anything).Return(gwmsResponse, nil).Once() - - err := s.mockHistoryEngine.RespondActivityTaskFailed(context.Background(), &types.HistoryRespondActivityTaskFailedRequest{ - DomainUUID: constants.TestDomainID, - FailedRequest: &types.RespondActivityTaskFailedRequest{ - TaskToken: taskToken, - Identity: identity, - }, - }) - s.NotNil(err) - s.IsType(&types.EntityNotExistsError{}, err) -} - -func (s *engineSuite) TestRespondActivityTaskFailedConflictOnUpdate() { - - we := types.WorkflowExecution{ - WorkflowID: "wId", - RunID: constants.TestRunID, - } - tl := "testTaskList" - taskToken, _ := json.Marshal(&common.TaskToken{ - WorkflowID: we.WorkflowID, - RunID: we.RunID, - ScheduleID: 5, - }) - identity := "testIdentity" - activity1ID := "activity1" - activity1Type := "activity_type1" - activity1Input := []byte("input1") - failReason := "fail reason" - details := []byte("fail details.") - activity2ID := "activity2" - activity2Type := "activity_type2" - activity2Input := []byte("input2") - activity2Result := []byte("activity2_result") - - msBuilder := execution.NewMutableStateBuilderWithEventV2( - s.mockHistoryEngine.shard, - testlogger.New(s.Suite.T()), - we.GetRunID(), - constants.TestLocalDomainEntry, - ) - test.AddWorkflowExecutionStartedEvent(msBuilder, we, "wType", tl, []byte("input"), 25, 25, identity) - di1 := test.AddDecisionTaskScheduledEvent(msBuilder) - decisionStartedEvent1 := test.AddDecisionTaskStartedEvent(msBuilder, di1.ScheduleID, tl, identity) - decisionCompletedEvent1 := test.AddDecisionTaskCompletedEvent(msBuilder, di1.ScheduleID, - decisionStartedEvent1.ID, nil, identity) - activity1ScheduledEvent, _ := test.AddActivityTaskScheduledEvent(msBuilder, decisionCompletedEvent1.ID, activity1ID, - activity1Type, tl, activity1Input, 100, 10, 1, 5) - activity2ScheduledEvent, _ := test.AddActivityTaskScheduledEvent(msBuilder, decisionCompletedEvent1.ID, activity2ID, - activity2Type, tl, activity2Input, 100, 10, 1, 5) - test.AddActivityTaskStartedEvent(msBuilder, activity1ScheduledEvent.ID, identity) - activity2StartedEvent := test.AddActivityTaskStartedEvent(msBuilder, activity2ScheduledEvent.ID, identity) - - ms1 := execution.CreatePersistenceMutableState(msBuilder) - gwmsResponse1 := &persistence.GetWorkflowExecutionResponse{State: ms1} - - test.AddActivityTaskCompletedEvent(msBuilder, activity2ScheduledEvent.ID, - activity2StartedEvent.ID, activity2Result, identity) - test.AddDecisionTaskScheduledEvent(msBuilder) - - ms2 := execution.CreatePersistenceMutableState(msBuilder) - gwmsResponse2 := &persistence.GetWorkflowExecutionResponse{State: ms2} - - s.mockExecutionMgr.On("GetWorkflowExecution", mock.Anything, mock.Anything).Return(gwmsResponse1, nil).Once() - s.mockHistoryV2Mgr.On("AppendHistoryNodes", mock.Anything, mock.Anything).Return(&persistence.AppendHistoryNodesResponse{}, nil).Once() - s.mockExecutionMgr.On("UpdateWorkflowExecution", mock.Anything, mock.Anything).Return(&persistence.UpdateWorkflowExecutionResponse{MutableStateUpdateSessionStats: &persistence.MutableStateUpdateSessionStats{}}, &persistence.ConditionFailedError{}).Once() - - s.mockExecutionMgr.On("GetWorkflowExecution", mock.Anything, mock.Anything).Return(gwmsResponse2, nil).Once() - s.mockHistoryV2Mgr.On("AppendHistoryNodes", mock.Anything, mock.Anything).Return(&persistence.AppendHistoryNodesResponse{}, nil).Once() - s.mockExecutionMgr.On("UpdateWorkflowExecution", mock.Anything, mock.Anything).Return(&persistence.UpdateWorkflowExecutionResponse{MutableStateUpdateSessionStats: &persistence.MutableStateUpdateSessionStats{}}, nil).Once() - - err := s.mockHistoryEngine.RespondActivityTaskFailed(context.Background(), &types.HistoryRespondActivityTaskFailedRequest{ - DomainUUID: constants.TestDomainID, - FailedRequest: &types.RespondActivityTaskFailedRequest{ - TaskToken: taskToken, - Reason: &failReason, - Details: details, - Identity: identity, - }, - }) - s.Nil(err, s.printHistory(msBuilder)) - executionBuilder := s.getBuilder(constants.TestDomainID, we) - s.Equal(int64(12), executionBuilder.GetExecutionInfo().NextEventID) - s.Equal(int64(3), executionBuilder.GetExecutionInfo().LastProcessedEvent) - s.Equal(persistence.WorkflowStateRunning, executionBuilder.GetExecutionInfo().State) - - s.True(executionBuilder.HasPendingDecision()) - di, ok := executionBuilder.GetDecisionInfo(int64(10)) - s.True(ok) - s.Equal(int32(25), di.DecisionTimeout) - s.Equal(int64(10), di.ScheduleID) - s.Equal(common.EmptyEventID, di.StartedID) -} - -func (s *engineSuite) TestRespondActivityTaskFailedMaxAttemptsExceeded() { - - we := types.WorkflowExecution{ - WorkflowID: "wId", - RunID: constants.TestRunID, - } - tl := "testTaskList" - taskToken, _ := json.Marshal(&common.TaskToken{ - WorkflowID: we.WorkflowID, - RunID: we.RunID, - ScheduleID: 5, - }) - identity := "testIdentity" - activityID := "activity1_id" - activityType := "activity_type1" - activityInput := []byte("input1") - - msBuilder := execution.NewMutableStateBuilderWithEventV2( - s.mockHistoryEngine.shard, - testlogger.New(s.Suite.T()), - we.GetRunID(), - constants.TestLocalDomainEntry, - ) - test.AddWorkflowExecutionStartedEvent(msBuilder, we, "wType", tl, []byte("input"), 100, 100, identity) - di := test.AddDecisionTaskScheduledEvent(msBuilder) - decisionStartedEvent := test.AddDecisionTaskStartedEvent(msBuilder, di.ScheduleID, tl, identity) - decisionCompletedEvent := test.AddDecisionTaskCompletedEvent(msBuilder, di.ScheduleID, - decisionStartedEvent.ID, nil, identity) - activityScheduledEvent, _ := test.AddActivityTaskScheduledEvent(msBuilder, decisionCompletedEvent.ID, activityID, - activityType, tl, activityInput, 100, 10, 1, 5) - test.AddActivityTaskStartedEvent(msBuilder, activityScheduledEvent.ID, identity) - - for i := 0; i < workflow.ConditionalRetryCount; i++ { - ms := execution.CreatePersistenceMutableState(msBuilder) - gwmsResponse := &persistence.GetWorkflowExecutionResponse{State: ms} - - s.mockExecutionMgr.On("GetWorkflowExecution", mock.Anything, mock.Anything).Return(gwmsResponse, nil).Once() - s.mockHistoryV2Mgr.On("AppendHistoryNodes", mock.Anything, mock.Anything).Return(&persistence.AppendHistoryNodesResponse{}, nil).Once() - s.mockExecutionMgr.On("UpdateWorkflowExecution", mock.Anything, mock.Anything).Return(&persistence.UpdateWorkflowExecutionResponse{MutableStateUpdateSessionStats: &persistence.MutableStateUpdateSessionStats{}}, &persistence.ConditionFailedError{}).Once() - } - - err := s.mockHistoryEngine.RespondActivityTaskFailed(context.Background(), &types.HistoryRespondActivityTaskFailedRequest{ - DomainUUID: constants.TestDomainID, - FailedRequest: &types.RespondActivityTaskFailedRequest{ - TaskToken: taskToken, - Identity: identity, - }, - }) - s.Equal(workflow.ErrMaxAttemptsExceeded, err) -} - -func (s *engineSuite) TestRespondActivityTaskFailedSuccess() { - - we := types.WorkflowExecution{ - WorkflowID: "wId", - RunID: constants.TestRunID, - } - tl := "testTaskList" - taskToken, _ := json.Marshal(&common.TaskToken{ - WorkflowID: we.WorkflowID, - RunID: we.RunID, - ScheduleID: 5, - }) - identity := "testIdentity" - activityID := "activity1_id" - activityType := "activity_type1" - activityInput := []byte("input1") - failReason := "failed" - failDetails := []byte("fail details.") - - msBuilder := execution.NewMutableStateBuilderWithEventV2( - s.mockHistoryEngine.shard, - testlogger.New(s.Suite.T()), - we.GetRunID(), - constants.TestLocalDomainEntry, - ) - test.AddWorkflowExecutionStartedEvent(msBuilder, we, "wType", tl, []byte("input"), 100, 100, identity) - di := test.AddDecisionTaskScheduledEvent(msBuilder) - decisionStartedEvent := test.AddDecisionTaskStartedEvent(msBuilder, di.ScheduleID, tl, identity) - decisionCompletedEvent := test.AddDecisionTaskCompletedEvent(msBuilder, di.ScheduleID, - decisionStartedEvent.ID, nil, identity) - activityScheduledEvent, _ := test.AddActivityTaskScheduledEvent(msBuilder, decisionCompletedEvent.ID, activityID, - activityType, tl, activityInput, 100, 10, 1, 5) - test.AddActivityTaskStartedEvent(msBuilder, activityScheduledEvent.ID, identity) - - ms := execution.CreatePersistenceMutableState(msBuilder) - gwmsResponse := &persistence.GetWorkflowExecutionResponse{State: ms} - - s.mockExecutionMgr.On("GetWorkflowExecution", mock.Anything, mock.Anything).Return(gwmsResponse, nil).Once() - s.mockHistoryV2Mgr.On("AppendHistoryNodes", mock.Anything, mock.Anything).Return(&persistence.AppendHistoryNodesResponse{}, nil).Once() - s.mockExecutionMgr.On("UpdateWorkflowExecution", mock.Anything, mock.Anything).Return(&persistence.UpdateWorkflowExecutionResponse{MutableStateUpdateSessionStats: &persistence.MutableStateUpdateSessionStats{}}, nil).Once() - - err := s.mockHistoryEngine.RespondActivityTaskFailed(context.Background(), &types.HistoryRespondActivityTaskFailedRequest{ - DomainUUID: constants.TestDomainID, - FailedRequest: &types.RespondActivityTaskFailedRequest{ - TaskToken: taskToken, - Reason: &failReason, - Details: failDetails, - Identity: identity, - }, - }) - s.Nil(err) - executionBuilder := s.getBuilder(constants.TestDomainID, we) - s.Equal(int64(9), executionBuilder.GetExecutionInfo().NextEventID) - s.Equal(int64(3), executionBuilder.GetExecutionInfo().LastProcessedEvent) - s.Equal(persistence.WorkflowStateRunning, executionBuilder.GetExecutionInfo().State) - - s.True(executionBuilder.HasPendingDecision()) - di, ok := executionBuilder.GetDecisionInfo(int64(8)) - s.True(ok) - s.Equal(int32(100), di.DecisionTimeout) - s.Equal(int64(8), di.ScheduleID) - s.Equal(common.EmptyEventID, di.StartedID) -} - -func (s *engineSuite) TestRespondActivityTaskFailedByIDSuccess() { - - we := types.WorkflowExecution{ - WorkflowID: "wId", - RunID: constants.TestRunID, - } - tl := "testTaskList" - - identity := "testIdentity" - activityID := "activity1_id" - activityType := "activity_type1" - activityInput := []byte("input1") - failReason := "failed" - failDetails := []byte("fail details.") - taskToken, _ := json.Marshal(&common.TaskToken{ - WorkflowID: we.WorkflowID, - ScheduleID: common.EmptyEventID, - ActivityID: activityID, - }) - - msBuilder := execution.NewMutableStateBuilderWithEventV2( - s.mockHistoryEngine.shard, - testlogger.New(s.Suite.T()), - we.GetRunID(), - constants.TestLocalDomainEntry, - ) - test.AddWorkflowExecutionStartedEvent(msBuilder, we, "wType", tl, []byte("input"), 100, 100, identity) - decisionScheduledEvent := test.AddDecisionTaskScheduledEvent(msBuilder) - decisionStartedEvent := test.AddDecisionTaskStartedEvent(msBuilder, decisionScheduledEvent.ScheduleID, tl, identity) - decisionCompletedEvent := test.AddDecisionTaskCompletedEvent(msBuilder, decisionScheduledEvent.ScheduleID, - decisionStartedEvent.ID, nil, identity) - activityScheduledEvent, _ := test.AddActivityTaskScheduledEvent(msBuilder, decisionCompletedEvent.ID, activityID, - activityType, tl, activityInput, 100, 10, 1, 5) - test.AddActivityTaskStartedEvent(msBuilder, activityScheduledEvent.ID, identity) - - ms := execution.CreatePersistenceMutableState(msBuilder) - gwmsResponse := &persistence.GetWorkflowExecutionResponse{State: ms} - gceResponse := &persistence.GetCurrentExecutionResponse{RunID: we.RunID} - - s.mockExecutionMgr.On("GetCurrentExecution", mock.Anything, mock.Anything).Return(gceResponse, nil).Once() - s.mockExecutionMgr.On("GetWorkflowExecution", mock.Anything, mock.Anything).Return(gwmsResponse, nil).Once() - s.mockHistoryV2Mgr.On("AppendHistoryNodes", mock.Anything, mock.Anything).Return(&persistence.AppendHistoryNodesResponse{}, nil).Once() - s.mockExecutionMgr.On("UpdateWorkflowExecution", mock.Anything, mock.Anything).Return(&persistence.UpdateWorkflowExecutionResponse{MutableStateUpdateSessionStats: &persistence.MutableStateUpdateSessionStats{}}, nil).Once() - - err := s.mockHistoryEngine.RespondActivityTaskFailed(context.Background(), &types.HistoryRespondActivityTaskFailedRequest{ - DomainUUID: constants.TestDomainID, - FailedRequest: &types.RespondActivityTaskFailedRequest{ - TaskToken: taskToken, - Reason: &failReason, - Details: failDetails, - Identity: identity, - }, - }) - s.Nil(err) - executionBuilder := s.getBuilder(constants.TestDomainID, we) - s.Equal(int64(9), executionBuilder.GetExecutionInfo().NextEventID) - s.Equal(int64(3), executionBuilder.GetExecutionInfo().LastProcessedEvent) - s.Equal(persistence.WorkflowStateRunning, executionBuilder.GetExecutionInfo().State) - - s.True(executionBuilder.HasPendingDecision()) - di, ok := executionBuilder.GetDecisionInfo(int64(8)) - s.True(ok) - s.Equal(int32(100), di.DecisionTimeout) - s.Equal(int64(8), di.ScheduleID) - s.Equal(common.EmptyEventID, di.StartedID) -} - -func (s *engineSuite) TestRecordActivityTaskHeartBeatSuccess_NoTimer() { - - we := types.WorkflowExecution{ - WorkflowID: "wId", - RunID: constants.TestRunID, - } - tl := "testTaskList" - taskToken, _ := json.Marshal(&common.TaskToken{ - WorkflowID: we.WorkflowID, - RunID: we.RunID, - ScheduleID: 5, - }) - identity := "testIdentity" - activityID := "activity1_id" - activityType := "activity_type1" - activityInput := []byte("input1") - - msBuilder := execution.NewMutableStateBuilderWithEventV2( - s.mockHistoryEngine.shard, - testlogger.New(s.Suite.T()), - we.GetRunID(), - constants.TestLocalDomainEntry, - ) - test.AddWorkflowExecutionStartedEvent(msBuilder, we, "wType", tl, []byte("input"), 100, 100, identity) - di := test.AddDecisionTaskScheduledEvent(msBuilder) - decisionStartedEvent := test.AddDecisionTaskStartedEvent(msBuilder, di.ScheduleID, tl, identity) - decisionCompletedEvent := test.AddDecisionTaskCompletedEvent(msBuilder, di.ScheduleID, - decisionStartedEvent.ID, nil, identity) - activityScheduledEvent, _ := test.AddActivityTaskScheduledEvent(msBuilder, decisionCompletedEvent.ID, activityID, - activityType, tl, activityInput, 100, 10, 1, 0) - test.AddActivityTaskStartedEvent(msBuilder, activityScheduledEvent.ID, identity) - - // No HeartBeat timer running. - ms := execution.CreatePersistenceMutableState(msBuilder) - gwmsResponse := &persistence.GetWorkflowExecutionResponse{State: ms} - s.mockExecutionMgr.On("GetWorkflowExecution", mock.Anything, mock.Anything).Return(gwmsResponse, nil).Once() - s.mockExecutionMgr.On("UpdateWorkflowExecution", mock.Anything, mock.Anything).Return(&persistence.UpdateWorkflowExecutionResponse{MutableStateUpdateSessionStats: &persistence.MutableStateUpdateSessionStats{}}, nil).Once() - - detais := []byte("details") - - _, err := s.mockHistoryEngine.RecordActivityTaskHeartbeat(context.Background(), &types.HistoryRecordActivityTaskHeartbeatRequest{ - DomainUUID: constants.TestDomainID, - HeartbeatRequest: &types.RecordActivityTaskHeartbeatRequest{ - TaskToken: taskToken, - Identity: identity, - Details: detais, - }, - }) - s.Nil(err) -} - -func (s *engineSuite) TestRecordActivityTaskHeartBeatSuccess_TimerRunning() { - - we := types.WorkflowExecution{ - WorkflowID: "wId", - RunID: constants.TestRunID, - } - tl := "testTaskList" - taskToken, _ := json.Marshal(&common.TaskToken{ - WorkflowID: we.WorkflowID, - RunID: we.RunID, - ScheduleID: 5, - }) - identity := "testIdentity" - activityID := "activity1_id" - activityType := "activity_type1" - activityInput := []byte("input1") - - msBuilder := execution.NewMutableStateBuilderWithEventV2( - s.mockHistoryEngine.shard, - testlogger.New(s.Suite.T()), - we.GetRunID(), - constants.TestLocalDomainEntry, - ) - test.AddWorkflowExecutionStartedEvent(msBuilder, we, "wType", tl, []byte("input"), 100, 100, identity) - di := test.AddDecisionTaskScheduledEvent(msBuilder) - decisionStartedEvent := test.AddDecisionTaskStartedEvent(msBuilder, di.ScheduleID, tl, identity) - decisionCompletedEvent := test.AddDecisionTaskCompletedEvent(msBuilder, di.ScheduleID, - decisionStartedEvent.ID, nil, identity) - activityScheduledEvent, _ := test.AddActivityTaskScheduledEvent(msBuilder, decisionCompletedEvent.ID, activityID, - activityType, tl, activityInput, 100, 10, 1, 1) - test.AddActivityTaskStartedEvent(msBuilder, activityScheduledEvent.ID, identity) - - ms := execution.CreatePersistenceMutableState(msBuilder) - gwmsResponse := &persistence.GetWorkflowExecutionResponse{State: ms} - - // HeartBeat timer running. - s.mockExecutionMgr.On("GetWorkflowExecution", mock.Anything, mock.Anything).Return(gwmsResponse, nil).Once() - s.mockExecutionMgr.On("UpdateWorkflowExecution", mock.Anything, mock.Anything).Return(&persistence.UpdateWorkflowExecutionResponse{MutableStateUpdateSessionStats: &persistence.MutableStateUpdateSessionStats{}}, nil).Once() - - detais := []byte("details") - - _, err := s.mockHistoryEngine.RecordActivityTaskHeartbeat(context.Background(), &types.HistoryRecordActivityTaskHeartbeatRequest{ - DomainUUID: constants.TestDomainID, - HeartbeatRequest: &types.RecordActivityTaskHeartbeatRequest{ - TaskToken: taskToken, - Identity: identity, - Details: detais, - }, - }) - s.Nil(err) - executionBuilder := s.getBuilder(constants.TestDomainID, we) - s.Equal(int64(7), executionBuilder.GetExecutionInfo().NextEventID) - s.Equal(int64(3), executionBuilder.GetExecutionInfo().LastProcessedEvent) - s.Equal(persistence.WorkflowStateRunning, executionBuilder.GetExecutionInfo().State) - s.False(executionBuilder.HasPendingDecision()) -} - -func (s *engineSuite) TestRecordActivityTaskHeartBeatByIDSuccess() { - - we := types.WorkflowExecution{ - WorkflowID: "wId", - RunID: constants.TestRunID, - } - tl := "testTaskList" - identity := "testIdentity" - activityID := "activity1_id" - activityType := "activity_type1" - activityInput := []byte("input1") - taskToken, _ := json.Marshal(&common.TaskToken{ - WorkflowID: we.WorkflowID, - RunID: we.RunID, - ScheduleID: common.EmptyEventID, - ActivityID: activityID, - }) - - msBuilder := execution.NewMutableStateBuilderWithEventV2( - s.mockHistoryEngine.shard, - testlogger.New(s.Suite.T()), - we.GetRunID(), - constants.TestLocalDomainEntry, - ) - test.AddWorkflowExecutionStartedEvent(msBuilder, we, "wType", tl, []byte("input"), 100, 100, identity) - di := test.AddDecisionTaskScheduledEvent(msBuilder) - decisionStartedEvent := test.AddDecisionTaskStartedEvent(msBuilder, di.ScheduleID, tl, identity) - decisionCompletedEvent := test.AddDecisionTaskCompletedEvent(msBuilder, di.ScheduleID, - decisionStartedEvent.ID, nil, identity) - activityScheduledEvent, _ := test.AddActivityTaskScheduledEvent(msBuilder, decisionCompletedEvent.ID, activityID, - activityType, tl, activityInput, 100, 10, 1, 0) - test.AddActivityTaskStartedEvent(msBuilder, activityScheduledEvent.ID, identity) - - // No HeartBeat timer running. - ms := execution.CreatePersistenceMutableState(msBuilder) - gwmsResponse := &persistence.GetWorkflowExecutionResponse{State: ms} - s.mockExecutionMgr.On("GetWorkflowExecution", mock.Anything, mock.Anything).Return(gwmsResponse, nil).Once() - s.mockExecutionMgr.On("UpdateWorkflowExecution", mock.Anything, mock.Anything).Return(&persistence.UpdateWorkflowExecutionResponse{MutableStateUpdateSessionStats: &persistence.MutableStateUpdateSessionStats{}}, nil).Once() - - detais := []byte("details") - - _, err := s.mockHistoryEngine.RecordActivityTaskHeartbeat(context.Background(), &types.HistoryRecordActivityTaskHeartbeatRequest{ - DomainUUID: constants.TestDomainID, - HeartbeatRequest: &types.RecordActivityTaskHeartbeatRequest{ - TaskToken: taskToken, - Identity: identity, - Details: detais, - }, - }) - s.Nil(err) -} - -func (s *engineSuite) TestRespondActivityTaskCanceled_Scheduled() { - - we := types.WorkflowExecution{ - WorkflowID: "wId", - RunID: constants.TestRunID, - } - tl := "testTaskList" - taskToken, _ := json.Marshal(&common.TaskToken{ - WorkflowID: we.WorkflowID, - RunID: we.RunID, - ScheduleID: 5, - }) - identity := "testIdentity" - activityID := "activity1_id" - activityType := "activity_type1" - activityInput := []byte("input1") - - msBuilder := execution.NewMutableStateBuilderWithEventV2( - s.mockHistoryEngine.shard, - testlogger.New(s.Suite.T()), - we.GetRunID(), - constants.TestLocalDomainEntry, - ) - test.AddWorkflowExecutionStartedEvent(msBuilder, we, "wType", tl, []byte("input"), 100, 100, identity) - di := test.AddDecisionTaskScheduledEvent(msBuilder) - decisionStartedEvent := test.AddDecisionTaskStartedEvent(msBuilder, di.ScheduleID, tl, identity) - decisionCompletedEvent := test.AddDecisionTaskCompletedEvent(msBuilder, di.ScheduleID, - decisionStartedEvent.ID, nil, identity) - test.AddActivityTaskScheduledEvent(msBuilder, decisionCompletedEvent.ID, activityID, - activityType, tl, activityInput, 100, 10, 1, 1) - - ms := execution.CreatePersistenceMutableState(msBuilder) - gwmsResponse := &persistence.GetWorkflowExecutionResponse{State: ms} - - s.mockExecutionMgr.On("GetWorkflowExecution", mock.Anything, mock.Anything).Return(gwmsResponse, nil).Once() - - err := s.mockHistoryEngine.RespondActivityTaskCanceled(context.Background(), &types.HistoryRespondActivityTaskCanceledRequest{ - DomainUUID: constants.TestDomainID, - CancelRequest: &types.RespondActivityTaskCanceledRequest{ - TaskToken: taskToken, - Identity: identity, - Details: []byte("details"), - }, - }) - s.NotNil(err) - s.IsType(&types.EntityNotExistsError{}, err) -} - -func (s *engineSuite) TestRespondActivityTaskCanceled_Started() { - - we := types.WorkflowExecution{ - WorkflowID: "wId", - RunID: constants.TestRunID, - } - tl := "testTaskList" - taskToken, _ := json.Marshal(&common.TaskToken{ - WorkflowID: we.WorkflowID, - RunID: we.RunID, - ScheduleID: 5, - }) - identity := "testIdentity" - activityID := "activity1_id" - activityType := "activity_type1" - activityInput := []byte("input1") - - msBuilder := execution.NewMutableStateBuilderWithEventV2( - s.mockHistoryEngine.shard, - testlogger.New(s.Suite.T()), - we.GetRunID(), - constants.TestLocalDomainEntry, - ) - test.AddWorkflowExecutionStartedEvent(msBuilder, we, "wType", tl, []byte("input"), 100, 100, identity) - di := test.AddDecisionTaskScheduledEvent(msBuilder) - decisionStartedEvent := test.AddDecisionTaskStartedEvent(msBuilder, di.ScheduleID, tl, identity) - decisionCompletedEvent := test.AddDecisionTaskCompletedEvent(msBuilder, di.ScheduleID, - decisionStartedEvent.ID, nil, identity) - activityScheduledEvent, _ := test.AddActivityTaskScheduledEvent(msBuilder, decisionCompletedEvent.ID, activityID, - activityType, tl, activityInput, 100, 10, 1, 1) - test.AddActivityTaskStartedEvent(msBuilder, activityScheduledEvent.ID, identity) - _, _, err := msBuilder.AddActivityTaskCancelRequestedEvent(decisionCompletedEvent.ID, activityID, identity) - s.Nil(err) - - ms := execution.CreatePersistenceMutableState(msBuilder) - gwmsResponse := &persistence.GetWorkflowExecutionResponse{State: ms} - - s.mockExecutionMgr.On("GetWorkflowExecution", mock.Anything, mock.Anything).Return(gwmsResponse, nil).Once() - s.mockHistoryV2Mgr.On("AppendHistoryNodes", mock.Anything, mock.Anything).Return(&persistence.AppendHistoryNodesResponse{}, nil).Once() - s.mockExecutionMgr.On("UpdateWorkflowExecution", mock.Anything, mock.Anything).Return(&persistence.UpdateWorkflowExecutionResponse{MutableStateUpdateSessionStats: &persistence.MutableStateUpdateSessionStats{}}, nil).Once() - - err = s.mockHistoryEngine.RespondActivityTaskCanceled(context.Background(), &types.HistoryRespondActivityTaskCanceledRequest{ - DomainUUID: constants.TestDomainID, - CancelRequest: &types.RespondActivityTaskCanceledRequest{ - TaskToken: taskToken, - Identity: identity, - Details: []byte("details"), - }, - }) - s.Nil(err) - executionBuilder := s.getBuilder(constants.TestDomainID, we) - s.Equal(int64(10), executionBuilder.GetExecutionInfo().NextEventID) - s.Equal(int64(3), executionBuilder.GetExecutionInfo().LastProcessedEvent) - s.Equal(persistence.WorkflowStateRunning, executionBuilder.GetExecutionInfo().State) - - s.True(executionBuilder.HasPendingDecision()) - di, ok := executionBuilder.GetDecisionInfo(int64(9)) - s.True(ok) - s.Equal(int32(100), di.DecisionTimeout) - s.Equal(int64(9), di.ScheduleID) - s.Equal(common.EmptyEventID, di.StartedID) -} - -func (s *engineSuite) TestRespondActivityTaskCanceledByID_Started() { - - we := types.WorkflowExecution{ - WorkflowID: "wId", - RunID: constants.TestRunID, - } - tl := "testTaskList" - identity := "testIdentity" - activityID := "activity1_id" - activityType := "activity_type1" - activityInput := []byte("input1") - taskToken, _ := json.Marshal(&common.TaskToken{ - WorkflowID: we.WorkflowID, - ScheduleID: common.EmptyEventID, - ActivityID: activityID, - }) - - msBuilder := execution.NewMutableStateBuilderWithEventV2( - s.mockHistoryEngine.shard, - testlogger.New(s.Suite.T()), - we.GetRunID(), - constants.TestLocalDomainEntry, - ) - test.AddWorkflowExecutionStartedEvent(msBuilder, we, "wType", tl, []byte("input"), 100, 100, identity) - decisionScheduledEvent := test.AddDecisionTaskScheduledEvent(msBuilder) - decisionStartedEvent := test.AddDecisionTaskStartedEvent(msBuilder, decisionScheduledEvent.ScheduleID, tl, identity) - decisionCompletedEvent := test.AddDecisionTaskCompletedEvent(msBuilder, decisionScheduledEvent.ScheduleID, - decisionStartedEvent.ID, nil, identity) - activityScheduledEvent, _ := test.AddActivityTaskScheduledEvent(msBuilder, decisionCompletedEvent.ID, activityID, - activityType, tl, activityInput, 100, 10, 1, 1) - test.AddActivityTaskStartedEvent(msBuilder, activityScheduledEvent.ID, identity) - _, _, err := msBuilder.AddActivityTaskCancelRequestedEvent(decisionCompletedEvent.ID, activityID, identity) - s.Nil(err) - - ms := execution.CreatePersistenceMutableState(msBuilder) - gwmsResponse := &persistence.GetWorkflowExecutionResponse{State: ms} - gceResponse := &persistence.GetCurrentExecutionResponse{RunID: we.RunID} - - s.mockExecutionMgr.On("GetCurrentExecution", mock.Anything, mock.Anything).Return(gceResponse, nil).Once() - s.mockExecutionMgr.On("GetWorkflowExecution", mock.Anything, mock.Anything).Return(gwmsResponse, nil).Once() - s.mockHistoryV2Mgr.On("AppendHistoryNodes", mock.Anything, mock.Anything).Return(&persistence.AppendHistoryNodesResponse{}, nil).Once() - s.mockExecutionMgr.On("UpdateWorkflowExecution", mock.Anything, mock.Anything).Return(&persistence.UpdateWorkflowExecutionResponse{MutableStateUpdateSessionStats: &persistence.MutableStateUpdateSessionStats{}}, nil).Once() - - err = s.mockHistoryEngine.RespondActivityTaskCanceled(context.Background(), &types.HistoryRespondActivityTaskCanceledRequest{ - DomainUUID: constants.TestDomainID, - CancelRequest: &types.RespondActivityTaskCanceledRequest{ - TaskToken: taskToken, - Identity: identity, - Details: []byte("details"), - }, - }) - s.Nil(err) - executionBuilder := s.getBuilder(constants.TestDomainID, we) - s.Equal(int64(10), executionBuilder.GetExecutionInfo().NextEventID) - s.Equal(int64(3), executionBuilder.GetExecutionInfo().LastProcessedEvent) - s.Equal(persistence.WorkflowStateRunning, executionBuilder.GetExecutionInfo().State) - - s.True(executionBuilder.HasPendingDecision()) - di, ok := executionBuilder.GetDecisionInfo(int64(9)) - s.True(ok) - s.Equal(int32(100), di.DecisionTimeout) - s.Equal(int64(9), di.ScheduleID) - s.Equal(common.EmptyEventID, di.StartedID) -} - -func (s *engineSuite) TestRespondActivityTaskCanceledIfNoRunID() { - - taskToken, _ := json.Marshal(&common.TaskToken{ - WorkflowID: "wId", - ScheduleID: 2, - }) - identity := "testIdentity" - - s.mockExecutionMgr.On("GetCurrentExecution", mock.Anything, mock.Anything).Return(nil, &types.EntityNotExistsError{}).Once() - - err := s.mockHistoryEngine.RespondActivityTaskCanceled(context.Background(), &types.HistoryRespondActivityTaskCanceledRequest{ - DomainUUID: constants.TestDomainID, - CancelRequest: &types.RespondActivityTaskCanceledRequest{ - TaskToken: taskToken, - Identity: identity, - }, - }) - s.NotNil(err) - s.IsType(&types.EntityNotExistsError{}, err) -} - -func (s *engineSuite) TestRespondActivityTaskCanceledIfNoAIdProvided() { - - taskToken, _ := json.Marshal(&common.TaskToken{ - WorkflowID: "wId", - ScheduleID: common.EmptyEventID, - }) - identity := "testIdentity" - - msBuilder := execution.NewMutableStateBuilderWithEventV2( - s.mockHistoryEngine.shard, - testlogger.New(s.Suite.T()), - constants.TestRunID, - constants.TestLocalDomainEntry, - ) - ms := execution.CreatePersistenceMutableState(msBuilder) - gwmsResponse := &persistence.GetWorkflowExecutionResponse{State: ms} - gceResponse := &persistence.GetCurrentExecutionResponse{RunID: constants.TestRunID} - - s.mockExecutionMgr.On("GetCurrentExecution", mock.Anything, mock.Anything).Return(gceResponse, nil).Once() - s.mockExecutionMgr.On("GetWorkflowExecution", mock.Anything, mock.Anything).Return(gwmsResponse, nil).Once() - - err := s.mockHistoryEngine.RespondActivityTaskCanceled(context.Background(), &types.HistoryRespondActivityTaskCanceledRequest{ - DomainUUID: constants.TestDomainID, - CancelRequest: &types.RespondActivityTaskCanceledRequest{ - TaskToken: taskToken, - Identity: identity, - }, - }) - s.EqualError(err, "Neither ActivityID nor ScheduleID is provided") -} - -func (s *engineSuite) TestRespondActivityTaskCanceledIfNotFound() { - - taskToken, _ := json.Marshal(&common.TaskToken{ - WorkflowID: "wId", - ScheduleID: common.EmptyEventID, - ActivityID: "aid", - }) - identity := "testIdentity" - - msBuilder := execution.NewMutableStateBuilderWithEventV2( - s.mockHistoryEngine.shard, - testlogger.New(s.Suite.T()), - constants.TestRunID, - constants.TestLocalDomainEntry, - ) - ms := execution.CreatePersistenceMutableState(msBuilder) - gwmsResponse := &persistence.GetWorkflowExecutionResponse{State: ms} - gceResponse := &persistence.GetCurrentExecutionResponse{RunID: constants.TestRunID} - - s.mockExecutionMgr.On("GetCurrentExecution", mock.Anything, mock.Anything).Return(gceResponse, nil).Once() - s.mockExecutionMgr.On("GetWorkflowExecution", mock.Anything, mock.Anything).Return(gwmsResponse, nil).Once() - - err := s.mockHistoryEngine.RespondActivityTaskCanceled(context.Background(), &types.HistoryRespondActivityTaskCanceledRequest{ - DomainUUID: constants.TestDomainID, - CancelRequest: &types.RespondActivityTaskCanceledRequest{ - TaskToken: taskToken, - Identity: identity, - }, - }) - s.Error(err) -} - -func (s *engineSuite) TestRequestCancel_RespondDecisionTaskCompleted_NotScheduled() { - - we := types.WorkflowExecution{ - WorkflowID: "wId", - RunID: constants.TestRunID, - } - tl := "testTaskList" - taskToken, _ := json.Marshal(&common.TaskToken{ - WorkflowID: we.WorkflowID, - RunID: we.RunID, - ScheduleID: 2, - }) - identity := "testIdentity" - activityID := "activity1_id" - - msBuilder := execution.NewMutableStateBuilderWithEventV2( - s.mockHistoryEngine.shard, - testlogger.New(s.Suite.T()), - we.GetRunID(), - constants.TestLocalDomainEntry, - ) - test.AddWorkflowExecutionStartedEvent(msBuilder, we, "wType", tl, []byte("input"), 100, 100, identity) - di := test.AddDecisionTaskScheduledEvent(msBuilder) - test.AddDecisionTaskStartedEvent(msBuilder, di.ScheduleID, tl, identity) - - decisions := []*types.Decision{{ - DecisionType: types.DecisionTypeRequestCancelActivityTask.Ptr(), - RequestCancelActivityTaskDecisionAttributes: &types.RequestCancelActivityTaskDecisionAttributes{ - ActivityID: activityID, - }, - }} - - ms := execution.CreatePersistenceMutableState(msBuilder) - gwmsResponse := &persistence.GetWorkflowExecutionResponse{State: ms} - - s.mockExecutionMgr.On("GetWorkflowExecution", mock.Anything, mock.Anything).Return(gwmsResponse, nil).Once() - s.mockHistoryV2Mgr.On("AppendHistoryNodes", mock.Anything, mock.Anything).Return(&persistence.AppendHistoryNodesResponse{}, nil).Once() - s.mockExecutionMgr.On("UpdateWorkflowExecution", mock.Anything, mock.Anything).Return(&persistence.UpdateWorkflowExecutionResponse{MutableStateUpdateSessionStats: &persistence.MutableStateUpdateSessionStats{}}, nil).Once() - - _, err := s.mockHistoryEngine.RespondDecisionTaskCompleted(context.Background(), &types.HistoryRespondDecisionTaskCompletedRequest{ - DomainUUID: constants.TestDomainID, - CompleteRequest: &types.RespondDecisionTaskCompletedRequest{ - TaskToken: taskToken, - Decisions: decisions, - ExecutionContext: []byte("context"), - Identity: identity, - }, - }) - s.Nil(err) - executionBuilder := s.getBuilder(constants.TestDomainID, we) - s.Equal(int64(7), executionBuilder.GetExecutionInfo().NextEventID) - s.Equal(int64(3), executionBuilder.GetExecutionInfo().LastProcessedEvent) - s.Equal(persistence.WorkflowStateRunning, executionBuilder.GetExecutionInfo().State) - s.False(executionBuilder.HasPendingDecision()) -} - -func (s *engineSuite) TestRequestCancel_RespondDecisionTaskCompleted_Scheduled() { - - we := types.WorkflowExecution{ - WorkflowID: "wId", - RunID: constants.TestRunID, - } - tl := "testTaskList" - taskToken, _ := json.Marshal(&common.TaskToken{ - WorkflowID: we.WorkflowID, - RunID: we.RunID, - ScheduleID: 6, - }) - identity := "testIdentity" - activityID := "activity1_id" - activityType := "activity_type1" - activityInput := []byte("input1") - - msBuilder := execution.NewMutableStateBuilderWithEventV2( - s.mockHistoryEngine.shard, - testlogger.New(s.Suite.T()), - we.GetRunID(), - constants.TestLocalDomainEntry, - ) - test.AddWorkflowExecutionStartedEvent(msBuilder, we, "wType", tl, []byte("input"), 100, 100, identity) - di := test.AddDecisionTaskScheduledEvent(msBuilder) - decisionStartedEvent := test.AddDecisionTaskStartedEvent(msBuilder, di.ScheduleID, tl, identity) - decisionCompletedEvent := test.AddDecisionTaskCompletedEvent(msBuilder, di.ScheduleID, - decisionStartedEvent.ID, nil, identity) - test.AddActivityTaskScheduledEvent(msBuilder, decisionCompletedEvent.ID, activityID, - activityType, tl, activityInput, 100, 10, 1, 1) - di2 := test.AddDecisionTaskScheduledEvent(msBuilder) - test.AddDecisionTaskStartedEvent(msBuilder, di2.ScheduleID, tl, identity) - - ms := execution.CreatePersistenceMutableState(msBuilder) - gwmsResponse := &persistence.GetWorkflowExecutionResponse{State: ms} - - decisions := []*types.Decision{{ - DecisionType: types.DecisionTypeRequestCancelActivityTask.Ptr(), - RequestCancelActivityTaskDecisionAttributes: &types.RequestCancelActivityTaskDecisionAttributes{ - ActivityID: activityID, - }, - }} - - s.mockExecutionMgr.On("GetWorkflowExecution", mock.Anything, mock.Anything).Return(gwmsResponse, nil).Once() - s.mockHistoryV2Mgr.On("AppendHistoryNodes", mock.Anything, mock.Anything).Return(&persistence.AppendHistoryNodesResponse{}, nil).Once() - s.mockExecutionMgr.On("UpdateWorkflowExecution", mock.Anything, mock.Anything).Return(&persistence.UpdateWorkflowExecutionResponse{MutableStateUpdateSessionStats: &persistence.MutableStateUpdateSessionStats{}}, nil).Once() - - _, err := s.mockHistoryEngine.RespondDecisionTaskCompleted(context.Background(), &types.HistoryRespondDecisionTaskCompletedRequest{ - DomainUUID: constants.TestDomainID, - CompleteRequest: &types.RespondDecisionTaskCompletedRequest{ - TaskToken: taskToken, - Decisions: decisions, - ExecutionContext: []byte("context"), - Identity: identity, - }, - }) - s.Nil(err) - - executionBuilder := s.getBuilder(constants.TestDomainID, we) - s.Equal(int64(12), executionBuilder.GetExecutionInfo().NextEventID) - s.Equal(int64(7), executionBuilder.GetExecutionInfo().LastProcessedEvent) - s.Equal(persistence.WorkflowStateRunning, executionBuilder.GetExecutionInfo().State) - s.True(executionBuilder.HasPendingDecision()) - di2, ok := executionBuilder.GetDecisionInfo(executionBuilder.GetExecutionInfo().NextEventID - 1) - s.True(ok) - s.Equal(executionBuilder.GetExecutionInfo().NextEventID-1, di2.ScheduleID) - s.Equal(int64(0), di2.Attempt) -} - -func (s *engineSuite) TestRequestCancel_RespondDecisionTaskCompleted_Started() { - - we := types.WorkflowExecution{ - WorkflowID: "wId", - RunID: constants.TestRunID, - } - tl := "testTaskList" - taskToken, _ := json.Marshal(&common.TaskToken{ - WorkflowID: we.WorkflowID, - RunID: we.RunID, - ScheduleID: 7, - }) - identity := "testIdentity" - activityID := "activity1_id" - activityType := "activity_type1" - activityInput := []byte("input1") - - msBuilder := execution.NewMutableStateBuilderWithEventV2( - s.mockHistoryEngine.shard, - testlogger.New(s.Suite.T()), - we.GetRunID(), - constants.TestLocalDomainEntry, - ) - test.AddWorkflowExecutionStartedEvent(msBuilder, we, "wType", tl, []byte("input"), 100, 100, identity) - di := test.AddDecisionTaskScheduledEvent(msBuilder) - decisionStartedEvent := test.AddDecisionTaskStartedEvent(msBuilder, di.ScheduleID, tl, identity) - decisionCompletedEvent := test.AddDecisionTaskCompletedEvent(msBuilder, di.ScheduleID, - decisionStartedEvent.ID, nil, identity) - activityScheduledEvent, _ := test.AddActivityTaskScheduledEvent(msBuilder, decisionCompletedEvent.ID, activityID, - activityType, tl, activityInput, 100, 10, 1, 0) - test.AddActivityTaskStartedEvent(msBuilder, activityScheduledEvent.ID, identity) - di2 := test.AddDecisionTaskScheduledEvent(msBuilder) - test.AddDecisionTaskStartedEvent(msBuilder, di2.ScheduleID, tl, identity) - - ms := execution.CreatePersistenceMutableState(msBuilder) - gwmsResponse := &persistence.GetWorkflowExecutionResponse{State: ms} - - decisions := []*types.Decision{{ - DecisionType: types.DecisionTypeRequestCancelActivityTask.Ptr(), - RequestCancelActivityTaskDecisionAttributes: &types.RequestCancelActivityTaskDecisionAttributes{ - ActivityID: activityID, - }, - }} - - s.mockExecutionMgr.On("GetWorkflowExecution", mock.Anything, mock.Anything).Return(gwmsResponse, nil).Once() - s.mockHistoryV2Mgr.On("AppendHistoryNodes", mock.Anything, mock.Anything).Return(&persistence.AppendHistoryNodesResponse{}, nil).Once() - s.mockExecutionMgr.On("UpdateWorkflowExecution", mock.Anything, mock.Anything).Return(&persistence.UpdateWorkflowExecutionResponse{MutableStateUpdateSessionStats: &persistence.MutableStateUpdateSessionStats{}}, nil).Once() - - _, err := s.mockHistoryEngine.RespondDecisionTaskCompleted(context.Background(), &types.HistoryRespondDecisionTaskCompletedRequest{ - DomainUUID: constants.TestDomainID, - CompleteRequest: &types.RespondDecisionTaskCompletedRequest{ - TaskToken: taskToken, - Decisions: decisions, - ExecutionContext: []byte("context"), - Identity: identity, - }, - }) - s.Nil(err) - - executionBuilder := s.getBuilder(constants.TestDomainID, we) - s.Equal(int64(11), executionBuilder.GetExecutionInfo().NextEventID) - s.Equal(int64(8), executionBuilder.GetExecutionInfo().LastProcessedEvent) - s.Equal(persistence.WorkflowStateRunning, executionBuilder.GetExecutionInfo().State) - s.False(executionBuilder.HasPendingDecision()) -} - -func (s *engineSuite) TestRequestCancel_RespondDecisionTaskCompleted_Completed() { - - we := types.WorkflowExecution{ - WorkflowID: "wId", - RunID: constants.TestRunID, - } - tl := "testTaskList" - taskToken, _ := json.Marshal(&common.TaskToken{ - WorkflowID: we.WorkflowID, - RunID: we.RunID, - ScheduleID: 6, - }) - identity := "testIdentity" - activityID := "activity1_id" - activityType := "activity_type1" - activityInput := []byte("input1") - workflowResult := []byte("workflow result") - - msBuilder := execution.NewMutableStateBuilderWithEventV2( - s.mockHistoryEngine.shard, - testlogger.New(s.Suite.T()), - we.GetRunID(), - constants.TestLocalDomainEntry, - ) - test.AddWorkflowExecutionStartedEvent(msBuilder, we, "wType", tl, []byte("input"), 100, 100, identity) - di := test.AddDecisionTaskScheduledEvent(msBuilder) - decisionStartedEvent := test.AddDecisionTaskStartedEvent(msBuilder, di.ScheduleID, tl, identity) - decisionCompletedEvent := test.AddDecisionTaskCompletedEvent(msBuilder, di.ScheduleID, - decisionStartedEvent.ID, nil, identity) - test.AddActivityTaskScheduledEvent(msBuilder, decisionCompletedEvent.ID, activityID, - activityType, tl, activityInput, 100, 10, 1, 0) - di2 := test.AddDecisionTaskScheduledEvent(msBuilder) - test.AddDecisionTaskStartedEvent(msBuilder, di2.ScheduleID, tl, identity) - - decisions := []*types.Decision{ - { - DecisionType: types.DecisionTypeRequestCancelActivityTask.Ptr(), - RequestCancelActivityTaskDecisionAttributes: &types.RequestCancelActivityTaskDecisionAttributes{ - ActivityID: activityID, - }, - }, - { - DecisionType: types.DecisionTypeCompleteWorkflowExecution.Ptr(), - CompleteWorkflowExecutionDecisionAttributes: &types.CompleteWorkflowExecutionDecisionAttributes{ - Result: workflowResult, - }, - }, - } - - ms := execution.CreatePersistenceMutableState(msBuilder) - gwmsResponse := &persistence.GetWorkflowExecutionResponse{State: ms} - s.mockExecutionMgr.On("GetWorkflowExecution", mock.Anything, mock.Anything).Return(gwmsResponse, nil).Once() - s.mockHistoryV2Mgr.On("AppendHistoryNodes", mock.Anything, mock.Anything).Return(&persistence.AppendHistoryNodesResponse{}, nil).Once() - s.mockExecutionMgr.On("UpdateWorkflowExecution", mock.Anything, mock.Anything).Return(&persistence.UpdateWorkflowExecutionResponse{MutableStateUpdateSessionStats: &persistence.MutableStateUpdateSessionStats{}}, nil).Once() - - _, err := s.mockHistoryEngine.RespondDecisionTaskCompleted(context.Background(), &types.HistoryRespondDecisionTaskCompletedRequest{ - DomainUUID: constants.TestDomainID, - CompleteRequest: &types.RespondDecisionTaskCompletedRequest{ - TaskToken: taskToken, - Decisions: decisions, - ExecutionContext: []byte("context"), - Identity: identity, - }, - }) - s.Nil(err) - - executionBuilder := s.getBuilder(constants.TestDomainID, we) - s.Equal(int64(11), executionBuilder.GetExecutionInfo().NextEventID) - s.Equal(int64(7), executionBuilder.GetExecutionInfo().LastProcessedEvent) - s.Equal(persistence.WorkflowStateCompleted, executionBuilder.GetExecutionInfo().State) - s.False(executionBuilder.HasPendingDecision()) -} - -func (s *engineSuite) TestRequestCancel_RespondDecisionTaskCompleted_NoHeartBeat() { - - we := types.WorkflowExecution{ - WorkflowID: "wId", - RunID: constants.TestRunID, - } - tl := "testTaskList" - taskToken, _ := json.Marshal(&common.TaskToken{ - WorkflowID: we.WorkflowID, - RunID: we.RunID, - ScheduleID: 7, - }) - identity := "testIdentity" - activityID := "activity1_id" - activityType := "activity_type1" - activityInput := []byte("input1") - - msBuilder := execution.NewMutableStateBuilderWithEventV2( - s.mockHistoryEngine.shard, - testlogger.New(s.Suite.T()), - we.GetRunID(), - constants.TestLocalDomainEntry, - ) - test.AddWorkflowExecutionStartedEvent(msBuilder, we, "wType", tl, []byte("input"), 100, 100, identity) - di := test.AddDecisionTaskScheduledEvent(msBuilder) - decisionStartedEvent := test.AddDecisionTaskStartedEvent(msBuilder, di.ScheduleID, tl, identity) - decisionCompletedEvent := test.AddDecisionTaskCompletedEvent(msBuilder, di.ScheduleID, - decisionStartedEvent.ID, nil, identity) - activityScheduledEvent, _ := test.AddActivityTaskScheduledEvent(msBuilder, decisionCompletedEvent.ID, activityID, - activityType, tl, activityInput, 100, 10, 1, 0) - test.AddActivityTaskStartedEvent(msBuilder, activityScheduledEvent.ID, identity) - di2 := test.AddDecisionTaskScheduledEvent(msBuilder) - test.AddDecisionTaskStartedEvent(msBuilder, di2.ScheduleID, tl, identity) - - ms := execution.CreatePersistenceMutableState(msBuilder) - gwmsResponse := &persistence.GetWorkflowExecutionResponse{State: ms} - - decisions := []*types.Decision{{ - DecisionType: types.DecisionTypeRequestCancelActivityTask.Ptr(), - RequestCancelActivityTaskDecisionAttributes: &types.RequestCancelActivityTaskDecisionAttributes{ - ActivityID: activityID, - }, - }} - - s.mockExecutionMgr.On("GetWorkflowExecution", mock.Anything, mock.Anything).Return(gwmsResponse, nil).Once() - s.mockHistoryV2Mgr.On("AppendHistoryNodes", mock.Anything, mock.Anything).Return(&persistence.AppendHistoryNodesResponse{}, nil).Once() - s.mockExecutionMgr.On("UpdateWorkflowExecution", mock.Anything, mock.Anything).Return(&persistence.UpdateWorkflowExecutionResponse{MutableStateUpdateSessionStats: &persistence.MutableStateUpdateSessionStats{}}, nil).Once() - - _, err := s.mockHistoryEngine.RespondDecisionTaskCompleted(context.Background(), &types.HistoryRespondDecisionTaskCompletedRequest{ - DomainUUID: constants.TestDomainID, - CompleteRequest: &types.RespondDecisionTaskCompletedRequest{ - TaskToken: taskToken, - Decisions: decisions, - ExecutionContext: []byte("context"), - Identity: identity, - }, - }) - s.Nil(err) - - executionBuilder := s.getBuilder(constants.TestDomainID, we) - s.Equal(int64(11), executionBuilder.GetExecutionInfo().NextEventID) - s.Equal(int64(8), executionBuilder.GetExecutionInfo().LastProcessedEvent) - s.Equal(persistence.WorkflowStateRunning, executionBuilder.GetExecutionInfo().State) - s.False(executionBuilder.HasPendingDecision()) - - // Try recording activity heartbeat - s.mockExecutionMgr.On("UpdateWorkflowExecution", mock.Anything, mock.Anything).Return(&persistence.UpdateWorkflowExecutionResponse{MutableStateUpdateSessionStats: &persistence.MutableStateUpdateSessionStats{}}, nil).Once() - - activityTaskToken, _ := json.Marshal(&common.TaskToken{ - WorkflowID: "wId", - RunID: we.GetRunID(), - ScheduleID: 5, - }) - - hbResponse, err := s.mockHistoryEngine.RecordActivityTaskHeartbeat(context.Background(), &types.HistoryRecordActivityTaskHeartbeatRequest{ - DomainUUID: constants.TestDomainID, - HeartbeatRequest: &types.RecordActivityTaskHeartbeatRequest{ - TaskToken: activityTaskToken, - Identity: identity, - Details: []byte("details"), - }, - }) - s.Nil(err) - s.NotNil(hbResponse) - s.True(hbResponse.CancelRequested) - - // Try cancelling the request. - s.mockHistoryV2Mgr.On("AppendHistoryNodes", mock.Anything, mock.Anything).Return(&persistence.AppendHistoryNodesResponse{}, nil).Once() - s.mockExecutionMgr.On("UpdateWorkflowExecution", mock.Anything, mock.Anything).Return(&persistence.UpdateWorkflowExecutionResponse{MutableStateUpdateSessionStats: &persistence.MutableStateUpdateSessionStats{}}, nil).Once() - - err = s.mockHistoryEngine.RespondActivityTaskCanceled(context.Background(), &types.HistoryRespondActivityTaskCanceledRequest{ - DomainUUID: constants.TestDomainID, - CancelRequest: &types.RespondActivityTaskCanceledRequest{ - TaskToken: activityTaskToken, - Identity: identity, - Details: []byte("details"), - }, - }) - s.Nil(err) - - executionBuilder = s.getBuilder(constants.TestDomainID, we) - s.Equal(int64(13), executionBuilder.GetExecutionInfo().NextEventID) - s.Equal(int64(8), executionBuilder.GetExecutionInfo().LastProcessedEvent) - s.Equal(persistence.WorkflowStateRunning, executionBuilder.GetExecutionInfo().State) - s.True(executionBuilder.HasPendingDecision()) -} - -func (s *engineSuite) TestRequestCancel_RespondDecisionTaskCompleted_Success() { - - we := types.WorkflowExecution{ - WorkflowID: "wId", - RunID: constants.TestRunID, - } - tl := "testTaskList" - taskToken, _ := json.Marshal(&common.TaskToken{ - WorkflowID: we.WorkflowID, - RunID: we.RunID, - ScheduleID: 7, - }) - identity := "testIdentity" - activityID := "activity1_id" - activityType := "activity_type1" - activityInput := []byte("input1") - - msBuilder := execution.NewMutableStateBuilderWithEventV2( - s.mockHistoryEngine.shard, - testlogger.New(s.Suite.T()), - we.GetRunID(), - constants.TestLocalDomainEntry, - ) - test.AddWorkflowExecutionStartedEvent(msBuilder, we, "wType", tl, []byte("input"), 100, 100, identity) - di := test.AddDecisionTaskScheduledEvent(msBuilder) - decisionStartedEvent := test.AddDecisionTaskStartedEvent(msBuilder, di.ScheduleID, tl, identity) - decisionCompletedEvent := test.AddDecisionTaskCompletedEvent(msBuilder, di.ScheduleID, - decisionStartedEvent.ID, nil, identity) - activityScheduledEvent, _ := test.AddActivityTaskScheduledEvent(msBuilder, decisionCompletedEvent.ID, activityID, - activityType, tl, activityInput, 100, 10, 1, 1) - test.AddActivityTaskStartedEvent(msBuilder, activityScheduledEvent.ID, identity) - di2 := test.AddDecisionTaskScheduledEvent(msBuilder) - test.AddDecisionTaskStartedEvent(msBuilder, di2.ScheduleID, tl, identity) - - ms := execution.CreatePersistenceMutableState(msBuilder) - gwmsResponse := &persistence.GetWorkflowExecutionResponse{State: ms} - - decisions := []*types.Decision{{ - DecisionType: types.DecisionTypeRequestCancelActivityTask.Ptr(), - RequestCancelActivityTaskDecisionAttributes: &types.RequestCancelActivityTaskDecisionAttributes{ - ActivityID: activityID, - }, - }} - - s.mockExecutionMgr.On("GetWorkflowExecution", mock.Anything, mock.Anything).Return(gwmsResponse, nil).Once() - s.mockHistoryV2Mgr.On("AppendHistoryNodes", mock.Anything, mock.Anything).Return(&persistence.AppendHistoryNodesResponse{}, nil).Once() - s.mockExecutionMgr.On("UpdateWorkflowExecution", mock.Anything, mock.Anything).Return(&persistence.UpdateWorkflowExecutionResponse{MutableStateUpdateSessionStats: &persistence.MutableStateUpdateSessionStats{}}, nil).Once() - - _, err := s.mockHistoryEngine.RespondDecisionTaskCompleted(context.Background(), &types.HistoryRespondDecisionTaskCompletedRequest{ - DomainUUID: constants.TestDomainID, - CompleteRequest: &types.RespondDecisionTaskCompletedRequest{ - TaskToken: taskToken, - Decisions: decisions, - ExecutionContext: []byte("context"), - Identity: identity, - }, - }) - s.Nil(err) - - executionBuilder := s.getBuilder(constants.TestDomainID, we) - s.Equal(int64(11), executionBuilder.GetExecutionInfo().NextEventID) - s.Equal(int64(8), executionBuilder.GetExecutionInfo().LastProcessedEvent) - s.Equal(persistence.WorkflowStateRunning, executionBuilder.GetExecutionInfo().State) - s.False(executionBuilder.HasPendingDecision()) - - // Try recording activity heartbeat - s.mockExecutionMgr.On("UpdateWorkflowExecution", mock.Anything, mock.Anything).Return(&persistence.UpdateWorkflowExecutionResponse{MutableStateUpdateSessionStats: &persistence.MutableStateUpdateSessionStats{}}, nil).Once() - - activityTaskToken, _ := json.Marshal(&common.TaskToken{ - WorkflowID: "wId", - RunID: we.GetRunID(), - ScheduleID: 5, - }) - - hbResponse, err := s.mockHistoryEngine.RecordActivityTaskHeartbeat(context.Background(), &types.HistoryRecordActivityTaskHeartbeatRequest{ - DomainUUID: constants.TestDomainID, - HeartbeatRequest: &types.RecordActivityTaskHeartbeatRequest{ - TaskToken: activityTaskToken, - Identity: identity, - Details: []byte("details"), - }, - }) - s.Nil(err) - s.NotNil(hbResponse) - s.True(hbResponse.CancelRequested) - - // Try cancelling the request. - s.mockHistoryV2Mgr.On("AppendHistoryNodes", mock.Anything, mock.Anything).Return(&persistence.AppendHistoryNodesResponse{}, nil).Once() - s.mockExecutionMgr.On("UpdateWorkflowExecution", mock.Anything, mock.Anything).Return(&persistence.UpdateWorkflowExecutionResponse{MutableStateUpdateSessionStats: &persistence.MutableStateUpdateSessionStats{}}, nil).Once() - - err = s.mockHistoryEngine.RespondActivityTaskCanceled(context.Background(), &types.HistoryRespondActivityTaskCanceledRequest{ - DomainUUID: constants.TestDomainID, - CancelRequest: &types.RespondActivityTaskCanceledRequest{ - TaskToken: activityTaskToken, - Identity: identity, - Details: []byte("details"), - }, - }) - s.Nil(err) - - executionBuilder = s.getBuilder(constants.TestDomainID, we) - s.Equal(int64(13), executionBuilder.GetExecutionInfo().NextEventID) - s.Equal(int64(8), executionBuilder.GetExecutionInfo().LastProcessedEvent) - s.Equal(persistence.WorkflowStateRunning, executionBuilder.GetExecutionInfo().State) - s.True(executionBuilder.HasPendingDecision()) -} - -func (s *engineSuite) TestRequestCancel_RespondDecisionTaskCompleted_SuccessWithQueries() { - we := types.WorkflowExecution{ - WorkflowID: "wId", - RunID: constants.TestRunID, - } - tl := "testTaskList" - taskToken, _ := json.Marshal(&common.TaskToken{ - WorkflowID: we.WorkflowID, - RunID: we.RunID, - ScheduleID: 7, - }) - identity := "testIdentity" - activityID := "activity1_id" - activityType := "activity_type1" - activityInput := []byte("input1") - - msBuilder := execution.NewMutableStateBuilderWithEventV2( - s.mockHistoryEngine.shard, - testlogger.New(s.Suite.T()), - we.GetRunID(), - constants.TestLocalDomainEntry, - ) - test.AddWorkflowExecutionStartedEvent(msBuilder, we, "wType", tl, []byte("input"), 100, 100, identity) - di := test.AddDecisionTaskScheduledEvent(msBuilder) - decisionStartedEvent := test.AddDecisionTaskStartedEvent(msBuilder, di.ScheduleID, tl, identity) - decisionCompletedEvent := test.AddDecisionTaskCompletedEvent(msBuilder, di.ScheduleID, - decisionStartedEvent.ID, nil, identity) - activityScheduledEvent, _ := test.AddActivityTaskScheduledEvent(msBuilder, decisionCompletedEvent.ID, activityID, - activityType, tl, activityInput, 100, 10, 1, 1) - test.AddActivityTaskStartedEvent(msBuilder, activityScheduledEvent.ID, identity) - di2 := test.AddDecisionTaskScheduledEvent(msBuilder) - test.AddDecisionTaskStartedEvent(msBuilder, di2.ScheduleID, tl, identity) - - ms := execution.CreatePersistenceMutableState(msBuilder) - gwmsResponse := &persistence.GetWorkflowExecutionResponse{State: ms} - - decisions := []*types.Decision{{ - DecisionType: types.DecisionTypeRequestCancelActivityTask.Ptr(), - RequestCancelActivityTaskDecisionAttributes: &types.RequestCancelActivityTaskDecisionAttributes{ - ActivityID: activityID, - }, - }} - - s.mockExecutionMgr.On("GetWorkflowExecution", mock.Anything, mock.Anything).Return(gwmsResponse, nil).Once() - s.mockHistoryV2Mgr.On("AppendHistoryNodes", mock.Anything, mock.Anything).Return(&persistence.AppendHistoryNodesResponse{}, nil).Once() - s.mockExecutionMgr.On("UpdateWorkflowExecution", mock.Anything, mock.Anything).Return(&persistence.UpdateWorkflowExecutionResponse{MutableStateUpdateSessionStats: &persistence.MutableStateUpdateSessionStats{}}, nil).Once() - - // load mutable state such that it already exists in memory when respond decision task is called - // this enables us to set query registry on it - ctx, release, err := s.mockHistoryEngine.executionCache.GetOrCreateWorkflowExecutionForBackground(constants.TestDomainID, we) - s.NoError(err) - loadedMS, err := ctx.LoadWorkflowExecution(context.Background()) - s.NoError(err) - qr := query.NewRegistry() - id1, _ := qr.BufferQuery(&types.WorkflowQuery{}) - id2, _ := qr.BufferQuery(&types.WorkflowQuery{}) - id3, _ := qr.BufferQuery(&types.WorkflowQuery{}) - loadedMS.SetQueryRegistry(qr) - release(nil) - result1 := &types.WorkflowQueryResult{ - ResultType: types.QueryResultTypeAnswered.Ptr(), - Answer: []byte{1, 2, 3}, - } - result2 := &types.WorkflowQueryResult{ - ResultType: types.QueryResultTypeFailed.Ptr(), - ErrorMessage: "error reason", - } - queryResults := map[string]*types.WorkflowQueryResult{ - id1: result1, - id2: result2, - } - _, err = s.mockHistoryEngine.RespondDecisionTaskCompleted(s.constructCallContext(cc.GoWorkerConsistentQueryVersion), &types.HistoryRespondDecisionTaskCompletedRequest{ - DomainUUID: constants.TestDomainID, - CompleteRequest: &types.RespondDecisionTaskCompletedRequest{ - TaskToken: taskToken, - Decisions: decisions, - ExecutionContext: []byte("context"), - Identity: identity, - QueryResults: queryResults, - }, - }) - s.Nil(err) - - executionBuilder := s.getBuilder(constants.TestDomainID, we) - s.Equal(int64(11), executionBuilder.GetExecutionInfo().NextEventID) - s.Equal(int64(8), executionBuilder.GetExecutionInfo().LastProcessedEvent) - s.Equal(persistence.WorkflowStateRunning, executionBuilder.GetExecutionInfo().State) - s.False(executionBuilder.HasPendingDecision()) - s.Len(qr.GetCompletedIDs(), 2) - completed1, err := qr.GetTerminationState(id1) - s.NoError(err) - s.Equal(result1, completed1.QueryResult) - s.Equal(query.TerminationTypeCompleted, completed1.TerminationType) - completed2, err := qr.GetTerminationState(id2) - s.NoError(err) - s.Equal(result2, completed2.QueryResult) - s.Equal(query.TerminationTypeCompleted, completed2.TerminationType) - s.Len(qr.GetBufferedIDs(), 0) - s.Len(qr.GetFailedIDs(), 0) - s.Len(qr.GetUnblockedIDs(), 1) - unblocked1, err := qr.GetTerminationState(id3) - s.NoError(err) - s.Nil(unblocked1.QueryResult) - s.Equal(query.TerminationTypeUnblocked, unblocked1.TerminationType) - - // Try recording activity heartbeat - s.mockExecutionMgr.On("UpdateWorkflowExecution", mock.Anything, mock.Anything).Return(&persistence.UpdateWorkflowExecutionResponse{MutableStateUpdateSessionStats: &persistence.MutableStateUpdateSessionStats{}}, nil).Once() - - activityTaskToken, _ := json.Marshal(&common.TaskToken{ - WorkflowID: "wId", - RunID: we.GetRunID(), - ScheduleID: 5, - }) - - hbResponse, err := s.mockHistoryEngine.RecordActivityTaskHeartbeat(context.Background(), &types.HistoryRecordActivityTaskHeartbeatRequest{ - DomainUUID: constants.TestDomainID, - HeartbeatRequest: &types.RecordActivityTaskHeartbeatRequest{ - TaskToken: activityTaskToken, - Identity: identity, - Details: []byte("details"), - }, - }) - s.Nil(err) - s.NotNil(hbResponse) - s.True(hbResponse.CancelRequested) - - // Try cancelling the request. - s.mockHistoryV2Mgr.On("AppendHistoryNodes", mock.Anything, mock.Anything).Return(&persistence.AppendHistoryNodesResponse{}, nil).Once() - s.mockExecutionMgr.On("UpdateWorkflowExecution", mock.Anything, mock.Anything).Return(&persistence.UpdateWorkflowExecutionResponse{MutableStateUpdateSessionStats: &persistence.MutableStateUpdateSessionStats{}}, nil).Once() - - err = s.mockHistoryEngine.RespondActivityTaskCanceled(context.Background(), &types.HistoryRespondActivityTaskCanceledRequest{ - DomainUUID: constants.TestDomainID, - CancelRequest: &types.RespondActivityTaskCanceledRequest{ - TaskToken: activityTaskToken, - Identity: identity, - Details: []byte("details"), - }, - }) - s.Nil(err) - - executionBuilder = s.getBuilder(constants.TestDomainID, we) - s.Equal(int64(13), executionBuilder.GetExecutionInfo().NextEventID) - s.Equal(int64(8), executionBuilder.GetExecutionInfo().LastProcessedEvent) - s.Equal(persistence.WorkflowStateRunning, executionBuilder.GetExecutionInfo().State) - s.True(executionBuilder.HasPendingDecision()) -} - -func (s *engineSuite) TestRequestCancel_RespondDecisionTaskCompleted_SuccessWithConsistentQueriesUnsupported() { - we := types.WorkflowExecution{ - WorkflowID: "wId", - RunID: constants.TestRunID, - } - tl := "testTaskList" - taskToken, _ := json.Marshal(&common.TaskToken{ - WorkflowID: we.WorkflowID, - RunID: we.RunID, - ScheduleID: 7, - }) - identity := "testIdentity" - activityID := "activity1_id" - activityType := "activity_type1" - activityInput := []byte("input1") - - msBuilder := execution.NewMutableStateBuilderWithEventV2( - s.mockHistoryEngine.shard, - testlogger.New(s.Suite.T()), - we.GetRunID(), - constants.TestLocalDomainEntry, - ) - test.AddWorkflowExecutionStartedEvent(msBuilder, we, "wType", tl, []byte("input"), 100, 100, identity) - di := test.AddDecisionTaskScheduledEvent(msBuilder) - decisionStartedEvent := test.AddDecisionTaskStartedEvent(msBuilder, di.ScheduleID, tl, identity) - decisionCompletedEvent := test.AddDecisionTaskCompletedEvent(msBuilder, di.ScheduleID, - decisionStartedEvent.ID, nil, identity) - activityScheduledEvent, _ := test.AddActivityTaskScheduledEvent(msBuilder, decisionCompletedEvent.ID, activityID, - activityType, tl, activityInput, 100, 10, 1, 1) - test.AddActivityTaskStartedEvent(msBuilder, activityScheduledEvent.ID, identity) - di2 := test.AddDecisionTaskScheduledEvent(msBuilder) - test.AddDecisionTaskStartedEvent(msBuilder, di2.ScheduleID, tl, identity) - - ms := execution.CreatePersistenceMutableState(msBuilder) - gwmsResponse := &persistence.GetWorkflowExecutionResponse{State: ms} - - decisions := []*types.Decision{{ - DecisionType: types.DecisionTypeRequestCancelActivityTask.Ptr(), - RequestCancelActivityTaskDecisionAttributes: &types.RequestCancelActivityTaskDecisionAttributes{ - ActivityID: activityID, - }, - }} - - s.mockExecutionMgr.On("GetWorkflowExecution", mock.Anything, mock.Anything).Return(gwmsResponse, nil).Once() - s.mockHistoryV2Mgr.On("AppendHistoryNodes", mock.Anything, mock.Anything).Return(&persistence.AppendHistoryNodesResponse{}, nil).Once() - s.mockExecutionMgr.On("UpdateWorkflowExecution", mock.Anything, mock.Anything).Return(&persistence.UpdateWorkflowExecutionResponse{MutableStateUpdateSessionStats: &persistence.MutableStateUpdateSessionStats{}}, nil).Once() - - // load mutable state such that it already exists in memory when respond decision task is called - // this enables us to set query registry on it - ctx, release, err := s.mockHistoryEngine.executionCache.GetOrCreateWorkflowExecutionForBackground(constants.TestDomainID, we) - s.NoError(err) - loadedMS, err := ctx.LoadWorkflowExecution(context.Background()) - s.NoError(err) - qr := query.NewRegistry() - qr.BufferQuery(&types.WorkflowQuery{}) - qr.BufferQuery(&types.WorkflowQuery{}) - qr.BufferQuery(&types.WorkflowQuery{}) - loadedMS.SetQueryRegistry(qr) - release(nil) - _, err = s.mockHistoryEngine.RespondDecisionTaskCompleted(s.constructCallContext("0.0.0"), &types.HistoryRespondDecisionTaskCompletedRequest{ - DomainUUID: constants.TestDomainID, - CompleteRequest: &types.RespondDecisionTaskCompletedRequest{ - TaskToken: taskToken, - Decisions: decisions, - ExecutionContext: []byte("context"), - Identity: identity, - }, - }) - s.Nil(err) - - executionBuilder := s.getBuilder(constants.TestDomainID, we) - s.Equal(int64(11), executionBuilder.GetExecutionInfo().NextEventID) - s.Equal(int64(8), executionBuilder.GetExecutionInfo().LastProcessedEvent) - s.Equal(persistence.WorkflowStateRunning, executionBuilder.GetExecutionInfo().State) - s.False(executionBuilder.HasPendingDecision()) - s.Len(qr.GetBufferedIDs(), 0) - s.Len(qr.GetCompletedIDs(), 0) - s.Len(qr.GetUnblockedIDs(), 0) - s.Len(qr.GetFailedIDs(), 3) -} - -func (s *engineSuite) constructCallContext(featureVersion string) context.Context { - ctx := context.Background() - ctx, call := encoding.NewInboundCall(ctx) - err := call.ReadFromRequest(&transport.Request{ - Headers: transport.NewHeaders().With(common.ClientImplHeaderName, cc.GoSDK).With(common.FeatureVersionHeaderName, featureVersion), - }) - s.NoError(err) - return ctx -} - -func (s *engineSuite) TestStarTimer_DuplicateTimerID() { - - we := types.WorkflowExecution{ - WorkflowID: "wId", - RunID: constants.TestRunID, - } - tl := "testTaskList" - taskToken, _ := json.Marshal(&common.TaskToken{ - WorkflowID: we.WorkflowID, - RunID: we.RunID, - ScheduleID: 2, - }) - identity := "testIdentity" - timerID := "t1" - - msBuilder := execution.NewMutableStateBuilderWithEventV2( - s.mockHistoryEngine.shard, - testlogger.New(s.Suite.T()), - we.GetRunID(), - constants.TestLocalDomainEntry, - ) - - test.AddWorkflowExecutionStartedEvent(msBuilder, we, "wType", tl, []byte("input"), 100, 100, identity) - di := test.AddDecisionTaskScheduledEvent(msBuilder) - test.AddDecisionTaskStartedEvent(msBuilder, di.ScheduleID, tl, identity) - - ms := execution.CreatePersistenceMutableState(msBuilder) - gwmsResponse := &persistence.GetWorkflowExecutionResponse{State: ms} - - decisions := []*types.Decision{{ - DecisionType: types.DecisionTypeStartTimer.Ptr(), - StartTimerDecisionAttributes: &types.StartTimerDecisionAttributes{ - TimerID: timerID, - StartToFireTimeoutSeconds: common.Int64Ptr(1), - }, - }} - - s.mockExecutionMgr.On("GetWorkflowExecution", mock.Anything, mock.Anything).Return(gwmsResponse, nil).Once() - s.mockHistoryV2Mgr.On("AppendHistoryNodes", mock.Anything, mock.Anything).Return(&persistence.AppendHistoryNodesResponse{}, nil).Once() - s.mockExecutionMgr.On("UpdateWorkflowExecution", mock.Anything, mock.Anything).Return(&persistence.UpdateWorkflowExecutionResponse{MutableStateUpdateSessionStats: &persistence.MutableStateUpdateSessionStats{}}, nil).Once() - - _, err := s.mockHistoryEngine.RespondDecisionTaskCompleted(context.Background(), &types.HistoryRespondDecisionTaskCompletedRequest{ - DomainUUID: constants.TestDomainID, - CompleteRequest: &types.RespondDecisionTaskCompletedRequest{ - TaskToken: taskToken, - Decisions: decisions, - ExecutionContext: []byte("context"), - Identity: identity, - }, - }) - s.Nil(err) - - executionBuilder := s.getBuilder(constants.TestDomainID, we) - s.Equal(persistence.WorkflowStateRunning, executionBuilder.GetExecutionInfo().State) - - // Try to add the same timer ID again. - di2 := test.AddDecisionTaskScheduledEvent(executionBuilder) - test.AddDecisionTaskStartedEvent(executionBuilder, di2.ScheduleID, tl, identity) - taskToken2, _ := json.Marshal(&common.TaskToken{ - WorkflowID: we.WorkflowID, - RunID: we.RunID, - ScheduleID: di2.ScheduleID, - }) - - ms2 := execution.CreatePersistenceMutableState(executionBuilder) - gwmsResponse2 := &persistence.GetWorkflowExecutionResponse{State: ms2} - - decisionFailedEvent := false - s.mockExecutionMgr.On("GetWorkflowExecution", mock.Anything, mock.Anything).Return(gwmsResponse2, nil).Once() - s.mockHistoryV2Mgr.On("AppendHistoryNodes", mock.Anything, mock.Anything).Return(&persistence.AppendHistoryNodesResponse{}, nil).Run(func(arguments mock.Arguments) { - req := arguments.Get(1).(*persistence.AppendHistoryNodesRequest) - decTaskIndex := len(req.Events) - 1 - if decTaskIndex >= 0 && *req.Events[decTaskIndex].EventType == types.EventTypeDecisionTaskFailed { - decisionFailedEvent = true - } - }).Once() - s.mockExecutionMgr.On("UpdateWorkflowExecution", mock.Anything, mock.Anything).Return(&persistence.UpdateWorkflowExecutionResponse{MutableStateUpdateSessionStats: &persistence.MutableStateUpdateSessionStats{}}, nil).Once() - - _, err = s.mockHistoryEngine.RespondDecisionTaskCompleted(context.Background(), &types.HistoryRespondDecisionTaskCompletedRequest{ - DomainUUID: constants.TestDomainID, - CompleteRequest: &types.RespondDecisionTaskCompletedRequest{ - TaskToken: taskToken2, - Decisions: decisions, - ExecutionContext: []byte("context"), - Identity: identity, - }, - }) - s.Nil(err) - - s.True(decisionFailedEvent) - executionBuilder = s.getBuilder(constants.TestDomainID, we) - s.Equal(persistence.WorkflowStateRunning, executionBuilder.GetExecutionInfo().State) - s.True(executionBuilder.HasPendingDecision()) - di3, ok := executionBuilder.GetDecisionInfo(executionBuilder.GetExecutionInfo().NextEventID) - s.True(ok, "DI.ScheduleID: %v, ScheduleID: %v, StartedID: %v", di2.ScheduleID, - executionBuilder.GetExecutionInfo().DecisionScheduleID, executionBuilder.GetExecutionInfo().DecisionStartedID) - s.Equal(executionBuilder.GetExecutionInfo().NextEventID, di3.ScheduleID) - s.Equal(int64(1), di3.Attempt) -} - -func (s *engineSuite) TestUserTimer_RespondDecisionTaskCompleted() { - - we := types.WorkflowExecution{ - WorkflowID: "wId", - RunID: constants.TestRunID, - } - tl := "testTaskList" - taskToken, _ := json.Marshal(&common.TaskToken{ - WorkflowID: we.WorkflowID, - RunID: we.RunID, - ScheduleID: 6, - }) - identity := "testIdentity" - timerID := "t1" - - msBuilder := execution.NewMutableStateBuilderWithEventV2( - s.mockHistoryEngine.shard, - testlogger.New(s.Suite.T()), - we.GetRunID(), - constants.TestLocalDomainEntry, - ) - // Verify cancel timer with a start event. - test.AddWorkflowExecutionStartedEvent(msBuilder, we, "wType", tl, []byte("input"), 100, 100, identity) - di := test.AddDecisionTaskScheduledEvent(msBuilder) - decisionStartedEvent := test.AddDecisionTaskStartedEvent(msBuilder, di.ScheduleID, tl, identity) - decisionCompletedEvent := test.AddDecisionTaskCompletedEvent(msBuilder, di.ScheduleID, - decisionStartedEvent.ID, nil, identity) - test.AddTimerStartedEvent(msBuilder, decisionCompletedEvent.ID, timerID, 10) - di2 := test.AddDecisionTaskScheduledEvent(msBuilder) - test.AddDecisionTaskStartedEvent(msBuilder, di2.ScheduleID, tl, identity) - - ms := execution.CreatePersistenceMutableState(msBuilder) - gwmsResponse := &persistence.GetWorkflowExecutionResponse{State: ms} - - decisions := []*types.Decision{{ - DecisionType: types.DecisionTypeCancelTimer.Ptr(), - CancelTimerDecisionAttributes: &types.CancelTimerDecisionAttributes{ - TimerID: timerID, - }, - }} - - s.mockExecutionMgr.On("GetWorkflowExecution", mock.Anything, mock.Anything).Return(gwmsResponse, nil).Once() - s.mockHistoryV2Mgr.On("AppendHistoryNodes", mock.Anything, mock.Anything).Return(&persistence.AppendHistoryNodesResponse{}, nil).Once() - s.mockExecutionMgr.On("UpdateWorkflowExecution", mock.Anything, mock.Anything).Return(&persistence.UpdateWorkflowExecutionResponse{MutableStateUpdateSessionStats: &persistence.MutableStateUpdateSessionStats{}}, nil).Once() - - _, err := s.mockHistoryEngine.RespondDecisionTaskCompleted(context.Background(), &types.HistoryRespondDecisionTaskCompletedRequest{ - DomainUUID: constants.TestDomainID, - CompleteRequest: &types.RespondDecisionTaskCompletedRequest{ - TaskToken: taskToken, - Decisions: decisions, - ExecutionContext: []byte("context"), - Identity: identity, - }, - }) - s.Nil(err) - - executionBuilder := s.getBuilder(constants.TestDomainID, we) - s.Equal(int64(10), executionBuilder.GetExecutionInfo().NextEventID) - s.Equal(int64(7), executionBuilder.GetExecutionInfo().LastProcessedEvent) - s.Equal(persistence.WorkflowStateRunning, executionBuilder.GetExecutionInfo().State) - s.False(executionBuilder.HasPendingDecision()) -} - -func (s *engineSuite) TestCancelTimer_RespondDecisionTaskCompleted_NoStartTimer() { - - we := types.WorkflowExecution{ - WorkflowID: "wId", - RunID: constants.TestRunID, - } - tl := "testTaskList" - taskToken, _ := json.Marshal(&common.TaskToken{ - WorkflowID: we.WorkflowID, - RunID: we.RunID, - ScheduleID: 2, - }) - identity := "testIdentity" - timerID := "t1" - - msBuilder := execution.NewMutableStateBuilderWithEventV2( - s.mockHistoryEngine.shard, - testlogger.New(s.Suite.T()), - we.GetRunID(), - constants.TestLocalDomainEntry, - ) - // Verify cancel timer with a start event. - test.AddWorkflowExecutionStartedEvent(msBuilder, we, "wType", tl, []byte("input"), 100, 100, identity) - di := test.AddDecisionTaskScheduledEvent(msBuilder) - test.AddDecisionTaskStartedEvent(msBuilder, di.ScheduleID, tl, identity) - - ms := execution.CreatePersistenceMutableState(msBuilder) - gwmsResponse := &persistence.GetWorkflowExecutionResponse{State: ms} - - decisions := []*types.Decision{{ - DecisionType: types.DecisionTypeCancelTimer.Ptr(), - CancelTimerDecisionAttributes: &types.CancelTimerDecisionAttributes{ - TimerID: timerID, - }, - }} - - s.mockExecutionMgr.On("GetWorkflowExecution", mock.Anything, mock.Anything).Return(gwmsResponse, nil).Once() - s.mockHistoryV2Mgr.On("AppendHistoryNodes", mock.Anything, mock.Anything).Return(&persistence.AppendHistoryNodesResponse{}, nil).Once() - s.mockExecutionMgr.On("UpdateWorkflowExecution", mock.Anything, mock.Anything).Return(&persistence.UpdateWorkflowExecutionResponse{MutableStateUpdateSessionStats: &persistence.MutableStateUpdateSessionStats{}}, nil).Once() - - _, err := s.mockHistoryEngine.RespondDecisionTaskCompleted(context.Background(), &types.HistoryRespondDecisionTaskCompletedRequest{ - DomainUUID: constants.TestDomainID, - CompleteRequest: &types.RespondDecisionTaskCompletedRequest{ - TaskToken: taskToken, - Decisions: decisions, - ExecutionContext: []byte("context"), - Identity: identity, - }, - }) - s.Nil(err) - - executionBuilder := s.getBuilder(constants.TestDomainID, we) - s.Equal(int64(6), executionBuilder.GetExecutionInfo().NextEventID) - s.Equal(int64(3), executionBuilder.GetExecutionInfo().LastProcessedEvent) - s.Equal(persistence.WorkflowStateRunning, executionBuilder.GetExecutionInfo().State) - s.False(executionBuilder.HasPendingDecision()) -} - -func (s *engineSuite) TestCancelTimer_RespondDecisionTaskCompleted_TimerFired() { - - we := types.WorkflowExecution{ - WorkflowID: "wId", - RunID: constants.TestRunID, - } - tl := "testTaskList" - taskToken, _ := json.Marshal(&common.TaskToken{ - WorkflowID: we.WorkflowID, - RunID: we.RunID, - ScheduleID: 6, - }) - identity := "testIdentity" - timerID := "t1" - - msBuilder := execution.NewMutableStateBuilderWithEventV2( - s.mockHistoryEngine.shard, - testlogger.New(s.Suite.T()), - we.GetRunID(), - constants.TestLocalDomainEntry, - ) - // Verify cancel timer with a start event. - test.AddWorkflowExecutionStartedEvent(msBuilder, we, "wType", tl, []byte("input"), 100, 100, identity) - di := test.AddDecisionTaskScheduledEvent(msBuilder) - decisionStartedEvent := test.AddDecisionTaskStartedEvent(msBuilder, di.ScheduleID, tl, identity) - decisionCompletedEvent := test.AddDecisionTaskCompletedEvent(msBuilder, di.ScheduleID, - decisionStartedEvent.ID, nil, identity) - test.AddTimerStartedEvent(msBuilder, decisionCompletedEvent.ID, timerID, 10) - di2 := test.AddDecisionTaskScheduledEvent(msBuilder) - test.AddDecisionTaskStartedEvent(msBuilder, di2.ScheduleID, tl, identity) - test.AddTimerFiredEvent(msBuilder, timerID) - _, _, err := msBuilder.CloseTransactionAsMutation(time.Now(), execution.TransactionPolicyActive) - s.Nil(err) - - ms := execution.CreatePersistenceMutableState(msBuilder) - gwmsResponse := &persistence.GetWorkflowExecutionResponse{State: ms} - s.True(len(gwmsResponse.State.BufferedEvents) > 0) - - decisions := []*types.Decision{{ - DecisionType: types.DecisionTypeCancelTimer.Ptr(), - CancelTimerDecisionAttributes: &types.CancelTimerDecisionAttributes{ - TimerID: timerID, - }, - }} - - s.mockExecutionMgr.On("GetWorkflowExecution", mock.Anything, mock.Anything).Return(gwmsResponse, nil).Once() - s.mockHistoryV2Mgr.On("AppendHistoryNodes", mock.Anything, mock.Anything).Return(&persistence.AppendHistoryNodesResponse{}, nil).Once() - s.mockExecutionMgr.On("UpdateWorkflowExecution", mock.Anything, mock.MatchedBy(func(input *persistence.UpdateWorkflowExecutionRequest) bool { - // need to check whether the buffered events are cleared - s.True(input.UpdateWorkflowMutation.ClearBufferedEvents) - return true - })).Return(&persistence.UpdateWorkflowExecutionResponse{MutableStateUpdateSessionStats: &persistence.MutableStateUpdateSessionStats{}}, nil).Once() - - _, err = s.mockHistoryEngine.RespondDecisionTaskCompleted(context.Background(), &types.HistoryRespondDecisionTaskCompletedRequest{ - DomainUUID: constants.TestDomainID, - CompleteRequest: &types.RespondDecisionTaskCompletedRequest{ - TaskToken: taskToken, - Decisions: decisions, - ExecutionContext: []byte("context"), - Identity: identity, - }, - }) - s.Nil(err) - - executionBuilder := s.getBuilder(constants.TestDomainID, we) - s.Equal(int64(10), executionBuilder.GetExecutionInfo().NextEventID) - s.Equal(int64(7), executionBuilder.GetExecutionInfo().LastProcessedEvent) - s.Equal(persistence.WorkflowStateRunning, executionBuilder.GetExecutionInfo().State) - s.False(executionBuilder.HasPendingDecision()) - s.False(executionBuilder.HasBufferedEvents()) -} - -func (s *engineSuite) TestSignalWorkflowExecution_InvalidRequest() { - signalRequest := &types.HistorySignalWorkflowExecutionRequest{} - err := s.mockHistoryEngine.SignalWorkflowExecution(context.Background(), signalRequest) - s.Error(err) -} - -func (s *engineSuite) TestSignalWorkflowExecution() { - we := types.WorkflowExecution{ - WorkflowID: constants.TestWorkflowID, - RunID: constants.TestRunID, - } - tasklist := "testTaskList" - identity := "testIdentity" - signalName := "my signal name" - input := []byte("test input") - signalRequest := &types.HistorySignalWorkflowExecutionRequest{ - DomainUUID: constants.TestDomainID, - SignalRequest: &types.SignalWorkflowExecutionRequest{ - Domain: constants.TestDomainID, - WorkflowExecution: &we, - Identity: identity, - SignalName: signalName, - Input: input, - }, - } - - msBuilder := execution.NewMutableStateBuilderWithEventV2( - s.mockHistoryEngine.shard, - testlogger.New(s.Suite.T()), - we.GetRunID(), - constants.TestLocalDomainEntry, - ) - test.AddWorkflowExecutionStartedEvent(msBuilder, we, "wType", tasklist, []byte("input"), 100, 200, identity) - test.AddDecisionTaskScheduledEvent(msBuilder) - ms := execution.CreatePersistenceMutableState(msBuilder) - ms.ExecutionInfo.DomainID = constants.TestDomainID - gwmsResponse := &persistence.GetWorkflowExecutionResponse{State: ms} - - s.mockExecutionMgr.On("GetWorkflowExecution", mock.Anything, mock.Anything).Return(gwmsResponse, nil).Once() - s.mockHistoryV2Mgr.On("AppendHistoryNodes", mock.Anything, mock.Anything).Return(&persistence.AppendHistoryNodesResponse{}, nil).Once() - s.mockExecutionMgr.On("UpdateWorkflowExecution", mock.Anything, mock.Anything).Return(&persistence.UpdateWorkflowExecutionResponse{MutableStateUpdateSessionStats: &persistence.MutableStateUpdateSessionStats{}}, nil).Once() - - err := s.mockHistoryEngine.SignalWorkflowExecution(context.Background(), signalRequest) - s.Nil(err) -} - -// Test signal decision by adding request ID -func (s *engineSuite) TestSignalWorkflowExecution_DuplicateRequest_WorkflowOpen() { - we := types.WorkflowExecution{ - WorkflowID: constants.TestWorkflowID, - RunID: constants.TestRunID, - } - tasklist := "testTaskList" - identity := "testIdentity" - signalName := "my signal name 2" - input := []byte("test input 2") - requestID := uuid.New() - signalRequest := &types.HistorySignalWorkflowExecutionRequest{ - DomainUUID: constants.TestDomainID, - SignalRequest: &types.SignalWorkflowExecutionRequest{ - Domain: constants.TestDomainID, - WorkflowExecution: &we, - Identity: identity, - SignalName: signalName, - Input: input, - RequestID: requestID, - }, - } - - msBuilder := execution.NewMutableStateBuilderWithEventV2( - s.mockHistoryEngine.shard, - testlogger.New(s.Suite.T()), - we.GetRunID(), - constants.TestLocalDomainEntry, - ) - test.AddWorkflowExecutionStartedEvent(msBuilder, we, "wType", tasklist, []byte("input"), 100, 200, identity) - test.AddDecisionTaskScheduledEvent(msBuilder) - ms := execution.CreatePersistenceMutableState(msBuilder) - // assume duplicate request id - ms.SignalRequestedIDs = make(map[string]struct{}) - ms.SignalRequestedIDs[requestID] = struct{}{} - ms.ExecutionInfo.DomainID = constants.TestDomainID - gwmsResponse := &persistence.GetWorkflowExecutionResponse{State: ms} - - s.mockExecutionMgr.On("GetWorkflowExecution", mock.Anything, mock.Anything).Return(gwmsResponse, nil).Once() - - err := s.mockHistoryEngine.SignalWorkflowExecution(context.Background(), signalRequest) - s.Nil(err) -} - -func (s *engineSuite) TestSignalWorkflowExecution_DuplicateRequest_WorkflowCompleted() { - we := types.WorkflowExecution{ - WorkflowID: constants.TestWorkflowID, - RunID: constants.TestRunID, - } - tasklist := "testTaskList" - identity := "testIdentity" - signalName := "my signal name 2" - input := []byte("test input 2") - requestID := uuid.New() - signalRequest := &types.HistorySignalWorkflowExecutionRequest{ - DomainUUID: constants.TestDomainID, - SignalRequest: &types.SignalWorkflowExecutionRequest{ - Domain: constants.TestDomainID, - WorkflowExecution: &we, - Identity: identity, - SignalName: signalName, - Input: input, - RequestID: requestID, - }, - } - - msBuilder := execution.NewMutableStateBuilderWithEventV2( - s.mockHistoryEngine.shard, - testlogger.New(s.Suite.T()), - we.GetRunID(), - constants.TestLocalDomainEntry, - ) - test.AddWorkflowExecutionStartedEvent(msBuilder, we, "wType", tasklist, []byte("input"), 100, 200, identity) - test.AddDecisionTaskScheduledEvent(msBuilder) - ms := execution.CreatePersistenceMutableState(msBuilder) - // assume duplicate request id - ms.SignalRequestedIDs = make(map[string]struct{}) - ms.SignalRequestedIDs[requestID] = struct{}{} - ms.ExecutionInfo.DomainID = constants.TestDomainID - ms.ExecutionInfo.State = persistence.WorkflowStateCompleted - gwmsResponse := &persistence.GetWorkflowExecutionResponse{State: ms} - - s.mockExecutionMgr.On("GetWorkflowExecution", mock.Anything, mock.Anything).Return(gwmsResponse, nil).Once() - - err := s.mockHistoryEngine.SignalWorkflowExecution(context.Background(), signalRequest) - s.Nil(err) -} - -func (s *engineSuite) TestSignalWorkflowExecution_WorkflowCompleted() { - we := &types.WorkflowExecution{ - WorkflowID: constants.TestWorkflowID, - RunID: constants.TestRunID, - } - tasklist := "testTaskList" - identity := "testIdentity" - signalName := "my signal name" - input := []byte("test input") - signalRequest := &types.HistorySignalWorkflowExecutionRequest{ - DomainUUID: constants.TestDomainID, - SignalRequest: &types.SignalWorkflowExecutionRequest{ - Domain: constants.TestDomainID, - WorkflowExecution: we, - Identity: identity, - SignalName: signalName, - Input: input, - }, - } - - msBuilder := execution.NewMutableStateBuilderWithEventV2( - s.mockHistoryEngine.shard, - testlogger.New(s.Suite.T()), - we.GetRunID(), - constants.TestLocalDomainEntry, - ) - test.AddWorkflowExecutionStartedEvent(msBuilder, *we, "wType", tasklist, []byte("input"), 100, 200, identity) - test.AddDecisionTaskScheduledEvent(msBuilder) - ms := execution.CreatePersistenceMutableState(msBuilder) - ms.ExecutionInfo.State = persistence.WorkflowStateCompleted - gwmsResponse := &persistence.GetWorkflowExecutionResponse{State: ms} - - s.mockExecutionMgr.On("GetWorkflowExecution", mock.Anything, mock.Anything).Return(gwmsResponse, nil).Once() - - err := s.mockHistoryEngine.SignalWorkflowExecution(context.Background(), signalRequest) - s.EqualError(err, "workflow execution already completed") -} - -func (s *engineSuite) TestRemoveSignalMutableState() { - removeRequest := &types.RemoveSignalMutableStateRequest{} - err := s.mockHistoryEngine.RemoveSignalMutableState(context.Background(), removeRequest) - s.Error(err) - - workflowExecution := types.WorkflowExecution{ - WorkflowID: "wId", - RunID: constants.TestRunID, - } - tasklist := "testTaskList" - identity := "testIdentity" - requestID := uuid.New() - removeRequest = &types.RemoveSignalMutableStateRequest{ - DomainUUID: constants.TestDomainID, - WorkflowExecution: &workflowExecution, - RequestID: requestID, - } - - msBuilder := execution.NewMutableStateBuilderWithEventV2( - s.mockHistoryEngine.shard, - testlogger.New(s.Suite.T()), - constants.TestRunID, - constants.TestLocalDomainEntry, - ) - test.AddWorkflowExecutionStartedEvent(msBuilder, workflowExecution, "wType", tasklist, []byte("input"), 100, 200, identity) - test.AddDecisionTaskScheduledEvent(msBuilder) - ms := execution.CreatePersistenceMutableState(msBuilder) - ms.ExecutionInfo.DomainID = constants.TestDomainID - gwmsResponse := &persistence.GetWorkflowExecutionResponse{State: ms} - - s.mockExecutionMgr.On("GetWorkflowExecution", mock.Anything, mock.Anything).Return(gwmsResponse, nil).Once() - s.mockExecutionMgr.On("UpdateWorkflowExecution", mock.Anything, mock.Anything).Return(&persistence.UpdateWorkflowExecutionResponse{MutableStateUpdateSessionStats: &persistence.MutableStateUpdateSessionStats{}}, nil).Once() - - err = s.mockHistoryEngine.RemoveSignalMutableState(context.Background(), removeRequest) - s.Nil(err) -} - -func (s *engineSuite) TestReapplyEvents_ReturnSuccess() { - workflowExecution := types.WorkflowExecution{ - WorkflowID: "test-reapply", - RunID: constants.TestRunID, - } - history := []*types.HistoryEvent{ - { - ID: 1, - EventType: types.EventTypeWorkflowExecutionSignaled.Ptr(), - Version: 1, - }, - } - msBuilder := execution.NewMutableStateBuilderWithEventV2( - s.mockHistoryEngine.shard, - testlogger.New(s.Suite.T()), - workflowExecution.GetRunID(), - constants.TestLocalDomainEntry, - ) - ms := execution.CreatePersistenceMutableState(msBuilder) - gwmsResponse := &persistence.GetWorkflowExecutionResponse{State: ms} - gceResponse := &persistence.GetCurrentExecutionResponse{RunID: constants.TestRunID} - s.mockExecutionMgr.On("GetCurrentExecution", mock.Anything, mock.Anything).Return(gceResponse, nil).Once() - s.mockExecutionMgr.On("GetWorkflowExecution", mock.Anything, mock.Anything).Return(gwmsResponse, nil).Once() - s.mockEventsReapplier.EXPECT().ReapplyEvents(gomock.Any(), gomock.Any(), gomock.Any(), gomock.Any()).Times(1) - - err := s.mockHistoryEngine.ReapplyEvents( - context.Background(), - constants.TestDomainID, - workflowExecution.WorkflowID, - workflowExecution.RunID, - history, - ) - s.NoError(err) -} - -func (s *engineSuite) TestReapplyEvents_IgnoreSameVersionEvents() { - workflowExecution := types.WorkflowExecution{ - WorkflowID: "test-reapply-same-version", - RunID: constants.TestRunID, - } - history := []*types.HistoryEvent{ - { - ID: 1, - EventType: types.EventTypeTimerStarted.Ptr(), - Version: common.EmptyVersion, - }, - } - msBuilder := execution.NewMutableStateBuilderWithEventV2( - s.mockHistoryEngine.shard, - testlogger.New(s.Suite.T()), - workflowExecution.GetRunID(), - constants.TestLocalDomainEntry, - ) - - ms := execution.CreatePersistenceMutableState(msBuilder) - gwmsResponse := &persistence.GetWorkflowExecutionResponse{State: ms} - gceResponse := &persistence.GetCurrentExecutionResponse{RunID: constants.TestRunID} - s.mockExecutionMgr.On("GetCurrentExecution", mock.Anything, mock.Anything).Return(gceResponse, nil).Once() - s.mockExecutionMgr.On("GetWorkflowExecution", mock.Anything, mock.Anything).Return(gwmsResponse, nil).Once() - s.mockEventsReapplier.EXPECT().ReapplyEvents(gomock.Any(), gomock.Any(), gomock.Any(), gomock.Any()).Times(0) - - err := s.mockHistoryEngine.ReapplyEvents( - context.Background(), - constants.TestDomainID, - workflowExecution.WorkflowID, - workflowExecution.RunID, - history, - ) - s.NoError(err) -} - -func (s *engineSuite) TestReapplyEvents_ResetWorkflow() { - workflowExecution := types.WorkflowExecution{ - WorkflowID: "test-reapply-reset-workflow", - RunID: constants.TestRunID, - } - history := []*types.HistoryEvent{ - { - ID: 1, - EventType: types.EventTypeWorkflowExecutionSignaled.Ptr(), - Version: 100, - }, - } - msBuilder := execution.NewMutableStateBuilderWithEventV2( - s.mockHistoryEngine.shard, - testlogger.New(s.Suite.T()), - workflowExecution.GetRunID(), - constants.TestLocalDomainEntry, - ) - ms := execution.CreatePersistenceMutableState(msBuilder) - ms.ExecutionInfo.State = persistence.WorkflowStateCompleted - ms.ExecutionInfo.LastProcessedEvent = 1 - token, err := msBuilder.GetCurrentBranchToken() - s.NoError(err) - item := persistence.NewVersionHistoryItem(1, 1) - versionHistory := persistence.NewVersionHistory(token, []*persistence.VersionHistoryItem{item}) - ms.VersionHistories = persistence.NewVersionHistories(versionHistory) - gwmsResponse := &persistence.GetWorkflowExecutionResponse{State: ms} - gceResponse := &persistence.GetCurrentExecutionResponse{RunID: constants.TestRunID} - s.mockExecutionMgr.On("GetCurrentExecution", mock.Anything, mock.Anything).Return(gceResponse, nil).Once() - s.mockExecutionMgr.On("GetWorkflowExecution", mock.Anything, mock.Anything).Return(gwmsResponse, nil).Once() - s.mockEventsReapplier.EXPECT().ReapplyEvents(gomock.Any(), gomock.Any(), gomock.Any(), gomock.Any()).Times(0) - s.mockWorkflowResetter.EXPECT().ResetWorkflow(gomock.Any(), gomock.Any(), gomock.Any(), gomock.Any(), gomock.Any(), - gomock.Any(), gomock.Any(), gomock.Any(), gomock.Any(), gomock.Any(), gomock.Any(), gomock.Any(), gomock.Any(), - gomock.Any(), - ).Return(nil).Times(1) - err = s.mockHistoryEngine.ReapplyEvents( - context.Background(), - constants.TestDomainID, - workflowExecution.WorkflowID, - workflowExecution.RunID, - history, - ) - s.NoError(err) -} - -func (s *engineSuite) getBuilder(testDomainID string, we types.WorkflowExecution) execution.MutableState { - context, release, err := s.mockHistoryEngine.executionCache.GetOrCreateWorkflowExecutionForBackground(testDomainID, we) - if err != nil { - return nil - } - defer release(nil) - - return context.GetWorkflowExecution() -} - -func (s *engineSuite) getActivityScheduledEvent( - msBuilder execution.MutableState, - scheduleID int64, -) *types.HistoryEvent { - event, _ := msBuilder.GetActivityScheduledEvent(context.Background(), scheduleID) - return event -} - -func (s *engineSuite) printHistory(builder execution.MutableState) string { - return thrift.FromHistory(builder.GetHistoryBuilder().GetHistory()).String() -} - -func TestRecordChildExecutionCompleted(t *testing.T) { - testCases := []struct { - name string - request *types.RecordChildExecutionCompletedRequest - mockSetup func(*execution.MockMutableState) - wantErr bool - assertErr func(t *testing.T, err error) - }{ - { - name: "workflow not running", - request: &types.RecordChildExecutionCompletedRequest{ - DomainUUID: "58f7998e-9c00-4827-bbd3-6a891b3ca0ca", - InitiatedID: 1, - WorkflowExecution: &types.WorkflowExecution{ - WorkflowID: "wid", - RunID: "4353ddce-ca34-4c78-9785-dc0b83af4bbc", - }, - CompletedExecution: &types.WorkflowExecution{ - WorkflowID: "wid1", - RunID: "312b2440-2859-4e50-a59f-d92a300a072d", - }, - }, - mockSetup: func(ms *execution.MockMutableState) { - ms.EXPECT().IsWorkflowExecutionRunning().Return(false) - }, - wantErr: true, - assertErr: func(t *testing.T, err error) { - assert.Equal(t, workflow.ErrNotExists, err) - }, - }, - { - name: "stale mutable state - not containing initiated event", - request: &types.RecordChildExecutionCompletedRequest{ - DomainUUID: "58f7998e-9c00-4827-bbd3-6a891b3ca0ca", - InitiatedID: 10, - WorkflowExecution: &types.WorkflowExecution{ - WorkflowID: "wid", - RunID: "4353ddce-ca34-4c78-9785-dc0b83af4bbc", - }, - CompletedExecution: &types.WorkflowExecution{ - WorkflowID: "wid1", - RunID: "312b2440-2859-4e50-a59f-d92a300a072d", - }, - }, - mockSetup: func(ms *execution.MockMutableState) { - ms.EXPECT().IsWorkflowExecutionRunning().Return(true) - ms.EXPECT().GetChildExecutionInfo(int64(10)).Return(nil, false) - ms.EXPECT().GetNextEventID().Return(int64(10)).Times(2) - }, - wantErr: true, - assertErr: func(t *testing.T, err error) { - assert.Equal(t, workflow.ErrStaleState, err) - }, - }, - { - name: "pending child execution not found", - request: &types.RecordChildExecutionCompletedRequest{ - DomainUUID: "58f7998e-9c00-4827-bbd3-6a891b3ca0ca", - InitiatedID: 10, - WorkflowExecution: &types.WorkflowExecution{ - WorkflowID: "wid", - RunID: "4353ddce-ca34-4c78-9785-dc0b83af4bbc", - }, - CompletedExecution: &types.WorkflowExecution{ - WorkflowID: "wid1", - RunID: "312b2440-2859-4e50-a59f-d92a300a072d", - }, - }, - mockSetup: func(ms *execution.MockMutableState) { - ms.EXPECT().IsWorkflowExecutionRunning().Return(true) - ms.EXPECT().GetChildExecutionInfo(int64(10)).Return(nil, false) - ms.EXPECT().GetNextEventID().Return(int64(11)).Times(1) - }, - wantErr: true, - assertErr: func(t *testing.T, err error) { - assert.Equal(t, &types.EntityNotExistsError{Message: "Pending child execution not found."}, err) - }, - }, - { - name: "stale mutable state - not containing started event", - request: &types.RecordChildExecutionCompletedRequest{ - DomainUUID: "58f7998e-9c00-4827-bbd3-6a891b3ca0ca", - InitiatedID: 10, - WorkflowExecution: &types.WorkflowExecution{ - WorkflowID: "wid", - RunID: "4353ddce-ca34-4c78-9785-dc0b83af4bbc", - }, - CompletedExecution: &types.WorkflowExecution{ - WorkflowID: "wid1", - RunID: "312b2440-2859-4e50-a59f-d92a300a072d", - }, - StartedID: 11, - }, - mockSetup: func(ms *execution.MockMutableState) { - ms.EXPECT().IsWorkflowExecutionRunning().Return(true) - ms.EXPECT().GetChildExecutionInfo(int64(10)).Return(&persistence.ChildExecutionInfo{StartedID: common.EmptyEventID}, true) - ms.EXPECT().GetNextEventID().Return(int64(11)).Times(2) - }, - wantErr: true, - assertErr: func(t *testing.T, err error) { - assert.Equal(t, workflow.ErrStaleState, err) - }, - }, - { - name: "pending child execution not started", - request: &types.RecordChildExecutionCompletedRequest{ - DomainUUID: "58f7998e-9c00-4827-bbd3-6a891b3ca0ca", - InitiatedID: 10, - WorkflowExecution: &types.WorkflowExecution{ - WorkflowID: "wid", - RunID: "4353ddce-ca34-4c78-9785-dc0b83af4bbc", - }, - CompletedExecution: &types.WorkflowExecution{ - WorkflowID: "wid1", - RunID: "312b2440-2859-4e50-a59f-d92a300a072d", - }, - StartedID: 11, - }, - mockSetup: func(ms *execution.MockMutableState) { - ms.EXPECT().IsWorkflowExecutionRunning().Return(true) - ms.EXPECT().GetChildExecutionInfo(int64(10)).Return(&persistence.ChildExecutionInfo{StartedID: common.EmptyEventID}, true) - ms.EXPECT().GetNextEventID().Return(int64(12)).Times(1) - }, - wantErr: true, - assertErr: func(t *testing.T, err error) { - assert.Equal(t, &types.EntityNotExistsError{Message: "Pending child execution not started."}, err) - }, - }, - { - name: "pending child execution workflowID mismatch", - request: &types.RecordChildExecutionCompletedRequest{ - DomainUUID: "58f7998e-9c00-4827-bbd3-6a891b3ca0ca", - InitiatedID: 10, - WorkflowExecution: &types.WorkflowExecution{ - WorkflowID: "wid", - RunID: "4353ddce-ca34-4c78-9785-dc0b83af4bbc", - }, - CompletedExecution: &types.WorkflowExecution{ - WorkflowID: "wid1", - RunID: "312b2440-2859-4e50-a59f-d92a300a072d", - }, - StartedID: 11, - }, - mockSetup: func(ms *execution.MockMutableState) { - ms.EXPECT().IsWorkflowExecutionRunning().Return(true) - ms.EXPECT().GetChildExecutionInfo(int64(10)).Return(&persistence.ChildExecutionInfo{StartedID: 11, StartedWorkflowID: "wid0"}, true) - }, - wantErr: true, - assertErr: func(t *testing.T, err error) { - assert.Equal(t, &types.EntityNotExistsError{Message: "Pending child execution workflowID mismatch."}, err) - }, - }, - { - name: "success - child workflow completed", - request: &types.RecordChildExecutionCompletedRequest{ - DomainUUID: "58f7998e-9c00-4827-bbd3-6a891b3ca0ca", - InitiatedID: 10, - WorkflowExecution: &types.WorkflowExecution{ - WorkflowID: "wid", - RunID: "4353ddce-ca34-4c78-9785-dc0b83af4bbc", - }, - CompletedExecution: &types.WorkflowExecution{ - WorkflowID: "wid1", - RunID: "312b2440-2859-4e50-a59f-d92a300a072d", - }, - CompletionEvent: &types.HistoryEvent{ - EventType: types.EventTypeWorkflowExecutionCompleted.Ptr(), - WorkflowExecutionCompletedEventAttributes: &types.WorkflowExecutionCompletedEventAttributes{ - Result: []byte("success"), - }, - }, - StartedID: 11, - }, - mockSetup: func(ms *execution.MockMutableState) { - ms.EXPECT().IsWorkflowExecutionRunning().Return(true) - ms.EXPECT().GetChildExecutionInfo(int64(10)).Return(&persistence.ChildExecutionInfo{StartedID: 11, StartedWorkflowID: "wid1"}, true) - ms.EXPECT().AddChildWorkflowExecutionCompletedEvent(int64(10), gomock.Any(), gomock.Any()).Return(nil, nil) - }, - wantErr: false, - }, - } - - for _, tc := range testCases { - t.Run(tc.name, func(t *testing.T) { - ctrl := gomock.NewController(t) - mockShard := shard.NewTestContext(t, ctrl, &persistence.ShardInfo{}, config.NewForTest()) - mockDomainCache := mockShard.Resource.DomainCache - testDomainEntry := cache.NewLocalDomainCacheEntryForTest( - &persistence.DomainInfo{ID: constants.TestDomainID}, &persistence.DomainConfig{}, "", - ) - mockDomainCache.EXPECT().GetDomainByID(gomock.Any()).Return(testDomainEntry, nil).AnyTimes() - mockDomainCache.EXPECT().GetDomainName(gomock.Any()).Return(constants.TestDomainID, nil).AnyTimes() - ms := execution.NewMockMutableState(ctrl) - tc.mockSetup(ms) - - historyEngine := &historyEngineImpl{ - shard: mockShard, - clusterMetadata: mockShard.GetClusterMetadata(), - timeSource: mockShard.GetTimeSource(), - metricsClient: metrics.NewClient(tally.NoopScope, metrics.History), - logger: mockShard.GetLogger(), - updateWithActionFn: func(_ context.Context, _ *execution.Cache, _ string, _ types.WorkflowExecution, _ bool, _ time.Time, actionFn func(wfContext execution.Context, mutableState execution.MutableState) error) error { - return actionFn(nil, ms) - }, - } - - err := historyEngine.RecordChildExecutionCompleted(context.Background(), tc.request) - if tc.wantErr { - tc.assertErr(t, err) - } else { - assert.NoError(t, err) - } - }) - } -} diff --git a/service/history/engine/engineimpl/history_engine_test.go b/service/history/engine/engineimpl/history_engine_test.go index 3e26cd68234..aed2550367f 100644 --- a/service/history/engine/engineimpl/history_engine_test.go +++ b/service/history/engine/engineimpl/history_engine_test.go @@ -22,15 +22,5445 @@ package engineimpl import ( + "context" + "encoding/json" + "errors" + "sync" "testing" + "time" - "github.com/uber/cadence/service/history/engine/testdata" + "github.com/golang/mock/gomock" + "github.com/pborman/uuid" + "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/mock" + "github.com/stretchr/testify/require" + "github.com/stretchr/testify/suite" + "github.com/uber-go/tally" + "go.uber.org/yarpc/api/encoding" + "go.uber.org/yarpc/api/transport" + + hclient "github.com/uber/cadence/client/history" + "github.com/uber/cadence/client/matching" + "github.com/uber/cadence/common" + "github.com/uber/cadence/common/cache" + cc "github.com/uber/cadence/common/client" + "github.com/uber/cadence/common/clock" + "github.com/uber/cadence/common/cluster" + "github.com/uber/cadence/common/dynamicconfig" + "github.com/uber/cadence/common/log/testlogger" + "github.com/uber/cadence/common/metrics" + "github.com/uber/cadence/common/mocks" + "github.com/uber/cadence/common/persistence" + "github.com/uber/cadence/common/types" + "github.com/uber/cadence/common/types/mapper/thrift" + "github.com/uber/cadence/service/history/config" + "github.com/uber/cadence/service/history/constants" + "github.com/uber/cadence/service/history/decision" + "github.com/uber/cadence/service/history/events" + "github.com/uber/cadence/service/history/execution" + "github.com/uber/cadence/service/history/ndc" + "github.com/uber/cadence/service/history/query" + "github.com/uber/cadence/service/history/queue" + "github.com/uber/cadence/service/history/reset" + "github.com/uber/cadence/service/history/shard" + test "github.com/uber/cadence/service/history/testing" + "github.com/uber/cadence/service/history/workflow" +) + +type ( + engineSuite struct { + suite.Suite + *require.Assertions + + controller *gomock.Controller + mockShard *shard.TestContext + mockTxProcessor *queue.MockProcessor + mockTimerProcessor *queue.MockProcessor + mockDomainCache *cache.MockDomainCache + mockHistoryClient *hclient.MockClient + mockMatchingClient *matching.MockClient + mockEventsReapplier *ndc.MockEventsReapplier + mockWorkflowResetter *reset.MockWorkflowResetter + + mockHistoryEngine *historyEngineImpl + mockExecutionMgr *mocks.ExecutionManager + mockHistoryV2Mgr *mocks.HistoryV2Manager + mockShardManager *mocks.ShardManager + + eventsCache events.Cache + config *config.Config + } ) -func TestHistoryEngineStartStop(t *testing.T) { - eft := testdata.NewEngineForTest(t, NewEngineWithShardContext) - defer eft.Cleanup() +func TestEngineSuite(t *testing.T) { + s := new(engineSuite) + suite.Run(t, s) +} + +func (s *engineSuite) SetupSuite() { + s.config = config.NewForTest() +} + +func (s *engineSuite) TearDownSuite() { +} + +func (s *engineSuite) SetupTest() { + s.Assertions = require.New(s.T()) + + s.controller = gomock.NewController(s.T()) + s.mockTxProcessor = queue.NewMockProcessor(s.controller) + s.mockTimerProcessor = queue.NewMockProcessor(s.controller) + s.mockEventsReapplier = ndc.NewMockEventsReapplier(s.controller) + s.mockWorkflowResetter = reset.NewMockWorkflowResetter(s.controller) + s.mockTxProcessor.EXPECT().NotifyNewTask(gomock.Any(), gomock.Any()).AnyTimes() + s.mockTimerProcessor.EXPECT().NotifyNewTask(gomock.Any(), gomock.Any()).AnyTimes() + + s.mockShard = shard.NewTestContext( + s.T(), + s.controller, + &persistence.ShardInfo{ + RangeID: 1, + TransferAckLevel: 0, + }, + s.config, + ) + s.eventsCache = events.NewCache( + s.mockShard.GetShardID(), + s.mockShard.GetHistoryManager(), + s.config, + s.mockShard.GetLogger(), + s.mockShard.GetMetricsClient(), + s.mockDomainCache, + ) + s.mockShard.SetEventsCache(s.eventsCache) + + s.mockMatchingClient = s.mockShard.Resource.MatchingClient + s.mockHistoryClient = s.mockShard.Resource.HistoryClient + s.mockExecutionMgr = s.mockShard.Resource.ExecutionMgr + s.mockHistoryV2Mgr = s.mockShard.Resource.HistoryMgr + s.mockShardManager = s.mockShard.Resource.ShardMgr + s.mockDomainCache = s.mockShard.Resource.DomainCache + s.mockDomainCache.EXPECT().GetDomainByID(constants.TestDomainID).Return(constants.TestLocalDomainEntry, nil).AnyTimes() + s.mockDomainCache.EXPECT().GetDomainName(constants.TestDomainID).Return(constants.TestDomainName, nil).AnyTimes() + s.mockDomainCache.EXPECT().GetDomain(constants.TestDomainName).Return(constants.TestLocalDomainEntry, nil).AnyTimes() + s.mockDomainCache.EXPECT().GetDomainID(constants.TestDomainName).Return(constants.TestDomainID, nil).AnyTimes() + + historyEventNotifier := events.NewNotifier( + clock.NewRealTimeSource(), + s.mockShard.Resource.MetricsClient, + func(workflowID string) int { + return len(workflowID) + }, + ) + + h := &historyEngineImpl{ + currentClusterName: s.mockShard.GetClusterMetadata().GetCurrentClusterName(), + shard: s.mockShard, + timeSource: s.mockShard.GetTimeSource(), + clusterMetadata: s.mockShard.Resource.ClusterMetadata, + executionManager: s.mockExecutionMgr, + historyV2Mgr: s.mockHistoryV2Mgr, + executionCache: execution.NewCache(s.mockShard), + logger: s.mockShard.GetLogger(), + metricsClient: s.mockShard.GetMetricsClient(), + tokenSerializer: common.NewJSONTaskTokenSerializer(), + historyEventNotifier: historyEventNotifier, + config: config.NewForTest(), + txProcessor: s.mockTxProcessor, + timerProcessor: s.mockTimerProcessor, + clientChecker: cc.NewVersionChecker(), + eventsReapplier: s.mockEventsReapplier, + workflowResetter: s.mockWorkflowResetter, + } + s.mockShard.SetEngine(h) + h.decisionHandler = decision.NewHandler(s.mockShard, h.executionCache, h.tokenSerializer) + + h.historyEventNotifier.Start() + + s.mockHistoryEngine = h +} + +func (s *engineSuite) TearDownTest() { + s.controller.Finish() + s.mockShard.Finish(s.T()) + s.mockHistoryEngine.historyEventNotifier.Stop() +} + +func (s *engineSuite) TestGetMutableStateSync() { + ctx := context.Background() + + workflowExecution := types.WorkflowExecution{ + WorkflowID: "test-get-workflow-execution-event-id", + RunID: constants.TestRunID, + } + tasklist := "testTaskList" + identity := "testIdentity" + + msBuilder := execution.NewMutableStateBuilderWithEventV2( + s.mockHistoryEngine.shard, + testlogger.New(s.Suite.T()), + workflowExecution.GetRunID(), + constants.TestLocalDomainEntry, + ) + test.AddWorkflowExecutionStartedEvent(msBuilder, workflowExecution, "wType", tasklist, []byte("input"), 100, 200, identity) + di := test.AddDecisionTaskScheduledEvent(msBuilder) + test.AddDecisionTaskStartedEvent(msBuilder, di.ScheduleID, tasklist, identity) + ms := execution.CreatePersistenceMutableState(msBuilder) + gweResponse := &persistence.GetWorkflowExecutionResponse{State: ms} + // right now the next event ID is 4 + s.mockExecutionMgr.On("GetWorkflowExecution", mock.Anything, mock.Anything).Return(gweResponse, nil).Once() + + // test get the next event ID instantly + response, err := s.mockHistoryEngine.GetMutableState(ctx, &types.GetMutableStateRequest{ + DomainUUID: constants.TestDomainID, + Execution: &workflowExecution, + }) + s.Nil(err) + s.Equal(int64(4), response.GetNextEventID()) +} + +func (s *engineSuite) TestGetMutableState_IntestRunID() { + ctx := context.Background() + + execution := types.WorkflowExecution{ + WorkflowID: "test-get-workflow-execution-event-id", + RunID: "run-id-not-valid-uuid", + } + + _, err := s.mockHistoryEngine.GetMutableState(ctx, &types.GetMutableStateRequest{ + DomainUUID: constants.TestDomainID, + Execution: &execution, + }) + s.Equal(constants.ErrRunIDNotValid, err) +} + +func (s *engineSuite) TestGetMutableState_EmptyRunID() { + ctx := context.Background() + + execution := types.WorkflowExecution{ + WorkflowID: "test-get-workflow-execution-event-id", + } + + s.mockExecutionMgr.On("GetCurrentExecution", mock.Anything, mock.Anything).Return(nil, &types.EntityNotExistsError{}).Once() + + _, err := s.mockHistoryEngine.GetMutableState(ctx, &types.GetMutableStateRequest{ + DomainUUID: constants.TestDomainID, + Execution: &execution, + }) + s.Equal(&types.EntityNotExistsError{}, err) +} + +func (s *engineSuite) TestGetMutableStateLongPoll() { + ctx := context.Background() + + workflowExecution := types.WorkflowExecution{ + WorkflowID: "test-get-workflow-execution-event-id", + RunID: constants.TestRunID, + } + tasklist := "testTaskList" + identity := "testIdentity" + + msBuilder := execution.NewMutableStateBuilderWithEventV2( + s.mockHistoryEngine.shard, + testlogger.New(s.Suite.T()), + workflowExecution.GetRunID(), + constants.TestLocalDomainEntry, + ) + test.AddWorkflowExecutionStartedEvent(msBuilder, workflowExecution, "wType", tasklist, []byte("input"), 100, 200, identity) + di := test.AddDecisionTaskScheduledEvent(msBuilder) + test.AddDecisionTaskStartedEvent(msBuilder, di.ScheduleID, tasklist, identity) + ms := execution.CreatePersistenceMutableState(msBuilder) + gweResponse := &persistence.GetWorkflowExecutionResponse{State: ms} + // right now the next event ID is 4 + s.mockExecutionMgr.On("GetWorkflowExecution", mock.Anything, mock.Anything).Return(gweResponse, nil).Once() + + // test long poll on next event ID change + waitGroup := &sync.WaitGroup{} + waitGroup.Add(1) + asycWorkflowUpdate := func(delay time.Duration) { + taskToken, _ := json.Marshal(&common.TaskToken{ + WorkflowID: workflowExecution.WorkflowID, + RunID: workflowExecution.RunID, + ScheduleID: 2, + }) + s.mockHistoryV2Mgr.On("AppendHistoryNodes", mock.Anything, mock.Anything).Return(&persistence.AppendHistoryNodesResponse{}, nil).Once() + s.mockExecutionMgr.On("UpdateWorkflowExecution", mock.Anything, mock.Anything).Return(&persistence.UpdateWorkflowExecutionResponse{MutableStateUpdateSessionStats: &persistence.MutableStateUpdateSessionStats{}}, nil).Once() + + timer := time.NewTimer(delay) + + <-timer.C + _, err := s.mockHistoryEngine.RespondDecisionTaskCompleted(context.Background(), &types.HistoryRespondDecisionTaskCompletedRequest{ + DomainUUID: constants.TestDomainID, + CompleteRequest: &types.RespondDecisionTaskCompletedRequest{ + TaskToken: taskToken, + Identity: identity, + }, + }) + s.Nil(err) + waitGroup.Done() + // right now the next event ID is 5 + } + + // return immediately, since the expected next event ID appears + response, err := s.mockHistoryEngine.GetMutableState(ctx, &types.GetMutableStateRequest{ + DomainUUID: constants.TestDomainID, + Execution: &workflowExecution, + ExpectedNextEventID: 3, + }) + s.Nil(err) + s.Equal(int64(4), response.NextEventID) + + // long poll, new event happen before long poll timeout + go asycWorkflowUpdate(time.Second * 2) + start := time.Now() + pollResponse, err := s.mockHistoryEngine.PollMutableState(ctx, &types.PollMutableStateRequest{ + DomainUUID: constants.TestDomainID, + Execution: &workflowExecution, + ExpectedNextEventID: 4, + }) + s.True(time.Now().After(start.Add(time.Second * 1))) + s.Nil(err) + s.Equal(int64(5), pollResponse.GetNextEventID()) + waitGroup.Wait() +} + +func (s *engineSuite) TestGetMutableStateLongPoll_CurrentBranchChanged() { + ctx := context.Background() + + workflowExecution := types.WorkflowExecution{ + WorkflowID: "test-get-workflow-execution-event-id", + RunID: constants.TestRunID, + } + tasklist := "testTaskList" + identity := "testIdentity" + + msBuilder := execution.NewMutableStateBuilderWithEventV2( + s.mockHistoryEngine.shard, + testlogger.New(s.Suite.T()), + workflowExecution.GetRunID(), + constants.TestLocalDomainEntry, + ) + test.AddWorkflowExecutionStartedEvent(msBuilder, workflowExecution, "wType", tasklist, []byte("input"), 100, 200, identity) + di := test.AddDecisionTaskScheduledEvent(msBuilder) + test.AddDecisionTaskStartedEvent(msBuilder, di.ScheduleID, tasklist, identity) + ms := execution.CreatePersistenceMutableState(msBuilder) + gweResponse := &persistence.GetWorkflowExecutionResponse{State: ms} + // right now the next event ID is 4 + s.mockExecutionMgr.On("GetWorkflowExecution", mock.Anything, mock.Anything).Return(gweResponse, nil).Once() + + // test long poll on next event ID change + asyncBranchTokenUpdate := func(delay time.Duration) { + timer := time.NewTimer(delay) + <-timer.C + newExecution := &types.WorkflowExecution{ + WorkflowID: workflowExecution.WorkflowID, + RunID: workflowExecution.RunID, + } + s.mockHistoryEngine.historyEventNotifier.NotifyNewHistoryEvent(events.NewNotification( + "constants.TestDomainID", + newExecution, + int64(1), + int64(4), + int64(1), + []byte{1}, + persistence.WorkflowStateCreated, + persistence.WorkflowCloseStatusNone)) + } + + // return immediately, since the expected next event ID appears + response0, err := s.mockHistoryEngine.GetMutableState(ctx, &types.GetMutableStateRequest{ + DomainUUID: constants.TestDomainID, + Execution: &workflowExecution, + ExpectedNextEventID: 3, + }) + s.Nil(err) + s.Equal(int64(4), response0.GetNextEventID()) + + // long poll, new event happen before long poll timeout + go asyncBranchTokenUpdate(time.Second * 2) + start := time.Now() + response1, err := s.mockHistoryEngine.GetMutableState(ctx, &types.GetMutableStateRequest{ + DomainUUID: constants.TestDomainID, + Execution: &workflowExecution, + ExpectedNextEventID: 10, + }) + s.True(time.Now().After(start.Add(time.Second * 1))) + s.Nil(err) + s.Equal(response0.GetCurrentBranchToken(), response1.GetCurrentBranchToken()) +} + +func (s *engineSuite) TestGetMutableStateLongPollTimeout() { + ctx := context.Background() + + workflowExecution := types.WorkflowExecution{ + WorkflowID: "test-get-workflow-execution-event-id", + RunID: constants.TestRunID, + } + tasklist := "testTaskList" + identity := "testIdentity" + + msBuilder := execution.NewMutableStateBuilderWithEventV2( + s.mockHistoryEngine.shard, + testlogger.New(s.Suite.T()), + workflowExecution.GetRunID(), + constants.TestLocalDomainEntry, + ) + test.AddWorkflowExecutionStartedEvent(msBuilder, workflowExecution, "wType", tasklist, []byte("input"), 100, 200, identity) + di := test.AddDecisionTaskScheduledEvent(msBuilder) + test.AddDecisionTaskStartedEvent(msBuilder, di.ScheduleID, tasklist, identity) + ms := execution.CreatePersistenceMutableState(msBuilder) + gweResponse := &persistence.GetWorkflowExecutionResponse{State: ms} + // right now the next event ID is 4 + s.mockExecutionMgr.On("GetWorkflowExecution", mock.Anything, mock.Anything).Return(gweResponse, nil).Once() + + // long poll, no event happen after long poll timeout + response, err := s.mockHistoryEngine.GetMutableState(ctx, &types.GetMutableStateRequest{ + DomainUUID: constants.TestDomainID, + Execution: &workflowExecution, + ExpectedNextEventID: 4, + }) + s.Nil(err) + s.Equal(int64(4), response.GetNextEventID()) +} + +func (s *engineSuite) TestQueryWorkflow_RejectBasedOnNotEnabled() { + s.mockHistoryEngine.config.EnableConsistentQueryByDomain = dynamicconfig.GetBoolPropertyFnFilteredByDomain(false) + request := &types.HistoryQueryWorkflowRequest{ + DomainUUID: constants.TestDomainID, + Request: &types.QueryWorkflowRequest{ + QueryConsistencyLevel: types.QueryConsistencyLevelStrong.Ptr(), + }, + } + resp, err := s.mockHistoryEngine.QueryWorkflow(context.Background(), request) + s.Nil(resp) + s.Equal(workflow.ErrConsistentQueryNotEnabled, err) + + s.mockHistoryEngine.config.EnableConsistentQueryByDomain = dynamicconfig.GetBoolPropertyFnFilteredByDomain(true) + s.mockHistoryEngine.config.EnableConsistentQuery = dynamicconfig.GetBoolPropertyFn(false) + resp, err = s.mockHistoryEngine.QueryWorkflow(context.Background(), request) + s.Nil(resp) + s.Equal(workflow.ErrConsistentQueryNotEnabled, err) +} + +func (s *engineSuite) TestQueryWorkflow_RejectBasedOnCompleted() { + workflowExecution := types.WorkflowExecution{ + WorkflowID: "TestQueryWorkflow_RejectBasedOnCompleted", + RunID: constants.TestRunID, + } + tasklist := "testTaskList" + identity := "testIdentity" + + msBuilder := execution.NewMutableStateBuilderWithEventV2( + s.mockHistoryEngine.shard, + testlogger.New(s.Suite.T()), + workflowExecution.GetRunID(), + constants.TestLocalDomainEntry, + ) + test.AddWorkflowExecutionStartedEvent(msBuilder, workflowExecution, "wType", tasklist, []byte("input"), 100, 200, identity) + di := test.AddDecisionTaskScheduledEvent(msBuilder) + event := test.AddDecisionTaskStartedEvent(msBuilder, di.ScheduleID, tasklist, identity) + di.StartedID = event.ID + event = test.AddDecisionTaskCompletedEvent(msBuilder, di.ScheduleID, di.StartedID, nil, "some random identity") + test.AddCompleteWorkflowEvent(msBuilder, event.ID, nil) + ms := execution.CreatePersistenceMutableState(msBuilder) + gweResponse := &persistence.GetWorkflowExecutionResponse{State: ms} + s.mockExecutionMgr.On("GetWorkflowExecution", mock.Anything, mock.Anything).Return(gweResponse, nil).Once() + + request := &types.HistoryQueryWorkflowRequest{ + DomainUUID: constants.TestDomainID, + Request: &types.QueryWorkflowRequest{ + Execution: &workflowExecution, + Query: &types.WorkflowQuery{}, + QueryRejectCondition: types.QueryRejectConditionNotOpen.Ptr(), + }, + } + resp, err := s.mockHistoryEngine.QueryWorkflow(context.Background(), request) + s.NoError(err) + s.Nil(resp.GetResponse().QueryResult) + s.NotNil(resp.GetResponse().QueryRejected) + s.Equal(types.WorkflowExecutionCloseStatusCompleted.Ptr(), resp.GetResponse().GetQueryRejected().CloseStatus) +} + +func (s *engineSuite) TestQueryWorkflow_RejectBasedOnFailed() { + workflowExecution := types.WorkflowExecution{ + WorkflowID: "TestQueryWorkflow_RejectBasedOnFailed", + RunID: constants.TestRunID, + } + tasklist := "testTaskList" + identity := "testIdentity" + + msBuilder := execution.NewMutableStateBuilderWithEventV2( + s.mockHistoryEngine.shard, + testlogger.New(s.Suite.T()), + workflowExecution.GetRunID(), + constants.TestLocalDomainEntry, + ) + test.AddWorkflowExecutionStartedEvent(msBuilder, workflowExecution, "wType", tasklist, []byte("input"), 100, 200, identity) + di := test.AddDecisionTaskScheduledEvent(msBuilder) + event := test.AddDecisionTaskStartedEvent(msBuilder, di.ScheduleID, tasklist, identity) + di.StartedID = event.ID + event = test.AddDecisionTaskCompletedEvent(msBuilder, di.ScheduleID, di.StartedID, nil, "some random identity") + test.AddFailWorkflowEvent(msBuilder, event.ID, "failure reason", []byte{1, 2, 3}) + ms := execution.CreatePersistenceMutableState(msBuilder) + gweResponse := &persistence.GetWorkflowExecutionResponse{State: ms} + s.mockExecutionMgr.On("GetWorkflowExecution", mock.Anything, mock.Anything).Return(gweResponse, nil).Once() + + request := &types.HistoryQueryWorkflowRequest{ + DomainUUID: constants.TestDomainID, + Request: &types.QueryWorkflowRequest{ + Execution: &workflowExecution, + Query: &types.WorkflowQuery{}, + QueryRejectCondition: types.QueryRejectConditionNotOpen.Ptr(), + }, + } + resp, err := s.mockHistoryEngine.QueryWorkflow(context.Background(), request) + s.NoError(err) + s.Nil(resp.GetResponse().QueryResult) + s.NotNil(resp.GetResponse().QueryRejected) + s.Equal(types.WorkflowExecutionCloseStatusFailed.Ptr(), resp.GetResponse().GetQueryRejected().CloseStatus) + + request = &types.HistoryQueryWorkflowRequest{ + DomainUUID: constants.TestDomainID, + Request: &types.QueryWorkflowRequest{ + Execution: &workflowExecution, + Query: &types.WorkflowQuery{}, + QueryRejectCondition: types.QueryRejectConditionNotCompletedCleanly.Ptr(), + }, + } + resp, err = s.mockHistoryEngine.QueryWorkflow(context.Background(), request) + s.NoError(err) + s.Nil(resp.GetResponse().QueryResult) + s.NotNil(resp.GetResponse().QueryRejected) + s.Equal(types.WorkflowExecutionCloseStatusFailed.Ptr(), resp.GetResponse().GetQueryRejected().CloseStatus) +} + +func (s *engineSuite) TestQueryWorkflow_FirstDecisionNotCompleted() { + workflowExecution := types.WorkflowExecution{ + WorkflowID: "TestQueryWorkflow_FirstDecisionNotCompleted", + RunID: constants.TestRunID, + } + tasklist := "testTaskList" + identity := "testIdentity" + + msBuilder := execution.NewMutableStateBuilderWithEventV2( + s.mockHistoryEngine.shard, + testlogger.New(s.Suite.T()), + workflowExecution.GetRunID(), + constants.TestLocalDomainEntry, + ) + test.AddWorkflowExecutionStartedEvent(msBuilder, workflowExecution, "wType", tasklist, []byte("input"), 100, 200, identity) + di := test.AddDecisionTaskScheduledEvent(msBuilder) + test.AddDecisionTaskStartedEvent(msBuilder, di.ScheduleID, tasklist, identity) + ms := execution.CreatePersistenceMutableState(msBuilder) + gweResponse := &persistence.GetWorkflowExecutionResponse{State: ms} + s.mockExecutionMgr.On("GetWorkflowExecution", mock.Anything, mock.Anything).Return(gweResponse, nil).Once() + + request := &types.HistoryQueryWorkflowRequest{ + DomainUUID: constants.TestDomainID, + Request: &types.QueryWorkflowRequest{ + Execution: &workflowExecution, + Query: &types.WorkflowQuery{}, + }, + } + resp, err := s.mockHistoryEngine.QueryWorkflow(context.Background(), request) + s.Equal(workflow.ErrQueryWorkflowBeforeFirstDecision, err) + s.Nil(resp) +} + +func (s *engineSuite) TestQueryWorkflow_DirectlyThroughMatching() { + workflowExecution := types.WorkflowExecution{ + WorkflowID: "TestQueryWorkflow_DirectlyThroughMatching", + RunID: constants.TestRunID, + } + tasklist := "testTaskList" + identity := "testIdentity" + + msBuilder := execution.NewMutableStateBuilderWithEventV2( + s.mockHistoryEngine.shard, + testlogger.New(s.Suite.T()), + workflowExecution.GetRunID(), + constants.TestLocalDomainEntry, + ) + test.AddWorkflowExecutionStartedEvent(msBuilder, workflowExecution, "wType", tasklist, []byte("input"), 100, 200, identity) + di := test.AddDecisionTaskScheduledEvent(msBuilder) + startedEvent := test.AddDecisionTaskStartedEvent(msBuilder, di.ScheduleID, tasklist, identity) + test.AddDecisionTaskCompletedEvent(msBuilder, di.ScheduleID, startedEvent.ID, nil, identity) + di = test.AddDecisionTaskScheduledEvent(msBuilder) + test.AddDecisionTaskStartedEvent(msBuilder, di.ScheduleID, tasklist, identity) + + ms := execution.CreatePersistenceMutableState(msBuilder) + gweResponse := &persistence.GetWorkflowExecutionResponse{State: ms} + s.mockExecutionMgr.On("GetWorkflowExecution", mock.Anything, mock.Anything).Return(gweResponse, nil).Once() + s.mockMatchingClient.EXPECT().QueryWorkflow(gomock.Any(), gomock.Any()).Return(&types.QueryWorkflowResponse{QueryResult: []byte{1, 2, 3}}, nil) + s.mockHistoryEngine.matchingClient = s.mockMatchingClient + request := &types.HistoryQueryWorkflowRequest{ + DomainUUID: constants.TestDomainID, + Request: &types.QueryWorkflowRequest{ + Execution: &workflowExecution, + Query: &types.WorkflowQuery{}, + // since workflow is open this filter does not reject query + QueryRejectCondition: types.QueryRejectConditionNotOpen.Ptr(), + QueryConsistencyLevel: types.QueryConsistencyLevelEventual.Ptr(), + }, + } + resp, err := s.mockHistoryEngine.QueryWorkflow(context.Background(), request) + s.NoError(err) + s.NotNil(resp.GetResponse().QueryResult) + s.Nil(resp.GetResponse().QueryRejected) + s.Equal([]byte{1, 2, 3}, resp.GetResponse().GetQueryResult()) +} + +func (s *engineSuite) TestQueryWorkflow_DecisionTaskDispatch_Timeout() { + workflowExecution := types.WorkflowExecution{ + WorkflowID: "TestQueryWorkflow_DecisionTaskDispatch_Timeout", + RunID: constants.TestRunID, + } + tasklist := "testTaskList" + identity := "testIdentity" + msBuilder := execution.NewMutableStateBuilderWithEventV2( + s.mockHistoryEngine.shard, + testlogger.New(s.Suite.T()), + workflowExecution.GetRunID(), + constants.TestLocalDomainEntry, + ) + test.AddWorkflowExecutionStartedEvent(msBuilder, workflowExecution, "wType", tasklist, []byte("input"), 100, 200, identity) + di := test.AddDecisionTaskScheduledEvent(msBuilder) + startedEvent := test.AddDecisionTaskStartedEvent(msBuilder, di.ScheduleID, tasklist, identity) + test.AddDecisionTaskCompletedEvent(msBuilder, di.ScheduleID, startedEvent.ID, nil, identity) + di = test.AddDecisionTaskScheduledEvent(msBuilder) + test.AddDecisionTaskStartedEvent(msBuilder, di.ScheduleID, tasklist, identity) + + ms := execution.CreatePersistenceMutableState(msBuilder) + gweResponse := &persistence.GetWorkflowExecutionResponse{State: ms} + s.mockExecutionMgr.On("GetWorkflowExecution", mock.Anything, mock.Anything).Return(gweResponse, nil).Once() + request := &types.HistoryQueryWorkflowRequest{ + DomainUUID: constants.TestDomainID, + Request: &types.QueryWorkflowRequest{ + Execution: &workflowExecution, + Query: &types.WorkflowQuery{}, + // since workflow is open this filter does not reject query + QueryRejectCondition: types.QueryRejectConditionNotOpen.Ptr(), + QueryConsistencyLevel: types.QueryConsistencyLevelStrong.Ptr(), + }, + } + + wg := &sync.WaitGroup{} + wg.Add(1) + go func() { + ctx, cancel := context.WithTimeout(context.Background(), time.Second*2) + defer cancel() + resp, err := s.mockHistoryEngine.QueryWorkflow(ctx, request) + s.Error(err) + s.Nil(resp) + wg.Done() + }() + + <-time.After(time.Second) + builder := s.getBuilder(constants.TestDomainID, workflowExecution) + s.NotNil(builder) + qr := builder.GetQueryRegistry() + s.True(qr.HasBufferedQuery()) + s.False(qr.HasCompletedQuery()) + s.False(qr.HasUnblockedQuery()) + s.False(qr.HasFailedQuery()) + wg.Wait() + s.False(qr.HasBufferedQuery()) + s.False(qr.HasCompletedQuery()) + s.False(qr.HasUnblockedQuery()) + s.False(qr.HasFailedQuery()) +} + +func (s *engineSuite) TestQueryWorkflow_ConsistentQueryBufferFull() { + workflowExecution := types.WorkflowExecution{ + WorkflowID: "TestQueryWorkflow_ConsistentQueryBufferFull", + RunID: constants.TestRunID, + } + tasklist := "testTaskList" + identity := "testIdentity" + msBuilder := execution.NewMutableStateBuilderWithEventV2( + s.mockHistoryEngine.shard, + testlogger.New(s.Suite.T()), + workflowExecution.GetRunID(), + constants.TestLocalDomainEntry, + ) + test.AddWorkflowExecutionStartedEvent(msBuilder, workflowExecution, "wType", tasklist, []byte("input"), 100, 200, identity) + di := test.AddDecisionTaskScheduledEvent(msBuilder) + startedEvent := test.AddDecisionTaskStartedEvent(msBuilder, di.ScheduleID, tasklist, identity) + test.AddDecisionTaskCompletedEvent(msBuilder, di.ScheduleID, startedEvent.ID, nil, identity) + di = test.AddDecisionTaskScheduledEvent(msBuilder) + test.AddDecisionTaskStartedEvent(msBuilder, di.ScheduleID, tasklist, identity) + + ms := execution.CreatePersistenceMutableState(msBuilder) + gweResponse := &persistence.GetWorkflowExecutionResponse{State: ms} + s.mockExecutionMgr.On("GetWorkflowExecution", mock.Anything, mock.Anything).Return(gweResponse, nil).Once() + + // buffer query so that when types.QueryWorkflow is called buffer is already full + ctx, release, err := s.mockHistoryEngine.executionCache.GetOrCreateWorkflowExecutionForBackground(constants.TestDomainID, workflowExecution) + s.NoError(err) + loadedMS, err := ctx.LoadWorkflowExecution(context.Background()) + s.NoError(err) + qr := query.NewRegistry() + qr.BufferQuery(&types.WorkflowQuery{}) + loadedMS.SetQueryRegistry(qr) + release(nil) + + request := &types.HistoryQueryWorkflowRequest{ + DomainUUID: constants.TestDomainID, + Request: &types.QueryWorkflowRequest{ + Execution: &workflowExecution, + Query: &types.WorkflowQuery{}, + QueryConsistencyLevel: types.QueryConsistencyLevelStrong.Ptr(), + }, + } + resp, err := s.mockHistoryEngine.QueryWorkflow(context.Background(), request) + s.Nil(resp) + s.Equal(workflow.ErrConsistentQueryBufferExceeded, err) +} + +func (s *engineSuite) TestQueryWorkflow_DecisionTaskDispatch_Complete() { + workflowExecution := types.WorkflowExecution{ + WorkflowID: "TestQueryWorkflow_DecisionTaskDispatch_Complete", + RunID: constants.TestRunID, + } + tasklist := "testTaskList" + identity := "testIdentity" + msBuilder := execution.NewMutableStateBuilderWithEventV2( + s.mockHistoryEngine.shard, + testlogger.New(s.Suite.T()), + workflowExecution.GetRunID(), + constants.TestLocalDomainEntry, + ) + test.AddWorkflowExecutionStartedEvent(msBuilder, workflowExecution, "wType", tasklist, []byte("input"), 100, 200, identity) + di := test.AddDecisionTaskScheduledEvent(msBuilder) + startedEvent := test.AddDecisionTaskStartedEvent(msBuilder, di.ScheduleID, tasklist, identity) + test.AddDecisionTaskCompletedEvent(msBuilder, di.ScheduleID, startedEvent.ID, nil, identity) + di = test.AddDecisionTaskScheduledEvent(msBuilder) + test.AddDecisionTaskStartedEvent(msBuilder, di.ScheduleID, tasklist, identity) + + ms := execution.CreatePersistenceMutableState(msBuilder) + gweResponse := &persistence.GetWorkflowExecutionResponse{State: ms} + s.mockExecutionMgr.On("GetWorkflowExecution", mock.Anything, mock.Anything).Return(gweResponse, nil).Once() + + waitGroup := &sync.WaitGroup{} + waitGroup.Add(1) + asyncQueryUpdate := func(delay time.Duration, answer []byte) { + defer waitGroup.Done() + <-time.After(delay) + builder := s.getBuilder(constants.TestDomainID, workflowExecution) + s.NotNil(builder) + qr := builder.GetQueryRegistry() + buffered := qr.GetBufferedIDs() + for _, id := range buffered { + resultType := types.QueryResultTypeAnswered + completedTerminationState := &query.TerminationState{ + TerminationType: query.TerminationTypeCompleted, + QueryResult: &types.WorkflowQueryResult{ + ResultType: &resultType, + Answer: answer, + }, + } + err := qr.SetTerminationState(id, completedTerminationState) + s.NoError(err) + state, err := qr.GetTerminationState(id) + s.NoError(err) + s.Equal(query.TerminationTypeCompleted, state.TerminationType) + } + } + + request := &types.HistoryQueryWorkflowRequest{ + DomainUUID: constants.TestDomainID, + Request: &types.QueryWorkflowRequest{ + Execution: &workflowExecution, + Query: &types.WorkflowQuery{}, + QueryConsistencyLevel: types.QueryConsistencyLevelStrong.Ptr(), + }, + } + go asyncQueryUpdate(time.Second*2, []byte{1, 2, 3}) + start := time.Now() + resp, err := s.mockHistoryEngine.QueryWorkflow(context.Background(), request) + s.True(time.Now().After(start.Add(time.Second))) + s.NoError(err) + s.Equal([]byte{1, 2, 3}, resp.GetResponse().GetQueryResult()) + builder := s.getBuilder(constants.TestDomainID, workflowExecution) + s.NotNil(builder) + qr := builder.GetQueryRegistry() + s.False(qr.HasBufferedQuery()) + s.False(qr.HasCompletedQuery()) + waitGroup.Wait() +} + +func (s *engineSuite) TestQueryWorkflow_DecisionTaskDispatch_Unblocked() { + workflowExecution := types.WorkflowExecution{ + WorkflowID: "TestQueryWorkflow_DecisionTaskDispatch_Unblocked", + RunID: constants.TestRunID, + } + tasklist := "testTaskList" + identity := "testIdentity" + msBuilder := execution.NewMutableStateBuilderWithEventV2( + s.mockHistoryEngine.shard, + testlogger.New(s.Suite.T()), + workflowExecution.GetRunID(), + constants.TestLocalDomainEntry, + ) + test.AddWorkflowExecutionStartedEvent(msBuilder, workflowExecution, "wType", tasklist, []byte("input"), 100, 200, identity) + di := test.AddDecisionTaskScheduledEvent(msBuilder) + startedEvent := test.AddDecisionTaskStartedEvent(msBuilder, di.ScheduleID, tasklist, identity) + test.AddDecisionTaskCompletedEvent(msBuilder, di.ScheduleID, startedEvent.ID, nil, identity) + di = test.AddDecisionTaskScheduledEvent(msBuilder) + test.AddDecisionTaskStartedEvent(msBuilder, di.ScheduleID, tasklist, identity) + + ms := execution.CreatePersistenceMutableState(msBuilder) + gweResponse := &persistence.GetWorkflowExecutionResponse{State: ms} + s.mockExecutionMgr.On("GetWorkflowExecution", mock.Anything, mock.Anything).Return(gweResponse, nil).Once() + s.mockMatchingClient.EXPECT().QueryWorkflow(gomock.Any(), gomock.Any()).Return(&types.QueryWorkflowResponse{QueryResult: []byte{1, 2, 3}}, nil) + s.mockHistoryEngine.matchingClient = s.mockMatchingClient + waitGroup := &sync.WaitGroup{} + waitGroup.Add(1) + asyncQueryUpdate := func(delay time.Duration, answer []byte) { + defer waitGroup.Done() + <-time.After(delay) + builder := s.getBuilder(constants.TestDomainID, workflowExecution) + s.NotNil(builder) + qr := builder.GetQueryRegistry() + buffered := qr.GetBufferedIDs() + for _, id := range buffered { + s.NoError(qr.SetTerminationState(id, &query.TerminationState{TerminationType: query.TerminationTypeUnblocked})) + state, err := qr.GetTerminationState(id) + s.NoError(err) + s.Equal(query.TerminationTypeUnblocked, state.TerminationType) + } + } + + request := &types.HistoryQueryWorkflowRequest{ + DomainUUID: constants.TestDomainID, + Request: &types.QueryWorkflowRequest{ + Execution: &workflowExecution, + Query: &types.WorkflowQuery{}, + QueryConsistencyLevel: types.QueryConsistencyLevelStrong.Ptr(), + }, + } + go asyncQueryUpdate(time.Second*2, []byte{1, 2, 3}) + start := time.Now() + resp, err := s.mockHistoryEngine.QueryWorkflow(context.Background(), request) + s.True(time.Now().After(start.Add(time.Second))) + s.NoError(err) + s.Equal([]byte{1, 2, 3}, resp.GetResponse().GetQueryResult()) + builder := s.getBuilder(constants.TestDomainID, workflowExecution) + s.NotNil(builder) + qr := builder.GetQueryRegistry() + s.False(qr.HasBufferedQuery()) + s.False(qr.HasCompletedQuery()) + s.False(qr.HasUnblockedQuery()) + waitGroup.Wait() +} + +func (s *engineSuite) TestRespondDecisionTaskCompletedInvalidToken() { + + invalidToken, _ := json.Marshal("bad token") + identity := "testIdentity" + + _, err := s.mockHistoryEngine.RespondDecisionTaskCompleted(context.Background(), &types.HistoryRespondDecisionTaskCompletedRequest{ + DomainUUID: constants.TestDomainID, + CompleteRequest: &types.RespondDecisionTaskCompletedRequest{ + TaskToken: invalidToken, + Decisions: nil, + ExecutionContext: nil, + Identity: identity, + }, + }) + + s.NotNil(err) + s.IsType(&types.BadRequestError{}, err) +} + +func (s *engineSuite) TestRespondDecisionTaskCompletedIfNoExecution() { + + taskToken, _ := json.Marshal(&common.TaskToken{ + WorkflowID: "wId", + RunID: constants.TestRunID, + ScheduleID: 2, + }) + identity := "testIdentity" + + s.mockExecutionMgr.On("GetWorkflowExecution", mock.Anything, mock.Anything).Return(nil, &types.EntityNotExistsError{}).Once() + + _, err := s.mockHistoryEngine.RespondDecisionTaskCompleted(context.Background(), &types.HistoryRespondDecisionTaskCompletedRequest{ + DomainUUID: constants.TestDomainID, + CompleteRequest: &types.RespondDecisionTaskCompletedRequest{ + TaskToken: taskToken, + Identity: identity, + }, + }) + s.NotNil(err) + s.IsType(&types.EntityNotExistsError{}, err) +} + +func (s *engineSuite) TestRespondDecisionTaskCompletedIfGetExecutionFailed() { + + taskToken, _ := json.Marshal(&common.TaskToken{ + WorkflowID: "wId", + RunID: constants.TestRunID, + ScheduleID: 2, + }) + identity := "testIdentity" + + s.mockExecutionMgr.On("GetWorkflowExecution", mock.Anything, mock.Anything).Return(nil, errors.New("FAILED")).Once() + + _, err := s.mockHistoryEngine.RespondDecisionTaskCompleted(context.Background(), &types.HistoryRespondDecisionTaskCompletedRequest{ + DomainUUID: constants.TestDomainID, + CompleteRequest: &types.RespondDecisionTaskCompletedRequest{ + TaskToken: taskToken, + Identity: identity, + }, + }) + s.EqualError(err, "FAILED") +} + +func (s *engineSuite) TestRespondDecisionTaskCompletedUpdateExecutionFailed() { + + we := types.WorkflowExecution{ + WorkflowID: "wId", + RunID: constants.TestRunID, + } + tl := "testTaskList" + + taskToken, _ := json.Marshal(&common.TaskToken{ + WorkflowID: we.WorkflowID, + RunID: we.RunID, + ScheduleID: 2, + }) + identity := "testIdentity" + + msBuilder := execution.NewMutableStateBuilderWithEventV2( + s.mockHistoryEngine.shard, + testlogger.New(s.Suite.T()), + we.GetRunID(), + constants.TestLocalDomainEntry, + ) + test.AddWorkflowExecutionStartedEvent(msBuilder, we, "wType", tl, []byte("input"), 100, 200, identity) + di := test.AddDecisionTaskScheduledEvent(msBuilder) + test.AddDecisionTaskStartedEvent(msBuilder, di.ScheduleID, tl, identity) + + ms := execution.CreatePersistenceMutableState(msBuilder) + gwmsResponse := &persistence.GetWorkflowExecutionResponse{State: ms} + + s.mockExecutionMgr.On("GetWorkflowExecution", mock.Anything, mock.Anything).Return(gwmsResponse, nil).Once() + s.mockHistoryV2Mgr.On("AppendHistoryNodes", mock.Anything, mock.Anything).Return(&persistence.AppendHistoryNodesResponse{}, nil).Once() + s.mockExecutionMgr.On("UpdateWorkflowExecution", mock.Anything, mock.Anything).Return(&persistence.UpdateWorkflowExecutionResponse{MutableStateUpdateSessionStats: &persistence.MutableStateUpdateSessionStats{}}, errors.New("FAILED")).Once() + s.mockShardManager.On("UpdateShard", mock.Anything, mock.Anything).Return(nil).Once() + + _, err := s.mockHistoryEngine.RespondDecisionTaskCompleted(context.Background(), &types.HistoryRespondDecisionTaskCompletedRequest{ + DomainUUID: constants.TestDomainID, + CompleteRequest: &types.RespondDecisionTaskCompletedRequest{ + TaskToken: taskToken, + Identity: identity, + }, + }) + s.NotNil(err) + s.EqualError(err, "FAILED") +} + +func (s *engineSuite) TestRespondDecisionTaskCompletedIfTaskCompleted() { + + we := types.WorkflowExecution{ + WorkflowID: "wId", + RunID: constants.TestRunID, + } + tl := "testTaskList" + taskToken, _ := json.Marshal(&common.TaskToken{ + WorkflowID: we.WorkflowID, + RunID: we.RunID, + ScheduleID: 2, + }) + identity := "testIdentity" + + msBuilder := execution.NewMutableStateBuilderWithEventV2( + s.mockHistoryEngine.shard, + testlogger.New(s.Suite.T()), + we.GetRunID(), + constants.TestLocalDomainEntry, + ) + test.AddWorkflowExecutionStartedEvent(msBuilder, we, "wType", tl, []byte("input"), 100, 200, identity) + di := test.AddDecisionTaskScheduledEvent(msBuilder) + startedEvent := test.AddDecisionTaskStartedEvent(msBuilder, di.ScheduleID, tl, identity) + test.AddDecisionTaskCompletedEvent(msBuilder, di.ScheduleID, startedEvent.ID, nil, identity) + + ms := execution.CreatePersistenceMutableState(msBuilder) + gwmsResponse := &persistence.GetWorkflowExecutionResponse{State: ms} + + s.mockExecutionMgr.On("GetWorkflowExecution", mock.Anything, mock.Anything).Return(gwmsResponse, nil).Once() + + _, err := s.mockHistoryEngine.RespondDecisionTaskCompleted(context.Background(), &types.HistoryRespondDecisionTaskCompletedRequest{ + DomainUUID: constants.TestDomainID, + CompleteRequest: &types.RespondDecisionTaskCompletedRequest{ + TaskToken: taskToken, + Identity: identity, + }, + }) + s.NotNil(err) + s.IsType(&types.EntityNotExistsError{}, err) +} + +func (s *engineSuite) TestRespondDecisionTaskCompletedIfTaskNotStarted() { + + we := types.WorkflowExecution{ + WorkflowID: "wId", + RunID: constants.TestRunID, + } + tl := "testTaskList" + taskToken, _ := json.Marshal(&common.TaskToken{ + WorkflowID: we.WorkflowID, + RunID: we.RunID, + ScheduleID: 2, + }) + identity := "testIdentity" + + msBuilder := execution.NewMutableStateBuilderWithEventV2( + s.mockHistoryEngine.shard, + testlogger.New(s.Suite.T()), + we.GetRunID(), + constants.TestLocalDomainEntry, + ) + test.AddWorkflowExecutionStartedEvent(msBuilder, we, "wType", tl, []byte("input"), 100, 200, identity) + test.AddDecisionTaskScheduledEvent(msBuilder) + + ms := execution.CreatePersistenceMutableState(msBuilder) + gwmsResponse := &persistence.GetWorkflowExecutionResponse{State: ms} + + s.mockExecutionMgr.On("GetWorkflowExecution", mock.Anything, mock.Anything).Return(gwmsResponse, nil).Once() + + _, err := s.mockHistoryEngine.RespondDecisionTaskCompleted(context.Background(), &types.HistoryRespondDecisionTaskCompletedRequest{ + DomainUUID: constants.TestDomainID, + CompleteRequest: &types.RespondDecisionTaskCompletedRequest{ + TaskToken: taskToken, + }, + }) + s.NotNil(err) + s.IsType(&types.EntityNotExistsError{}, err) +} + +func (s *engineSuite) TestRespondDecisionTaskCompletedConflictOnUpdate() { + + we := types.WorkflowExecution{ + WorkflowID: "wId", + RunID: constants.TestRunID, + } + tl := "testTaskList" + identity := "testIdentity" + executionContext := []byte("context") + activity1ID := "activity1" + activity1Type := "activity_type1" + activity1Input := []byte("input1") + activity1Result := []byte("activity1_result") + activity2ID := "activity2" + activity2Type := "activity_type2" + activity2Input := []byte("input2") + activity2Result := []byte("activity2_result") + activity3ID := "activity3" + activity3Type := "activity_type3" + activity3Input := []byte("input3") + + msBuilder := execution.NewMutableStateBuilderWithEventV2( + s.mockHistoryEngine.shard, + testlogger.New(s.Suite.T()), + we.GetRunID(), + constants.TestLocalDomainEntry, + ) + test.AddWorkflowExecutionStartedEvent(msBuilder, we, "wType", tl, []byte("input"), 100, 100, identity) + di1 := test.AddDecisionTaskScheduledEvent(msBuilder) + decisionStartedEvent1 := test.AddDecisionTaskStartedEvent(msBuilder, di1.ScheduleID, tl, identity) + decisionCompletedEvent1 := test.AddDecisionTaskCompletedEvent(msBuilder, di1.ScheduleID, + decisionStartedEvent1.ID, nil, identity) + activity1ScheduledEvent, _ := test.AddActivityTaskScheduledEvent(msBuilder, decisionCompletedEvent1.ID, + activity1ID, activity1Type, tl, activity1Input, 100, 10, 1, 5) + activity2ScheduledEvent, _ := test.AddActivityTaskScheduledEvent(msBuilder, decisionCompletedEvent1.ID, + activity2ID, activity2Type, tl, activity2Input, 100, 10, 1, 5) + activity1StartedEvent := test.AddActivityTaskStartedEvent(msBuilder, activity1ScheduledEvent.ID, identity) + activity2StartedEvent := test.AddActivityTaskStartedEvent(msBuilder, activity2ScheduledEvent.ID, identity) + test.AddActivityTaskCompletedEvent(msBuilder, activity1ScheduledEvent.ID, + activity1StartedEvent.ID, activity1Result, identity) + di2 := test.AddDecisionTaskScheduledEvent(msBuilder) + decisionStartedEvent2 := test.AddDecisionTaskStartedEvent(msBuilder, di2.ScheduleID, tl, identity) + + taskToken, _ := json.Marshal(&common.TaskToken{ + WorkflowID: "wId", + RunID: we.GetRunID(), + ScheduleID: di2.ScheduleID, + }) + + decisions := []*types.Decision{{ + DecisionType: types.DecisionTypeScheduleActivityTask.Ptr(), + ScheduleActivityTaskDecisionAttributes: &types.ScheduleActivityTaskDecisionAttributes{ + ActivityID: activity3ID, + ActivityType: &types.ActivityType{Name: activity3Type}, + TaskList: &types.TaskList{Name: tl}, + Input: activity3Input, + ScheduleToCloseTimeoutSeconds: common.Int32Ptr(100), + ScheduleToStartTimeoutSeconds: common.Int32Ptr(10), + StartToCloseTimeoutSeconds: common.Int32Ptr(50), + HeartbeatTimeoutSeconds: common.Int32Ptr(5), + }, + }} + + ms := execution.CreatePersistenceMutableState(msBuilder) + gwmsResponse := &persistence.GetWorkflowExecutionResponse{State: ms} + + test.AddActivityTaskCompletedEvent(msBuilder, activity2ScheduledEvent.ID, + activity2StartedEvent.ID, activity2Result, identity) + + ms2 := execution.CreatePersistenceMutableState(msBuilder) + gwmsResponse2 := &persistence.GetWorkflowExecutionResponse{State: ms2} + + s.mockExecutionMgr.On("GetWorkflowExecution", mock.Anything, mock.Anything).Return(gwmsResponse, nil).Once() + s.mockHistoryV2Mgr.On("AppendHistoryNodes", mock.Anything, mock.Anything).Return(&persistence.AppendHistoryNodesResponse{}, nil).Once() + s.mockExecutionMgr.On("UpdateWorkflowExecution", mock.Anything, mock.Anything).Return(&persistence.UpdateWorkflowExecutionResponse{MutableStateUpdateSessionStats: &persistence.MutableStateUpdateSessionStats{}}, + &persistence.ConditionFailedError{}).Once() + + s.mockExecutionMgr.On("GetWorkflowExecution", mock.Anything, mock.Anything).Return(gwmsResponse2, nil).Once() + s.mockHistoryV2Mgr.On("AppendHistoryNodes", mock.Anything, mock.Anything).Return(&persistence.AppendHistoryNodesResponse{}, nil).Once() + s.mockExecutionMgr.On("UpdateWorkflowExecution", mock.Anything, mock.Anything).Return(&persistence.UpdateWorkflowExecutionResponse{MutableStateUpdateSessionStats: &persistence.MutableStateUpdateSessionStats{}}, nil).Once() + + _, err := s.mockHistoryEngine.RespondDecisionTaskCompleted(context.Background(), &types.HistoryRespondDecisionTaskCompletedRequest{ + DomainUUID: constants.TestDomainID, + CompleteRequest: &types.RespondDecisionTaskCompletedRequest{ + TaskToken: taskToken, + Decisions: decisions, + ExecutionContext: executionContext, + Identity: identity, + }, + }) + s.Nil(err, s.printHistory(msBuilder)) + s.Equal(int64(16), ms2.ExecutionInfo.NextEventID) + s.Equal(decisionStartedEvent2.ID, ms2.ExecutionInfo.LastProcessedEvent) + s.Equal(executionContext, ms2.ExecutionInfo.ExecutionContext) + + executionBuilder := s.getBuilder(constants.TestDomainID, we) + activity3Attributes := s.getActivityScheduledEvent(executionBuilder, 13).ActivityTaskScheduledEventAttributes + s.Equal(activity3ID, activity3Attributes.ActivityID) + s.Equal(activity3Type, activity3Attributes.ActivityType.Name) + s.Equal(int64(12), activity3Attributes.DecisionTaskCompletedEventID) + s.Equal(tl, activity3Attributes.TaskList.Name) + s.Equal(activity3Input, activity3Attributes.Input) + s.Equal(int32(100), *activity3Attributes.ScheduleToCloseTimeoutSeconds) + s.Equal(int32(10), *activity3Attributes.ScheduleToStartTimeoutSeconds) + s.Equal(int32(50), *activity3Attributes.StartToCloseTimeoutSeconds) + s.Equal(int32(5), *activity3Attributes.HeartbeatTimeoutSeconds) + + di, ok := executionBuilder.GetDecisionInfo(15) + s.True(ok) + s.Equal(int32(100), di.DecisionTimeout) +} + +func (s *engineSuite) TestValidateSignalRequest() { + workflowType := "testType" + input := []byte("input") + startRequest := &types.StartWorkflowExecutionRequest{ + WorkflowID: "ID", + WorkflowType: &types.WorkflowType{Name: workflowType}, + TaskList: &types.TaskList{Name: "taskptr"}, + Input: input, + ExecutionStartToCloseTimeoutSeconds: common.Int32Ptr(10), + TaskStartToCloseTimeoutSeconds: common.Int32Ptr(10), + Identity: "identity", + } + + err := s.mockHistoryEngine.validateStartWorkflowExecutionRequest(startRequest, 0) + s.Error(err, "startRequest doesn't have request id, it should error out") +} + +func (s *engineSuite) TestRespondDecisionTaskCompletedMaxAttemptsExceeded() { + + we := types.WorkflowExecution{ + WorkflowID: "wId", + RunID: constants.TestRunID, + } + tl := "testTaskList" + taskToken, _ := json.Marshal(&common.TaskToken{ + WorkflowID: we.WorkflowID, + RunID: we.RunID, + ScheduleID: 2, + }) + identity := "testIdentity" + executionContext := []byte("context") + input := []byte("input") + + msBuilder := execution.NewMutableStateBuilderWithEventV2( + s.mockHistoryEngine.shard, + testlogger.New(s.Suite.T()), + we.GetRunID(), + constants.TestLocalDomainEntry, + ) + test.AddWorkflowExecutionStartedEvent(msBuilder, we, "wType", tl, []byte("input"), 100, 200, identity) + di := test.AddDecisionTaskScheduledEvent(msBuilder) + test.AddDecisionTaskStartedEvent(msBuilder, di.ScheduleID, tl, identity) + + decisions := []*types.Decision{{ + DecisionType: types.DecisionTypeScheduleActivityTask.Ptr(), + ScheduleActivityTaskDecisionAttributes: &types.ScheduleActivityTaskDecisionAttributes{ + ActivityID: "activity1", + ActivityType: &types.ActivityType{Name: "activity_type1"}, + TaskList: &types.TaskList{Name: tl}, + Input: input, + ScheduleToCloseTimeoutSeconds: common.Int32Ptr(100), + ScheduleToStartTimeoutSeconds: common.Int32Ptr(10), + StartToCloseTimeoutSeconds: common.Int32Ptr(50), + HeartbeatTimeoutSeconds: common.Int32Ptr(5), + }, + }} + + for i := 0; i < workflow.ConditionalRetryCount; i++ { + ms := execution.CreatePersistenceMutableState(msBuilder) + gwmsResponse := &persistence.GetWorkflowExecutionResponse{State: ms} + + s.mockExecutionMgr.On("GetWorkflowExecution", mock.Anything, mock.Anything).Return(gwmsResponse, nil).Once() + s.mockHistoryV2Mgr.On("AppendHistoryNodes", mock.Anything, mock.Anything).Return(&persistence.AppendHistoryNodesResponse{}, nil).Once() + s.mockExecutionMgr.On("UpdateWorkflowExecution", mock.Anything, mock.Anything).Return(&persistence.UpdateWorkflowExecutionResponse{MutableStateUpdateSessionStats: &persistence.MutableStateUpdateSessionStats{}}, + &persistence.ConditionFailedError{}).Once() + } + + _, err := s.mockHistoryEngine.RespondDecisionTaskCompleted(context.Background(), &types.HistoryRespondDecisionTaskCompletedRequest{ + DomainUUID: constants.TestDomainID, + CompleteRequest: &types.RespondDecisionTaskCompletedRequest{ + TaskToken: taskToken, + Decisions: decisions, + ExecutionContext: executionContext, + Identity: identity, + }, + }) + s.NotNil(err) + s.Equal(workflow.ErrMaxAttemptsExceeded, err) +} + +func (s *engineSuite) TestRespondDecisionTaskCompletedCompleteWorkflowFailed() { + + we := types.WorkflowExecution{ + WorkflowID: "wId", + RunID: constants.TestRunID, + } + tl := "testTaskList" + identity := "testIdentity" + executionContext := []byte("context") + activity1ID := "activity1" + activity1Type := "activity_type1" + activity1Input := []byte("input1") + activity1Result := []byte("activity1_result") + activity2ID := "activity2" + activity2Type := "activity_type2" + activity2Input := []byte("input2") + activity2Result := []byte("activity2_result") + workflowResult := []byte("workflow result") + + msBuilder := execution.NewMutableStateBuilderWithEventV2( + s.mockHistoryEngine.shard, + testlogger.New(s.Suite.T()), + we.GetRunID(), + constants.TestLocalDomainEntry, + ) + test.AddWorkflowExecutionStartedEvent(msBuilder, we, "wType", tl, []byte("input"), 25, 200, identity) + di1 := test.AddDecisionTaskScheduledEvent(msBuilder) + decisionStartedEvent1 := test.AddDecisionTaskStartedEvent(msBuilder, di1.ScheduleID, tl, identity) + decisionCompletedEvent1 := test.AddDecisionTaskCompletedEvent(msBuilder, di1.ScheduleID, + decisionStartedEvent1.ID, nil, identity) + activity1ScheduledEvent, _ := test.AddActivityTaskScheduledEvent(msBuilder, decisionCompletedEvent1.ID, + activity1ID, activity1Type, tl, activity1Input, 100, 10, 1, 5) + activity2ScheduledEvent, _ := test.AddActivityTaskScheduledEvent(msBuilder, decisionCompletedEvent1.ID, + activity2ID, activity2Type, tl, activity2Input, 100, 10, 1, 5) + activity1StartedEvent := test.AddActivityTaskStartedEvent(msBuilder, activity1ScheduledEvent.ID, identity) + activity2StartedEvent := test.AddActivityTaskStartedEvent(msBuilder, activity2ScheduledEvent.ID, identity) + test.AddActivityTaskCompletedEvent(msBuilder, activity1ScheduledEvent.ID, + activity1StartedEvent.ID, activity1Result, identity) + di2 := test.AddDecisionTaskScheduledEvent(msBuilder) + test.AddDecisionTaskStartedEvent(msBuilder, di2.ScheduleID, tl, identity) + test.AddActivityTaskCompletedEvent(msBuilder, activity2ScheduledEvent.ID, + activity2StartedEvent.ID, activity2Result, identity) + + taskToken, _ := json.Marshal(&common.TaskToken{ + WorkflowID: we.WorkflowID, + RunID: we.RunID, + ScheduleID: di2.ScheduleID, + }) + + decisions := []*types.Decision{{ + DecisionType: types.DecisionTypeCompleteWorkflowExecution.Ptr(), + CompleteWorkflowExecutionDecisionAttributes: &types.CompleteWorkflowExecutionDecisionAttributes{ + Result: workflowResult, + }, + }} + + for i := 0; i < 2; i++ { + ms := execution.CreatePersistenceMutableState(msBuilder) + gwmsResponse := &persistence.GetWorkflowExecutionResponse{State: ms} + s.mockExecutionMgr.On("GetWorkflowExecution", mock.Anything, mock.Anything).Return(gwmsResponse, nil).Once() + } + + s.mockHistoryV2Mgr.On("AppendHistoryNodes", mock.Anything, mock.Anything).Return(&persistence.AppendHistoryNodesResponse{}, nil).Once() + s.mockExecutionMgr.On("UpdateWorkflowExecution", mock.Anything, mock.Anything).Return(&persistence.UpdateWorkflowExecutionResponse{MutableStateUpdateSessionStats: &persistence.MutableStateUpdateSessionStats{}}, nil).Once() + + _, err := s.mockHistoryEngine.RespondDecisionTaskCompleted(context.Background(), &types.HistoryRespondDecisionTaskCompletedRequest{ + DomainUUID: constants.TestDomainID, + CompleteRequest: &types.RespondDecisionTaskCompletedRequest{ + TaskToken: taskToken, + Decisions: decisions, + ExecutionContext: executionContext, + Identity: identity, + }, + }) + s.Nil(err, s.printHistory(msBuilder)) + executionBuilder := s.getBuilder(constants.TestDomainID, we) + s.Equal(int64(15), executionBuilder.GetExecutionInfo().NextEventID) + s.Equal(decisionStartedEvent1.ID, executionBuilder.GetExecutionInfo().LastProcessedEvent) + s.Empty(executionBuilder.GetExecutionInfo().ExecutionContext) + s.Equal(persistence.WorkflowStateRunning, executionBuilder.GetExecutionInfo().State) + s.True(executionBuilder.HasPendingDecision()) + di3, ok := executionBuilder.GetDecisionInfo(executionBuilder.GetExecutionInfo().NextEventID - 1) + s.True(ok) + s.Equal(executionBuilder.GetExecutionInfo().NextEventID-1, di3.ScheduleID) + s.Equal(int64(0), di3.Attempt) +} + +func (s *engineSuite) TestRespondDecisionTaskCompletedFailWorkflowFailed() { + + we := types.WorkflowExecution{ + WorkflowID: "wId", + RunID: constants.TestRunID, + } + tl := "testTaskList" + identity := "testIdentity" + executionContext := []byte("context") + activity1ID := "activity1" + activity1Type := "activity_type1" + activity1Input := []byte("input1") + activity1Result := []byte("activity1_result") + activity2ID := "activity2" + activity2Type := "activity_type2" + activity2Input := []byte("input2") + activity2Result := []byte("activity2_result") + reason := "workflow fail reason" + details := []byte("workflow fail details") + + msBuilder := execution.NewMutableStateBuilderWithEventV2( + s.mockHistoryEngine.shard, + testlogger.New(s.Suite.T()), + we.GetRunID(), + constants.TestLocalDomainEntry, + ) + test.AddWorkflowExecutionStartedEvent(msBuilder, we, "wType", tl, []byte("input"), 25, 200, identity) + di1 := test.AddDecisionTaskScheduledEvent(msBuilder) + decisionStartedEvent1 := test.AddDecisionTaskStartedEvent(msBuilder, di1.ScheduleID, tl, identity) + decisionCompletedEvent1 := test.AddDecisionTaskCompletedEvent(msBuilder, di1.ScheduleID, + decisionStartedEvent1.ID, nil, identity) + activity1ScheduledEvent, _ := test.AddActivityTaskScheduledEvent(msBuilder, decisionCompletedEvent1.ID, activity1ID, + activity1Type, tl, activity1Input, 100, 10, 1, 5) + activity2ScheduledEvent, _ := test.AddActivityTaskScheduledEvent(msBuilder, decisionCompletedEvent1.ID, activity2ID, + activity2Type, tl, activity2Input, 100, 10, 1, 5) + activity1StartedEvent := test.AddActivityTaskStartedEvent(msBuilder, activity1ScheduledEvent.ID, identity) + activity2StartedEvent := test.AddActivityTaskStartedEvent(msBuilder, activity2ScheduledEvent.ID, identity) + test.AddActivityTaskCompletedEvent(msBuilder, activity1ScheduledEvent.ID, + activity1StartedEvent.ID, activity1Result, identity) + di2 := test.AddDecisionTaskScheduledEvent(msBuilder) + test.AddDecisionTaskStartedEvent(msBuilder, di2.ScheduleID, tl, identity) + test.AddActivityTaskCompletedEvent(msBuilder, activity2ScheduledEvent.ID, + activity2StartedEvent.ID, activity2Result, identity) + + taskToken, _ := json.Marshal(&common.TaskToken{ + WorkflowID: we.WorkflowID, + RunID: we.RunID, + ScheduleID: di2.ScheduleID, + }) + + decisions := []*types.Decision{{ + DecisionType: types.DecisionTypeFailWorkflowExecution.Ptr(), + FailWorkflowExecutionDecisionAttributes: &types.FailWorkflowExecutionDecisionAttributes{ + Reason: &reason, + Details: details, + }, + }} + + for i := 0; i < 2; i++ { + ms := execution.CreatePersistenceMutableState(msBuilder) + gwmsResponse := &persistence.GetWorkflowExecutionResponse{State: ms} + s.mockExecutionMgr.On("GetWorkflowExecution", mock.Anything, mock.Anything).Return(gwmsResponse, nil).Once() + } + + s.mockHistoryV2Mgr.On("AppendHistoryNodes", mock.Anything, mock.Anything).Return(&persistence.AppendHistoryNodesResponse{}, nil).Once() + s.mockExecutionMgr.On("UpdateWorkflowExecution", mock.Anything, mock.Anything).Return(&persistence.UpdateWorkflowExecutionResponse{MutableStateUpdateSessionStats: &persistence.MutableStateUpdateSessionStats{}}, nil).Once() + + _, err := s.mockHistoryEngine.RespondDecisionTaskCompleted(context.Background(), &types.HistoryRespondDecisionTaskCompletedRequest{ + DomainUUID: constants.TestDomainID, + CompleteRequest: &types.RespondDecisionTaskCompletedRequest{ + TaskToken: taskToken, + Decisions: decisions, + ExecutionContext: executionContext, + Identity: identity, + }, + }) + s.Nil(err, s.printHistory(msBuilder)) + executionBuilder := s.getBuilder(constants.TestDomainID, we) + s.Equal(int64(15), executionBuilder.GetExecutionInfo().NextEventID) + s.Equal(decisionStartedEvent1.ID, executionBuilder.GetExecutionInfo().LastProcessedEvent) + s.Empty(executionBuilder.GetExecutionInfo().ExecutionContext) + s.Equal(persistence.WorkflowStateRunning, executionBuilder.GetExecutionInfo().State) + s.True(executionBuilder.HasPendingDecision()) + di3, ok := executionBuilder.GetDecisionInfo(executionBuilder.GetExecutionInfo().NextEventID - 1) + s.True(ok) + s.Equal(executionBuilder.GetExecutionInfo().NextEventID-1, di3.ScheduleID) + s.Equal(int64(0), di3.Attempt) +} + +func (s *engineSuite) TestRespondDecisionTaskCompletedBadDecisionAttributes() { + + we := types.WorkflowExecution{ + WorkflowID: "wId", + RunID: constants.TestRunID, + } + tl := "testTaskList" + identity := "testIdentity" + executionContext := []byte("context") + activity1ID := "activity1" + activity1Type := "activity_type1" + activity1Input := []byte("input1") + activity1Result := []byte("activity1_result") + + msBuilder := execution.NewMutableStateBuilderWithEventV2( + s.mockHistoryEngine.shard, + testlogger.New(s.Suite.T()), + we.GetRunID(), + constants.TestLocalDomainEntry, + ) + test.AddWorkflowExecutionStartedEvent(msBuilder, we, "wType", tl, []byte("input"), 25, 200, identity) + di1 := test.AddDecisionTaskScheduledEvent(msBuilder) + decisionStartedEvent1 := test.AddDecisionTaskStartedEvent(msBuilder, di1.ScheduleID, tl, identity) + decisionCompletedEvent1 := test.AddDecisionTaskCompletedEvent(msBuilder, di1.ScheduleID, + decisionStartedEvent1.ID, nil, identity) + activity1ScheduledEvent, _ := test.AddActivityTaskScheduledEvent(msBuilder, decisionCompletedEvent1.ID, activity1ID, + activity1Type, tl, activity1Input, 100, 10, 1, 5) + activity1StartedEvent := test.AddActivityTaskStartedEvent(msBuilder, activity1ScheduledEvent.ID, identity) + test.AddActivityTaskCompletedEvent(msBuilder, activity1ScheduledEvent.ID, + activity1StartedEvent.ID, activity1Result, identity) + di2 := test.AddDecisionTaskScheduledEvent(msBuilder) + test.AddDecisionTaskStartedEvent(msBuilder, di2.ScheduleID, tl, identity) + + taskToken, _ := json.Marshal(&common.TaskToken{ + WorkflowID: we.WorkflowID, + RunID: we.RunID, + ScheduleID: di2.ScheduleID, + }) + + // Decision with nil attributes + decisions := []*types.Decision{{ + DecisionType: types.DecisionTypeCompleteWorkflowExecution.Ptr(), + }} + + gwmsResponse1 := &persistence.GetWorkflowExecutionResponse{State: execution.CreatePersistenceMutableState(msBuilder)} + gwmsResponse2 := &persistence.GetWorkflowExecutionResponse{State: execution.CreatePersistenceMutableState(msBuilder)} + s.mockExecutionMgr.On("GetWorkflowExecution", mock.Anything, mock.Anything).Return(gwmsResponse1, nil).Once() + s.mockExecutionMgr.On("GetWorkflowExecution", mock.Anything, mock.Anything).Return(gwmsResponse2, nil).Once() + + s.mockHistoryV2Mgr.On("AppendHistoryNodes", mock.Anything, mock.Anything).Return(&persistence.AppendHistoryNodesResponse{}, nil).Once() + s.mockExecutionMgr.On("UpdateWorkflowExecution", mock.Anything, mock.Anything).Return(&persistence.UpdateWorkflowExecutionResponse{ + MutableStateUpdateSessionStats: &persistence.MutableStateUpdateSessionStats{}}, nil, + ).Once() + + _, err := s.mockHistoryEngine.RespondDecisionTaskCompleted(context.Background(), &types.HistoryRespondDecisionTaskCompletedRequest{ + DomainUUID: constants.TestDomainID, + CompleteRequest: &types.RespondDecisionTaskCompletedRequest{ + TaskToken: taskToken, + Decisions: decisions, + ExecutionContext: executionContext, + Identity: identity, + }, + }) + s.Nil(err) +} + +// This test unit tests the activity schedule timeout validation logic of HistoryEngine's RespondDecisionTaskComplete function. +// An scheduled activity decision has 3 timeouts: ScheduleToClose, ScheduleToStart and StartToClose. +// This test verifies that when either ScheduleToClose or ScheduleToStart and StartToClose are specified, +// HistoryEngine's validateActivityScheduleAttribute will deduce the missing timeout and fill it in +// instead of returning a BadRequest error and only when all three are missing should a BadRequest be returned. +func (s *engineSuite) TestRespondDecisionTaskCompletedSingleActivityScheduledAttribute() { + workflowTimeout := int32(100) + testIterationVariables := []struct { + scheduleToClose *int32 + scheduleToStart *int32 + startToClose *int32 + heartbeat *int32 + expectedScheduleToClose int32 + expectedScheduleToStart int32 + expectedStartToClose int32 + expectDecisionFail bool + }{ + // No ScheduleToClose timeout, will use ScheduleToStart + StartToClose + {nil, common.Int32Ptr(3), common.Int32Ptr(7), nil, + 3 + 7, 3, 7, false}, + // Has ScheduleToClose timeout but not ScheduleToStart or StartToClose, + // will use ScheduleToClose for ScheduleToStart and StartToClose + {common.Int32Ptr(7), nil, nil, nil, + 7, 7, 7, false}, + // No ScheduleToClose timeout, ScheduleToStart or StartToClose, expect error return + {nil, nil, nil, nil, + 0, 0, 0, true}, + // Negative ScheduleToClose, expect error return + {common.Int32Ptr(-1), nil, nil, nil, + 0, 0, 0, true}, + // Negative ScheduleToStart, expect error return + {nil, common.Int32Ptr(-1), nil, nil, + 0, 0, 0, true}, + // Negative StartToClose, expect error return + {nil, nil, common.Int32Ptr(-1), nil, + 0, 0, 0, true}, + // Negative HeartBeat, expect error return + {nil, nil, nil, common.Int32Ptr(-1), + 0, 0, 0, true}, + // Use workflow timeout + {common.Int32Ptr(workflowTimeout), nil, nil, nil, + workflowTimeout, workflowTimeout, workflowTimeout, false}, + // Timeout larger than workflow timeout + {common.Int32Ptr(workflowTimeout + 1), nil, nil, nil, + workflowTimeout, workflowTimeout, workflowTimeout, false}, + {nil, common.Int32Ptr(workflowTimeout + 1), nil, nil, + 0, 0, 0, true}, + {nil, nil, common.Int32Ptr(workflowTimeout + 1), nil, + 0, 0, 0, true}, + {nil, nil, nil, common.Int32Ptr(workflowTimeout + 1), + 0, 0, 0, true}, + // No ScheduleToClose timeout, will use ScheduleToStart + StartToClose, but exceed limit + {nil, common.Int32Ptr(workflowTimeout), common.Int32Ptr(10), nil, + workflowTimeout, workflowTimeout, 10, false}, + } + + for _, iVar := range testIterationVariables { + + we := types.WorkflowExecution{ + WorkflowID: "wId", + RunID: constants.TestRunID, + } + tl := "testTaskList" + taskToken, _ := json.Marshal(&common.TaskToken{ + WorkflowID: "wId", + RunID: we.GetRunID(), + ScheduleID: 2, + }) + identity := "testIdentity" + executionContext := []byte("context") + input := []byte("input") + + msBuilder := execution.NewMutableStateBuilderWithEventV2( + s.mockHistoryEngine.shard, + testlogger.New(s.Suite.T()), + we.GetRunID(), + constants.TestLocalDomainEntry, + ) + test.AddWorkflowExecutionStartedEvent(msBuilder, we, "wType", tl, []byte("input"), workflowTimeout, 200, identity) + di := test.AddDecisionTaskScheduledEvent(msBuilder) + test.AddDecisionTaskStartedEvent(msBuilder, di.ScheduleID, tl, identity) + + decisions := []*types.Decision{{ + DecisionType: types.DecisionTypeScheduleActivityTask.Ptr(), + ScheduleActivityTaskDecisionAttributes: &types.ScheduleActivityTaskDecisionAttributes{ + ActivityID: "activity1", + ActivityType: &types.ActivityType{Name: "activity_type1"}, + TaskList: &types.TaskList{Name: tl}, + Input: input, + ScheduleToCloseTimeoutSeconds: iVar.scheduleToClose, + ScheduleToStartTimeoutSeconds: iVar.scheduleToStart, + StartToCloseTimeoutSeconds: iVar.startToClose, + HeartbeatTimeoutSeconds: iVar.heartbeat, + }, + }} + + gwmsResponse1 := &persistence.GetWorkflowExecutionResponse{State: execution.CreatePersistenceMutableState(msBuilder)} + s.mockExecutionMgr.On("GetWorkflowExecution", mock.Anything, mock.Anything).Return(gwmsResponse1, nil).Once() + if iVar.expectDecisionFail { + gwmsResponse2 := &persistence.GetWorkflowExecutionResponse{State: execution.CreatePersistenceMutableState(msBuilder)} + s.mockExecutionMgr.On("GetWorkflowExecution", mock.Anything, mock.Anything).Return(gwmsResponse2, nil).Once() + } + + s.mockHistoryV2Mgr.On("AppendHistoryNodes", mock.Anything, mock.Anything).Return(&persistence.AppendHistoryNodesResponse{}, nil).Once() + s.mockExecutionMgr.On("UpdateWorkflowExecution", mock.Anything, mock.Anything).Return(&persistence.UpdateWorkflowExecutionResponse{MutableStateUpdateSessionStats: &persistence.MutableStateUpdateSessionStats{}}, nil).Once() + + _, err := s.mockHistoryEngine.RespondDecisionTaskCompleted(context.Background(), &types.HistoryRespondDecisionTaskCompletedRequest{ + DomainUUID: constants.TestDomainID, + CompleteRequest: &types.RespondDecisionTaskCompletedRequest{ + TaskToken: taskToken, + Decisions: decisions, + ExecutionContext: executionContext, + Identity: identity, + }, + }) + + s.Nil(err, s.printHistory(msBuilder)) + executionBuilder := s.getBuilder(constants.TestDomainID, we) + if !iVar.expectDecisionFail { + s.Equal(int64(6), executionBuilder.GetExecutionInfo().NextEventID) + s.Equal(int64(3), executionBuilder.GetExecutionInfo().LastProcessedEvent) + s.Equal(persistence.WorkflowStateRunning, executionBuilder.GetExecutionInfo().State) + s.False(executionBuilder.HasPendingDecision()) + + activity1Attributes := s.getActivityScheduledEvent(executionBuilder, int64(5)).ActivityTaskScheduledEventAttributes + s.Equal(iVar.expectedScheduleToClose, activity1Attributes.GetScheduleToCloseTimeoutSeconds()) + s.Equal(iVar.expectedScheduleToStart, activity1Attributes.GetScheduleToStartTimeoutSeconds()) + s.Equal(iVar.expectedStartToClose, activity1Attributes.GetStartToCloseTimeoutSeconds()) + } else { + s.Equal(int64(5), executionBuilder.GetExecutionInfo().NextEventID) + s.Equal(common.EmptyEventID, executionBuilder.GetExecutionInfo().LastProcessedEvent) + s.Equal(persistence.WorkflowStateRunning, executionBuilder.GetExecutionInfo().State) + s.True(executionBuilder.HasPendingDecision()) + } + s.TearDownTest() + s.SetupTest() + } +} + +func (s *engineSuite) TestRespondDecisionTaskCompletedBadBinary() { + domainID := uuid.New() + we := types.WorkflowExecution{ + WorkflowID: "wId", + RunID: constants.TestRunID, + } + tl := "testTaskList" + taskToken, _ := json.Marshal(&common.TaskToken{ + WorkflowID: "wId", + RunID: we.GetRunID(), + ScheduleID: 2, + }) + identity := "testIdentity" + executionContext := []byte("context") + domainEntry := cache.NewLocalDomainCacheEntryForTest( + &persistence.DomainInfo{ID: domainID, Name: constants.TestDomainName}, + &persistence.DomainConfig{ + Retention: 2, + BadBinaries: types.BadBinaries{ + Binaries: map[string]*types.BadBinaryInfo{ + "test-bad-binary": {}, + }, + }, + }, + cluster.TestCurrentClusterName, + ) + + msBuilder := execution.NewMutableStateBuilderWithEventV2( + s.mockHistoryEngine.shard, + testlogger.New(s.Suite.T()), + we.GetRunID(), + domainEntry, + ) + test.AddWorkflowExecutionStartedEvent(msBuilder, we, "wType", tl, []byte("input"), 100, 200, identity) + di := test.AddDecisionTaskScheduledEvent(msBuilder) + test.AddDecisionTaskStartedEvent(msBuilder, di.ScheduleID, tl, identity) + + var decisions []*types.Decision + + gwmsResponse1 := &persistence.GetWorkflowExecutionResponse{State: execution.CreatePersistenceMutableState(msBuilder)} + gwmsResponse2 := &persistence.GetWorkflowExecutionResponse{State: execution.CreatePersistenceMutableState(msBuilder)} + + s.mockExecutionMgr.On("GetWorkflowExecution", mock.Anything, mock.Anything).Return(gwmsResponse1, nil).Once() + s.mockExecutionMgr.On("GetWorkflowExecution", mock.Anything, mock.Anything).Return(gwmsResponse2, nil).Once() + s.mockHistoryV2Mgr.On("AppendHistoryNodes", mock.Anything, mock.Anything).Return(&persistence.AppendHistoryNodesResponse{}, nil).Once() + s.mockExecutionMgr.On("UpdateWorkflowExecution", mock.Anything, mock.Anything).Return(&persistence.UpdateWorkflowExecutionResponse{MutableStateUpdateSessionStats: &persistence.MutableStateUpdateSessionStats{}}, nil).Once() + s.mockDomainCache.EXPECT().GetDomainByID(domainID).Return(domainEntry, nil).AnyTimes() + s.mockDomainCache.EXPECT().GetDomainName(domainID).Return(constants.TestDomainName, nil).AnyTimes() + + _, err := s.mockHistoryEngine.RespondDecisionTaskCompleted(context.Background(), &types.HistoryRespondDecisionTaskCompletedRequest{ + DomainUUID: domainID, + CompleteRequest: &types.RespondDecisionTaskCompletedRequest{ + TaskToken: taskToken, + Decisions: decisions, + ExecutionContext: executionContext, + Identity: identity, + BinaryChecksum: "test-bad-binary", + }, + }) + s.Nil(err, s.printHistory(msBuilder)) + executionBuilder := s.getBuilder(domainID, we) + s.Equal(int64(5), executionBuilder.GetExecutionInfo().NextEventID) + s.Equal(common.EmptyEventID, executionBuilder.GetExecutionInfo().LastProcessedEvent) + s.Empty(executionBuilder.GetExecutionInfo().ExecutionContext) + s.Equal(persistence.WorkflowStateRunning, executionBuilder.GetExecutionInfo().State) + s.True(executionBuilder.HasPendingDecision()) +} + +func (s *engineSuite) TestRespondDecisionTaskCompletedSingleActivityScheduledDecision() { + + we := types.WorkflowExecution{ + WorkflowID: "wId", + RunID: constants.TestRunID, + } + tl := "testTaskList" + taskToken, _ := json.Marshal(&common.TaskToken{ + WorkflowID: "wId", + RunID: we.GetRunID(), + ScheduleID: 2, + }) + identity := "testIdentity" + executionContext := []byte("context") + input := []byte("input") + + msBuilder := execution.NewMutableStateBuilderWithEventV2( + s.mockHistoryEngine.shard, + testlogger.New(s.Suite.T()), + we.GetRunID(), + constants.TestLocalDomainEntry, + ) + test.AddWorkflowExecutionStartedEvent(msBuilder, we, "wType", tl, []byte("input"), 100, 200, identity) + di := test.AddDecisionTaskScheduledEvent(msBuilder) + test.AddDecisionTaskStartedEvent(msBuilder, di.ScheduleID, tl, identity) + + decisions := []*types.Decision{{ + DecisionType: types.DecisionTypeScheduleActivityTask.Ptr(), + ScheduleActivityTaskDecisionAttributes: &types.ScheduleActivityTaskDecisionAttributes{ + ActivityID: "activity1", + ActivityType: &types.ActivityType{Name: "activity_type1"}, + TaskList: &types.TaskList{Name: tl}, + Input: input, + ScheduleToCloseTimeoutSeconds: common.Int32Ptr(100), + ScheduleToStartTimeoutSeconds: common.Int32Ptr(10), + StartToCloseTimeoutSeconds: common.Int32Ptr(50), + HeartbeatTimeoutSeconds: common.Int32Ptr(5), + }, + }} + + ms := execution.CreatePersistenceMutableState(msBuilder) + gwmsResponse := &persistence.GetWorkflowExecutionResponse{State: ms} + + s.mockExecutionMgr.On("GetWorkflowExecution", mock.Anything, mock.Anything).Return(gwmsResponse, nil).Once() + s.mockHistoryV2Mgr.On("AppendHistoryNodes", mock.Anything, mock.Anything).Return(&persistence.AppendHistoryNodesResponse{}, nil).Once() + s.mockExecutionMgr.On("UpdateWorkflowExecution", mock.Anything, mock.Anything).Return(&persistence.UpdateWorkflowExecutionResponse{MutableStateUpdateSessionStats: &persistence.MutableStateUpdateSessionStats{}}, nil).Once() + + _, err := s.mockHistoryEngine.RespondDecisionTaskCompleted(context.Background(), &types.HistoryRespondDecisionTaskCompletedRequest{ + DomainUUID: constants.TestDomainID, + CompleteRequest: &types.RespondDecisionTaskCompletedRequest{ + TaskToken: taskToken, + Decisions: decisions, + ExecutionContext: executionContext, + Identity: identity, + }, + }) + s.Nil(err, s.printHistory(msBuilder)) + executionBuilder := s.getBuilder(constants.TestDomainID, we) + s.Equal(int64(6), executionBuilder.GetExecutionInfo().NextEventID) + s.Equal(int64(3), executionBuilder.GetExecutionInfo().LastProcessedEvent) + s.Equal(executionContext, executionBuilder.GetExecutionInfo().ExecutionContext) + s.Equal(persistence.WorkflowStateRunning, executionBuilder.GetExecutionInfo().State) + s.False(executionBuilder.HasPendingDecision()) + + activity1Attributes := s.getActivityScheduledEvent(executionBuilder, int64(5)).ActivityTaskScheduledEventAttributes + s.Equal("activity1", activity1Attributes.ActivityID) + s.Equal("activity_type1", activity1Attributes.ActivityType.Name) + s.Equal(int64(4), activity1Attributes.DecisionTaskCompletedEventID) + s.Equal(tl, activity1Attributes.TaskList.Name) + s.Equal(input, activity1Attributes.Input) + s.Equal(int32(100), *activity1Attributes.ScheduleToCloseTimeoutSeconds) + s.Equal(int32(10), *activity1Attributes.ScheduleToStartTimeoutSeconds) + s.Equal(int32(50), *activity1Attributes.StartToCloseTimeoutSeconds) + s.Equal(int32(5), *activity1Attributes.HeartbeatTimeoutSeconds) +} + +func (s *engineSuite) TestRespondDecisionTaskCompleted_DecisionHeartbeatTimeout() { + + we := types.WorkflowExecution{ + WorkflowID: "wId", + RunID: constants.TestRunID, + } + tl := "testTaskList" + taskToken, _ := json.Marshal(&common.TaskToken{ + WorkflowID: we.WorkflowID, + RunID: we.RunID, + ScheduleID: 2, + }) + identity := "testIdentity" + executionContext := []byte("context") + + msBuilder := execution.NewMutableStateBuilderWithEventV2( + s.mockHistoryEngine.shard, + testlogger.New(s.Suite.T()), + we.GetRunID(), + constants.TestLocalDomainEntry, + ) + test.AddWorkflowExecutionStartedEvent(msBuilder, we, "wType", tl, []byte("input"), 100, 200, identity) + di := test.AddDecisionTaskScheduledEvent(msBuilder) + test.AddDecisionTaskStartedEvent(msBuilder, di.ScheduleID, tl, identity) + msBuilder.GetExecutionInfo().DecisionOriginalScheduledTimestamp = time.Now().Add(-time.Hour).UnixNano() + + decisions := []*types.Decision{} + + ms := execution.CreatePersistenceMutableState(msBuilder) + gwmsResponse := &persistence.GetWorkflowExecutionResponse{State: ms} + + s.mockExecutionMgr.On("GetWorkflowExecution", mock.Anything, mock.Anything).Return(gwmsResponse, nil).Once() + s.mockHistoryV2Mgr.On("AppendHistoryNodes", mock.Anything, mock.Anything).Return(&persistence.AppendHistoryNodesResponse{}, nil).Once() + s.mockExecutionMgr.On("UpdateWorkflowExecution", mock.Anything, mock.Anything).Return(&persistence.UpdateWorkflowExecutionResponse{MutableStateUpdateSessionStats: &persistence.MutableStateUpdateSessionStats{}}, nil).Once() + + _, err := s.mockHistoryEngine.RespondDecisionTaskCompleted(context.Background(), &types.HistoryRespondDecisionTaskCompletedRequest{ + DomainUUID: constants.TestDomainID, + CompleteRequest: &types.RespondDecisionTaskCompletedRequest{ + ForceCreateNewDecisionTask: true, + TaskToken: taskToken, + Decisions: decisions, + ExecutionContext: executionContext, + Identity: identity, + }, + }) + s.Error(err, "decision heartbeat timeout") +} + +func (s *engineSuite) TestRespondDecisionTaskCompleted_DecisionHeartbeatNotTimeout() { + + we := types.WorkflowExecution{ + WorkflowID: "wId", + RunID: constants.TestRunID, + } + tl := "testTaskList" + taskToken, _ := json.Marshal(&common.TaskToken{ + WorkflowID: we.WorkflowID, + RunID: we.RunID, + ScheduleID: 2, + }) + identity := "testIdentity" + executionContext := []byte("context") + + msBuilder := execution.NewMutableStateBuilderWithEventV2( + s.mockHistoryEngine.shard, + testlogger.New(s.Suite.T()), + we.GetRunID(), + constants.TestLocalDomainEntry, + ) + test.AddWorkflowExecutionStartedEvent(msBuilder, we, "wType", tl, []byte("input"), 100, 200, identity) + di := test.AddDecisionTaskScheduledEvent(msBuilder) + test.AddDecisionTaskStartedEvent(msBuilder, di.ScheduleID, tl, identity) + msBuilder.GetExecutionInfo().DecisionOriginalScheduledTimestamp = time.Now().Add(-time.Minute).UnixNano() + + decisions := []*types.Decision{} + + ms := execution.CreatePersistenceMutableState(msBuilder) + gwmsResponse := &persistence.GetWorkflowExecutionResponse{State: ms} + + s.mockExecutionMgr.On("GetWorkflowExecution", mock.Anything, mock.Anything).Return(gwmsResponse, nil).Once() + s.mockHistoryV2Mgr.On("AppendHistoryNodes", mock.Anything, mock.Anything).Return(&persistence.AppendHistoryNodesResponse{}, nil).Once() + s.mockExecutionMgr.On("UpdateWorkflowExecution", mock.Anything, mock.Anything).Return(&persistence.UpdateWorkflowExecutionResponse{MutableStateUpdateSessionStats: &persistence.MutableStateUpdateSessionStats{}}, nil).Once() + + _, err := s.mockHistoryEngine.RespondDecisionTaskCompleted(context.Background(), &types.HistoryRespondDecisionTaskCompletedRequest{ + DomainUUID: constants.TestDomainID, + CompleteRequest: &types.RespondDecisionTaskCompletedRequest{ + ForceCreateNewDecisionTask: true, + TaskToken: taskToken, + Decisions: decisions, + ExecutionContext: executionContext, + Identity: identity, + }, + }) + s.Nil(err) +} + +func (s *engineSuite) TestRespondDecisionTaskCompleted_DecisionHeartbeatNotTimeout_ZeroOrignalScheduledTime() { + + we := types.WorkflowExecution{ + WorkflowID: "wId", + RunID: constants.TestRunID, + } + tl := "testTaskList" + taskToken, _ := json.Marshal(&common.TaskToken{ + WorkflowID: we.WorkflowID, + RunID: we.RunID, + ScheduleID: 2, + }) + identity := "testIdentity" + executionContext := []byte("context") + + msBuilder := execution.NewMutableStateBuilderWithEventV2( + s.mockHistoryEngine.shard, + testlogger.New(s.Suite.T()), + we.GetRunID(), + constants.TestLocalDomainEntry, + ) + test.AddWorkflowExecutionStartedEvent(msBuilder, we, "wType", tl, []byte("input"), 100, 200, identity) + di := test.AddDecisionTaskScheduledEvent(msBuilder) + test.AddDecisionTaskStartedEvent(msBuilder, di.ScheduleID, tl, identity) + msBuilder.GetExecutionInfo().DecisionOriginalScheduledTimestamp = 0 + + decisions := []*types.Decision{} + + ms := execution.CreatePersistenceMutableState(msBuilder) + gwmsResponse := &persistence.GetWorkflowExecutionResponse{State: ms} + + s.mockExecutionMgr.On("GetWorkflowExecution", mock.Anything, mock.Anything).Return(gwmsResponse, nil).Once() + s.mockHistoryV2Mgr.On("AppendHistoryNodes", mock.Anything, mock.Anything).Return(&persistence.AppendHistoryNodesResponse{}, nil).Once() + s.mockExecutionMgr.On("UpdateWorkflowExecution", mock.Anything, mock.Anything).Return(&persistence.UpdateWorkflowExecutionResponse{MutableStateUpdateSessionStats: &persistence.MutableStateUpdateSessionStats{}}, nil).Once() + + _, err := s.mockHistoryEngine.RespondDecisionTaskCompleted(context.Background(), &types.HistoryRespondDecisionTaskCompletedRequest{ + DomainUUID: constants.TestDomainID, + CompleteRequest: &types.RespondDecisionTaskCompletedRequest{ + ForceCreateNewDecisionTask: true, + TaskToken: taskToken, + Decisions: decisions, + ExecutionContext: executionContext, + Identity: identity, + }, + }) + s.Nil(err) +} + +func (s *engineSuite) TestRespondDecisionTaskCompletedCompleteWorkflowSuccess() { + + we := types.WorkflowExecution{ + WorkflowID: "wId", + RunID: constants.TestRunID, + } + tl := "testTaskList" + taskToken, _ := json.Marshal(&common.TaskToken{ + WorkflowID: we.WorkflowID, + RunID: we.RunID, + ScheduleID: 2, + }) + identity := "testIdentity" + executionContext := []byte("context") + workflowResult := []byte("success") + + msBuilder := execution.NewMutableStateBuilderWithEventV2( + s.mockHistoryEngine.shard, + testlogger.New(s.Suite.T()), + we.GetRunID(), + constants.TestLocalDomainEntry, + ) + test.AddWorkflowExecutionStartedEvent(msBuilder, we, "wType", tl, []byte("input"), 100, 200, identity) + di := test.AddDecisionTaskScheduledEvent(msBuilder) + test.AddDecisionTaskStartedEvent(msBuilder, di.ScheduleID, tl, identity) + + decisions := []*types.Decision{{ + DecisionType: types.DecisionTypeCompleteWorkflowExecution.Ptr(), + CompleteWorkflowExecutionDecisionAttributes: &types.CompleteWorkflowExecutionDecisionAttributes{ + Result: workflowResult, + }, + }} + + ms := execution.CreatePersistenceMutableState(msBuilder) + gwmsResponse := &persistence.GetWorkflowExecutionResponse{State: ms} + + s.mockExecutionMgr.On("GetWorkflowExecution", mock.Anything, mock.Anything).Return(gwmsResponse, nil).Once() + s.mockHistoryV2Mgr.On("AppendHistoryNodes", mock.Anything, mock.Anything).Return(&persistence.AppendHistoryNodesResponse{}, nil).Once() + s.mockExecutionMgr.On("UpdateWorkflowExecution", mock.Anything, mock.Anything).Return(&persistence.UpdateWorkflowExecutionResponse{MutableStateUpdateSessionStats: &persistence.MutableStateUpdateSessionStats{}}, nil).Once() + + _, err := s.mockHistoryEngine.RespondDecisionTaskCompleted(context.Background(), &types.HistoryRespondDecisionTaskCompletedRequest{ + DomainUUID: constants.TestDomainID, + CompleteRequest: &types.RespondDecisionTaskCompletedRequest{ + TaskToken: taskToken, + Decisions: decisions, + ExecutionContext: executionContext, + Identity: identity, + }, + }) + s.Nil(err, s.printHistory(msBuilder)) + executionBuilder := s.getBuilder(constants.TestDomainID, we) + s.Equal(int64(6), executionBuilder.GetExecutionInfo().NextEventID) + s.Equal(int64(3), executionBuilder.GetExecutionInfo().LastProcessedEvent) + s.Equal(executionContext, executionBuilder.GetExecutionInfo().ExecutionContext) + s.Equal(persistence.WorkflowStateCompleted, executionBuilder.GetExecutionInfo().State) + s.False(executionBuilder.HasPendingDecision()) +} + +func (s *engineSuite) TestRespondDecisionTaskCompletedFailWorkflowSuccess() { + + we := types.WorkflowExecution{ + WorkflowID: "wId", + RunID: constants.TestRunID, + } + tl := "testTaskList" + taskToken, _ := json.Marshal(&common.TaskToken{ + WorkflowID: we.WorkflowID, + RunID: we.RunID, + ScheduleID: 2, + }) + identity := "testIdentity" + executionContext := []byte("context") + details := []byte("fail workflow details") + reason := "fail workflow reason" + + msBuilder := execution.NewMutableStateBuilderWithEventV2( + s.mockHistoryEngine.shard, + testlogger.New(s.Suite.T()), + we.GetRunID(), + constants.TestLocalDomainEntry, + ) + test.AddWorkflowExecutionStartedEvent(msBuilder, we, "wType", tl, []byte("input"), 100, 200, identity) + di := test.AddDecisionTaskScheduledEvent(msBuilder) + test.AddDecisionTaskStartedEvent(msBuilder, di.ScheduleID, tl, identity) + + decisions := []*types.Decision{{ + DecisionType: types.DecisionTypeFailWorkflowExecution.Ptr(), + FailWorkflowExecutionDecisionAttributes: &types.FailWorkflowExecutionDecisionAttributes{ + Reason: &reason, + Details: details, + }, + }} + + ms := execution.CreatePersistenceMutableState(msBuilder) + gwmsResponse := &persistence.GetWorkflowExecutionResponse{State: ms} + + s.mockExecutionMgr.On("GetWorkflowExecution", mock.Anything, mock.Anything).Return(gwmsResponse, nil).Once() + s.mockHistoryV2Mgr.On("AppendHistoryNodes", mock.Anything, mock.Anything).Return(&persistence.AppendHistoryNodesResponse{}, nil).Once() + s.mockExecutionMgr.On("UpdateWorkflowExecution", mock.Anything, mock.Anything).Return(&persistence.UpdateWorkflowExecutionResponse{MutableStateUpdateSessionStats: &persistence.MutableStateUpdateSessionStats{}}, nil).Once() + + _, err := s.mockHistoryEngine.RespondDecisionTaskCompleted(context.Background(), &types.HistoryRespondDecisionTaskCompletedRequest{ + DomainUUID: constants.TestDomainID, + CompleteRequest: &types.RespondDecisionTaskCompletedRequest{ + TaskToken: taskToken, + Decisions: decisions, + ExecutionContext: executionContext, + Identity: identity, + }, + }) + s.Nil(err, s.printHistory(msBuilder)) + executionBuilder := s.getBuilder(constants.TestDomainID, we) + s.Equal(int64(6), executionBuilder.GetExecutionInfo().NextEventID) + s.Equal(int64(3), executionBuilder.GetExecutionInfo().LastProcessedEvent) + s.Equal(executionContext, executionBuilder.GetExecutionInfo().ExecutionContext) + s.Equal(persistence.WorkflowStateCompleted, executionBuilder.GetExecutionInfo().State) + s.False(executionBuilder.HasPendingDecision()) +} + +func (s *engineSuite) TestRespondDecisionTaskCompletedSignalExternalWorkflowSuccess() { + + we := types.WorkflowExecution{ + WorkflowID: "wId", + RunID: constants.TestRunID, + } + tl := "testTaskList" + taskToken, _ := json.Marshal(&common.TaskToken{ + WorkflowID: we.WorkflowID, + RunID: we.RunID, + ScheduleID: 2, + }) + identity := "testIdentity" + executionContext := []byte("context") + + msBuilder := execution.NewMutableStateBuilderWithEventV2( + s.mockHistoryEngine.shard, + testlogger.New(s.Suite.T()), + we.GetRunID(), + constants.TestLocalDomainEntry, + ) + test.AddWorkflowExecutionStartedEvent(msBuilder, we, "wType", tl, []byte("input"), 100, 200, identity) + di := test.AddDecisionTaskScheduledEvent(msBuilder) + test.AddDecisionTaskStartedEvent(msBuilder, di.ScheduleID, tl, identity) + + decisions := []*types.Decision{{ + DecisionType: types.DecisionTypeSignalExternalWorkflowExecution.Ptr(), + SignalExternalWorkflowExecutionDecisionAttributes: &types.SignalExternalWorkflowExecutionDecisionAttributes{ + Domain: constants.TestDomainName, + Execution: &types.WorkflowExecution{ + WorkflowID: we.WorkflowID, + RunID: we.RunID, + }, + SignalName: "signal", + Input: []byte("test input"), + }, + }} + + ms := execution.CreatePersistenceMutableState(msBuilder) + gwmsResponse := &persistence.GetWorkflowExecutionResponse{State: ms} + + s.mockExecutionMgr.On("GetWorkflowExecution", mock.Anything, mock.Anything).Return(gwmsResponse, nil).Once() + s.mockHistoryV2Mgr.On("AppendHistoryNodes", mock.Anything, mock.Anything).Return(&persistence.AppendHistoryNodesResponse{}, nil).Once() + s.mockExecutionMgr.On("UpdateWorkflowExecution", mock.Anything, mock.Anything).Return(&persistence.UpdateWorkflowExecutionResponse{MutableStateUpdateSessionStats: &persistence.MutableStateUpdateSessionStats{}}, nil).Once() + + _, err := s.mockHistoryEngine.RespondDecisionTaskCompleted(context.Background(), &types.HistoryRespondDecisionTaskCompletedRequest{ + DomainUUID: constants.TestDomainID, + CompleteRequest: &types.RespondDecisionTaskCompletedRequest{ + TaskToken: taskToken, + Decisions: decisions, + ExecutionContext: executionContext, + Identity: identity, + }, + }) + s.Nil(err, s.printHistory(msBuilder)) + executionBuilder := s.getBuilder(constants.TestDomainID, we) + s.Equal(int64(6), executionBuilder.GetExecutionInfo().NextEventID) + s.Equal(int64(3), executionBuilder.GetExecutionInfo().LastProcessedEvent) + s.Equal(executionContext, executionBuilder.GetExecutionInfo().ExecutionContext) +} + +func (s *engineSuite) TestRespondDecisionTaskCompletedStartChildWorkflowWithAbandonPolicy() { + + we := types.WorkflowExecution{ + WorkflowID: "wId", + RunID: constants.TestRunID, + } + tl := "testTaskList" + taskToken, _ := json.Marshal(&common.TaskToken{ + WorkflowID: we.WorkflowID, + RunID: we.RunID, + ScheduleID: 2, + }) + identity := "testIdentity" + executionContext := []byte("context") + + msBuilder := execution.NewMutableStateBuilderWithEventV2( + s.mockHistoryEngine.shard, + testlogger.New(s.Suite.T()), + we.GetRunID(), + constants.TestLocalDomainEntry, + ) + test.AddWorkflowExecutionStartedEvent(msBuilder, we, "wType", tl, []byte("input"), 100, 200, identity) + di := test.AddDecisionTaskScheduledEvent(msBuilder) + test.AddDecisionTaskStartedEvent(msBuilder, di.ScheduleID, tl, identity) + + abandon := types.ParentClosePolicyAbandon + decisions := []*types.Decision{{ + DecisionType: types.DecisionTypeStartChildWorkflowExecution.Ptr(), + StartChildWorkflowExecutionDecisionAttributes: &types.StartChildWorkflowExecutionDecisionAttributes{ + Domain: constants.TestDomainName, + WorkflowID: "child-workflow-id", + WorkflowType: &types.WorkflowType{ + Name: "child-workflow-type", + }, + ParentClosePolicy: &abandon, + }, + }} + + ms := execution.CreatePersistenceMutableState(msBuilder) + gwmsResponse := &persistence.GetWorkflowExecutionResponse{State: ms} + + s.mockExecutionMgr.On("GetWorkflowExecution", mock.Anything, mock.Anything).Return(gwmsResponse, nil).Once() + s.mockHistoryV2Mgr.On("AppendHistoryNodes", mock.Anything, mock.Anything).Return(&persistence.AppendHistoryNodesResponse{}, nil).Once() + s.mockExecutionMgr.On("UpdateWorkflowExecution", mock.Anything, mock.Anything).Return(&persistence.UpdateWorkflowExecutionResponse{MutableStateUpdateSessionStats: &persistence.MutableStateUpdateSessionStats{}}, nil).Once() + + _, err := s.mockHistoryEngine.RespondDecisionTaskCompleted(context.Background(), &types.HistoryRespondDecisionTaskCompletedRequest{ + DomainUUID: constants.TestDomainID, + CompleteRequest: &types.RespondDecisionTaskCompletedRequest{ + TaskToken: taskToken, + Decisions: decisions, + ExecutionContext: executionContext, + Identity: identity, + }, + }) + s.Nil(err, s.printHistory(msBuilder)) + executionBuilder := s.getBuilder(constants.TestDomainID, we) + s.Equal(int64(6), executionBuilder.GetExecutionInfo().NextEventID) + s.Equal(int64(3), executionBuilder.GetExecutionInfo().LastProcessedEvent) + s.Equal(executionContext, executionBuilder.GetExecutionInfo().ExecutionContext) + s.Equal(int(1), len(executionBuilder.GetPendingChildExecutionInfos())) + var childID int64 + for c := range executionBuilder.GetPendingChildExecutionInfos() { + childID = c + break + } + s.Equal("child-workflow-id", executionBuilder.GetPendingChildExecutionInfos()[childID].StartedWorkflowID) + s.Equal(types.ParentClosePolicyAbandon, executionBuilder.GetPendingChildExecutionInfos()[childID].ParentClosePolicy) +} + +func (s *engineSuite) TestRespondDecisionTaskCompletedStartChildWorkflowWithTerminatePolicy() { + + we := types.WorkflowExecution{ + WorkflowID: "wId", + RunID: constants.TestRunID, + } + tl := "testTaskList" + taskToken, _ := json.Marshal(&common.TaskToken{ + WorkflowID: we.WorkflowID, + RunID: we.RunID, + ScheduleID: 2, + }) + identity := "testIdentity" + executionContext := []byte("context") + + msBuilder := execution.NewMutableStateBuilderWithEventV2( + s.mockHistoryEngine.shard, + testlogger.New(s.Suite.T()), + we.GetRunID(), + constants.TestLocalDomainEntry, + ) + test.AddWorkflowExecutionStartedEvent(msBuilder, we, "wType", tl, []byte("input"), 100, 200, identity) + di := test.AddDecisionTaskScheduledEvent(msBuilder) + test.AddDecisionTaskStartedEvent(msBuilder, di.ScheduleID, tl, identity) + + terminate := types.ParentClosePolicyTerminate + decisions := []*types.Decision{{ + DecisionType: types.DecisionTypeStartChildWorkflowExecution.Ptr(), + StartChildWorkflowExecutionDecisionAttributes: &types.StartChildWorkflowExecutionDecisionAttributes{ + Domain: constants.TestDomainName, + WorkflowID: "child-workflow-id", + WorkflowType: &types.WorkflowType{ + Name: "child-workflow-type", + }, + ParentClosePolicy: &terminate, + }, + }} + + ms := execution.CreatePersistenceMutableState(msBuilder) + gwmsResponse := &persistence.GetWorkflowExecutionResponse{State: ms} + + s.mockExecutionMgr.On("GetWorkflowExecution", mock.Anything, mock.Anything).Return(gwmsResponse, nil).Once() + s.mockHistoryV2Mgr.On("AppendHistoryNodes", mock.Anything, mock.Anything).Return(&persistence.AppendHistoryNodesResponse{}, nil).Once() + s.mockExecutionMgr.On("UpdateWorkflowExecution", mock.Anything, mock.Anything).Return(&persistence.UpdateWorkflowExecutionResponse{MutableStateUpdateSessionStats: &persistence.MutableStateUpdateSessionStats{}}, nil).Once() + + _, err := s.mockHistoryEngine.RespondDecisionTaskCompleted(context.Background(), &types.HistoryRespondDecisionTaskCompletedRequest{ + DomainUUID: constants.TestDomainID, + CompleteRequest: &types.RespondDecisionTaskCompletedRequest{ + TaskToken: taskToken, + Decisions: decisions, + ExecutionContext: executionContext, + Identity: identity, + }, + }) + s.Nil(err, s.printHistory(msBuilder)) + executionBuilder := s.getBuilder(constants.TestDomainID, we) + s.Equal(int64(6), executionBuilder.GetExecutionInfo().NextEventID) + s.Equal(int64(3), executionBuilder.GetExecutionInfo().LastProcessedEvent) + s.Equal(executionContext, executionBuilder.GetExecutionInfo().ExecutionContext) + s.Equal(int(1), len(executionBuilder.GetPendingChildExecutionInfos())) + var childID int64 + for c := range executionBuilder.GetPendingChildExecutionInfos() { + childID = c + break + } + s.Equal("child-workflow-id", executionBuilder.GetPendingChildExecutionInfos()[childID].StartedWorkflowID) + s.Equal(types.ParentClosePolicyTerminate, executionBuilder.GetPendingChildExecutionInfos()[childID].ParentClosePolicy) +} + +func (s *engineSuite) TestRespondDecisionTaskCompletedSignalExternalWorkflowFailed() { + + we := types.WorkflowExecution{ + WorkflowID: "wId", + RunID: "invalid run id", + } + tl := "testTaskList" + taskToken, _ := json.Marshal(&common.TaskToken{ + WorkflowID: we.GetWorkflowID(), + RunID: we.GetRunID(), + ScheduleID: 2, + }) + identity := "testIdentity" + executionContext := []byte("context") + + msBuilder := execution.NewMutableStateBuilderWithEventV2( + s.mockHistoryEngine.shard, + testlogger.New(s.Suite.T()), + we.GetRunID(), + constants.TestLocalDomainEntry, + ) + test.AddWorkflowExecutionStartedEvent(msBuilder, we, "wType", tl, []byte("input"), 100, 200, identity) + di := test.AddDecisionTaskScheduledEvent(msBuilder) + test.AddDecisionTaskStartedEvent(msBuilder, di.ScheduleID, tl, identity) + + decisions := []*types.Decision{{ + DecisionType: types.DecisionTypeSignalExternalWorkflowExecution.Ptr(), + SignalExternalWorkflowExecutionDecisionAttributes: &types.SignalExternalWorkflowExecutionDecisionAttributes{ + Domain: constants.TestDomainID, + Execution: &types.WorkflowExecution{ + WorkflowID: we.WorkflowID, + RunID: we.RunID, + }, + SignalName: "signal", + Input: []byte("test input"), + }, + }} + + _, err := s.mockHistoryEngine.RespondDecisionTaskCompleted(context.Background(), &types.HistoryRespondDecisionTaskCompletedRequest{ + DomainUUID: constants.TestDomainID, + CompleteRequest: &types.RespondDecisionTaskCompletedRequest{ + TaskToken: taskToken, + Decisions: decisions, + ExecutionContext: executionContext, + Identity: identity, + }, + }) + + s.EqualError(err, "RunID is not valid UUID.") +} + +func (s *engineSuite) TestRespondDecisionTaskCompletedSignalExternalWorkflowFailed_UnKnownDomain() { + + we := types.WorkflowExecution{ + WorkflowID: "wId", + RunID: constants.TestRunID, + } + tl := "testTaskList" + taskToken, _ := json.Marshal(&common.TaskToken{ + WorkflowID: we.WorkflowID, + RunID: we.RunID, + ScheduleID: 2, + }) + identity := "testIdentity" + executionContext := []byte("context") + foreignDomain := "unknown domain" + + msBuilder := execution.NewMutableStateBuilderWithEventV2( + s.mockHistoryEngine.shard, + testlogger.New(s.Suite.T()), + we.GetRunID(), + constants.TestLocalDomainEntry, + ) + test.AddWorkflowExecutionStartedEvent(msBuilder, we, "wType", tl, []byte("input"), 100, 200, identity) + di := test.AddDecisionTaskScheduledEvent(msBuilder) + test.AddDecisionTaskStartedEvent(msBuilder, di.ScheduleID, tl, identity) + + decisions := []*types.Decision{{ + DecisionType: types.DecisionTypeSignalExternalWorkflowExecution.Ptr(), + SignalExternalWorkflowExecutionDecisionAttributes: &types.SignalExternalWorkflowExecutionDecisionAttributes{ + Domain: foreignDomain, + Execution: &types.WorkflowExecution{ + WorkflowID: we.WorkflowID, + RunID: we.RunID, + }, + SignalName: "signal", + Input: []byte("test input"), + }, + }} + + ms := execution.CreatePersistenceMutableState(msBuilder) + gwmsResponse := &persistence.GetWorkflowExecutionResponse{State: ms} + + s.mockExecutionMgr.On("GetWorkflowExecution", mock.Anything, mock.Anything).Return(gwmsResponse, nil).Once() + s.mockDomainCache.EXPECT().GetDomain(foreignDomain).Return( + nil, errors.New("get foreign domain error"), + ).Times(1) + + _, err := s.mockHistoryEngine.RespondDecisionTaskCompleted(context.Background(), &types.HistoryRespondDecisionTaskCompletedRequest{ + DomainUUID: constants.TestDomainID, + CompleteRequest: &types.RespondDecisionTaskCompletedRequest{ + TaskToken: taskToken, + Decisions: decisions, + ExecutionContext: executionContext, + Identity: identity, + }, + }) + + s.NotNil(err) +} + +func (s *engineSuite) TestRespondActivityTaskCompletedInvalidToken() { + + invalidToken, _ := json.Marshal("bad token") + identity := "testIdentity" + + err := s.mockHistoryEngine.RespondActivityTaskCompleted(context.Background(), &types.HistoryRespondActivityTaskCompletedRequest{ + DomainUUID: constants.TestDomainID, + CompleteRequest: &types.RespondActivityTaskCompletedRequest{ + TaskToken: invalidToken, + Result: nil, + Identity: identity, + }, + }) + + s.NotNil(err) + s.IsType(&types.BadRequestError{}, err) +} + +func (s *engineSuite) TestRespondActivityTaskCompletedIfNoExecution() { + + taskToken, _ := json.Marshal(&common.TaskToken{ + WorkflowID: "wId", + RunID: constants.TestRunID, + ScheduleID: 2, + }) + identity := "testIdentity" + + s.mockExecutionMgr.On("GetWorkflowExecution", mock.Anything, mock.Anything).Return(nil, &types.EntityNotExistsError{}).Once() + + err := s.mockHistoryEngine.RespondActivityTaskCompleted(context.Background(), &types.HistoryRespondActivityTaskCompletedRequest{ + DomainUUID: constants.TestDomainID, + CompleteRequest: &types.RespondActivityTaskCompletedRequest{ + TaskToken: taskToken, + Identity: identity, + }, + }) + s.NotNil(err) + s.IsType(&types.EntityNotExistsError{}, err) +} + +func (s *engineSuite) TestRespondActivityTaskCompletedIfNoRunID() { + + taskToken, _ := json.Marshal(&common.TaskToken{ + WorkflowID: "wId", + ScheduleID: 2, + }) + identity := "testIdentity" + + s.mockExecutionMgr.On("GetCurrentExecution", mock.Anything, mock.Anything).Return(nil, &types.EntityNotExistsError{}).Once() + + err := s.mockHistoryEngine.RespondActivityTaskCompleted(context.Background(), &types.HistoryRespondActivityTaskCompletedRequest{ + DomainUUID: constants.TestDomainID, + CompleteRequest: &types.RespondActivityTaskCompletedRequest{ + TaskToken: taskToken, + Identity: identity, + }, + }) + s.NotNil(err) + s.IsType(&types.EntityNotExistsError{}, err) +} + +func (s *engineSuite) TestRespondActivityTaskCompletedIfGetExecutionFailed() { + + taskToken, _ := json.Marshal(&common.TaskToken{ + WorkflowID: "wId", + RunID: constants.TestRunID, + ScheduleID: 2, + }) + identity := "testIdentity" + + s.mockExecutionMgr.On("GetWorkflowExecution", mock.Anything, mock.Anything).Return(nil, errors.New("FAILED")).Once() + + err := s.mockHistoryEngine.RespondActivityTaskCompleted(context.Background(), &types.HistoryRespondActivityTaskCompletedRequest{ + DomainUUID: constants.TestDomainID, + CompleteRequest: &types.RespondActivityTaskCompletedRequest{ + TaskToken: taskToken, + Identity: identity, + }, + }) + s.EqualError(err, "FAILED") +} + +func (s *engineSuite) TestRespondActivityTaskCompletedIfNoAIdProvided() { + + workflowExecution := types.WorkflowExecution{ + WorkflowID: "wId", + RunID: constants.TestRunID, + } + tasklist := "testTaskList" + identity := "testIdentity" + taskToken, _ := json.Marshal(&common.TaskToken{ + WorkflowID: "wId", + ScheduleID: common.EmptyEventID, + }) + + msBuilder := execution.NewMutableStateBuilderWithEventV2( + s.mockHistoryEngine.shard, + testlogger.New(s.Suite.T()), + constants.TestRunID, + constants.TestLocalDomainEntry, + ) + test.AddWorkflowExecutionStartedEvent(msBuilder, workflowExecution, "wType", tasklist, []byte("input"), 100, 200, identity) + test.AddDecisionTaskScheduledEvent(msBuilder) + ms := execution.CreatePersistenceMutableState(msBuilder) + gwmsResponse := &persistence.GetWorkflowExecutionResponse{State: ms} + gceResponse := &persistence.GetCurrentExecutionResponse{RunID: constants.TestRunID} + + s.mockExecutionMgr.On("GetCurrentExecution", mock.Anything, mock.Anything).Return(gceResponse, nil).Once() + s.mockExecutionMgr.On("GetWorkflowExecution", mock.Anything, mock.Anything).Return(gwmsResponse, nil).Once() + + err := s.mockHistoryEngine.RespondActivityTaskCompleted(context.Background(), &types.HistoryRespondActivityTaskCompletedRequest{ + DomainUUID: constants.TestDomainID, + CompleteRequest: &types.RespondActivityTaskCompletedRequest{ + TaskToken: taskToken, + Identity: identity, + }, + }) + s.EqualError(err, "Neither ActivityID nor ScheduleID is provided") +} + +func (s *engineSuite) TestRespondActivityTaskCompletedIfNotFound() { + + taskToken, _ := json.Marshal(&common.TaskToken{ + WorkflowID: "wId", + ScheduleID: common.EmptyEventID, + ActivityID: "aid", + }) + workflowExecution := types.WorkflowExecution{ + WorkflowID: "wId", + RunID: constants.TestRunID, + } + tasklist := "testTaskList" + identity := "testIdentity" + + msBuilder := execution.NewMutableStateBuilderWithEventV2( + s.mockHistoryEngine.shard, + testlogger.New(s.Suite.T()), + constants.TestRunID, + constants.TestLocalDomainEntry, + ) + test.AddWorkflowExecutionStartedEvent(msBuilder, workflowExecution, "wType", tasklist, []byte("input"), 100, 200, identity) + test.AddDecisionTaskScheduledEvent(msBuilder) + ms := execution.CreatePersistenceMutableState(msBuilder) + gwmsResponse := &persistence.GetWorkflowExecutionResponse{State: ms} + gceResponse := &persistence.GetCurrentExecutionResponse{RunID: constants.TestRunID} + + s.mockExecutionMgr.On("GetCurrentExecution", mock.Anything, mock.Anything).Return(gceResponse, nil).Once() + s.mockExecutionMgr.On("GetWorkflowExecution", mock.Anything, mock.Anything).Return(gwmsResponse, nil).Once() + + err := s.mockHistoryEngine.RespondActivityTaskCompleted(context.Background(), &types.HistoryRespondActivityTaskCompletedRequest{ + DomainUUID: constants.TestDomainID, + CompleteRequest: &types.RespondActivityTaskCompletedRequest{ + TaskToken: taskToken, + Identity: identity, + }, + }) + s.Error(err) +} + +func (s *engineSuite) TestRespondActivityTaskCompletedUpdateExecutionFailed() { + + we := types.WorkflowExecution{ + WorkflowID: "wId", + RunID: constants.TestRunID, + } + tl := "testTaskList" + taskToken, _ := json.Marshal(&common.TaskToken{ + WorkflowID: we.WorkflowID, + RunID: we.RunID, + ScheduleID: 5, + }) + identity := "testIdentity" + activityID := "activity1_id" + activityType := "activity_type1" + activityInput := []byte("input1") + activityResult := []byte("activity result") + + msBuilder := execution.NewMutableStateBuilderWithEventV2( + s.mockHistoryEngine.shard, + testlogger.New(s.Suite.T()), + we.GetRunID(), + constants.TestLocalDomainEntry, + ) + test.AddWorkflowExecutionStartedEvent(msBuilder, we, "wType", tl, []byte("input"), 100, 200, identity) + di := test.AddDecisionTaskScheduledEvent(msBuilder) + decisionStartedEvent := test.AddDecisionTaskStartedEvent(msBuilder, di.ScheduleID, tl, identity) + decisionCompletedEvent := test.AddDecisionTaskCompletedEvent(msBuilder, di.ScheduleID, + decisionStartedEvent.ID, nil, identity) + activityScheduledEvent, _ := test.AddActivityTaskScheduledEvent(msBuilder, decisionCompletedEvent.ID, activityID, + activityType, tl, activityInput, 100, 10, 1, 5) + test.AddActivityTaskStartedEvent(msBuilder, activityScheduledEvent.ID, identity) + + ms := execution.CreatePersistenceMutableState(msBuilder) + gwmsResponse := &persistence.GetWorkflowExecutionResponse{State: ms} + + s.mockExecutionMgr.On("GetWorkflowExecution", mock.Anything, mock.Anything).Return(gwmsResponse, nil).Once() + s.mockHistoryV2Mgr.On("AppendHistoryNodes", mock.Anything, mock.Anything).Return(&persistence.AppendHistoryNodesResponse{}, nil).Once() + s.mockExecutionMgr.On("UpdateWorkflowExecution", mock.Anything, mock.Anything).Return(&persistence.UpdateWorkflowExecutionResponse{MutableStateUpdateSessionStats: &persistence.MutableStateUpdateSessionStats{}}, errors.New("FAILED")).Once() + s.mockShardManager.On("UpdateShard", mock.Anything, mock.Anything).Return(nil).Once() + + err := s.mockHistoryEngine.RespondActivityTaskCompleted(context.Background(), &types.HistoryRespondActivityTaskCompletedRequest{ + DomainUUID: constants.TestDomainID, + CompleteRequest: &types.RespondActivityTaskCompletedRequest{ + TaskToken: taskToken, + Result: activityResult, + Identity: identity, + }, + }) + s.EqualError(err, "FAILED") +} + +func (s *engineSuite) TestRespondActivityTaskCompletedIfTaskCompleted() { + + we := types.WorkflowExecution{ + WorkflowID: "wId", + RunID: constants.TestRunID, + } + tl := "testTaskList" + taskToken, _ := json.Marshal(&common.TaskToken{ + WorkflowID: we.WorkflowID, + RunID: we.RunID, + ScheduleID: 5, + }) + identity := "testIdentity" + activityID := "activity1_id" + activityType := "activity_type1" + activityInput := []byte("input1") + activityResult := []byte("activity result") + + msBuilder := execution.NewMutableStateBuilderWithEventV2( + s.mockHistoryEngine.shard, + testlogger.New(s.Suite.T()), + we.GetRunID(), + constants.TestLocalDomainEntry, + ) + test.AddWorkflowExecutionStartedEvent(msBuilder, we, "wType", tl, []byte("input"), 100, 200, identity) + di := test.AddDecisionTaskScheduledEvent(msBuilder) + decisionStartedEvent := test.AddDecisionTaskStartedEvent(msBuilder, di.ScheduleID, tl, identity) + decisionCompletedEvent := test.AddDecisionTaskCompletedEvent(msBuilder, di.ScheduleID, + decisionStartedEvent.ID, nil, identity) + activityScheduledEvent, _ := test.AddActivityTaskScheduledEvent(msBuilder, decisionCompletedEvent.ID, activityID, + activityType, tl, activityInput, 100, 10, 1, 5) + activityStartedEvent := test.AddActivityTaskStartedEvent(msBuilder, activityScheduledEvent.ID, identity) + test.AddActivityTaskCompletedEvent(msBuilder, activityScheduledEvent.ID, activityStartedEvent.ID, + activityResult, identity) + test.AddDecisionTaskScheduledEvent(msBuilder) + + ms := execution.CreatePersistenceMutableState(msBuilder) + gwmsResponse := &persistence.GetWorkflowExecutionResponse{State: ms} + + s.mockExecutionMgr.On("GetWorkflowExecution", mock.Anything, mock.Anything).Return(gwmsResponse, nil).Once() + + err := s.mockHistoryEngine.RespondActivityTaskCompleted(context.Background(), &types.HistoryRespondActivityTaskCompletedRequest{ + DomainUUID: constants.TestDomainID, + CompleteRequest: &types.RespondActivityTaskCompletedRequest{ + TaskToken: taskToken, + Result: activityResult, + Identity: identity, + }, + }) + s.NotNil(err) + s.IsType(&types.EntityNotExistsError{}, err) +} + +func (s *engineSuite) TestRespondActivityTaskCompletedIfTaskNotStarted() { + + we := types.WorkflowExecution{ + WorkflowID: "wId", + RunID: constants.TestRunID, + } + tl := "testTaskList" + taskToken, _ := json.Marshal(&common.TaskToken{ + WorkflowID: we.WorkflowID, + RunID: we.RunID, + ScheduleID: 5, + }) + identity := "testIdentity" + activityID := "activity1_id" + activityType := "activity_type1" + activityInput := []byte("input1") + activityResult := []byte("activity result") + + msBuilder := execution.NewMutableStateBuilderWithEventV2( + s.mockHistoryEngine.shard, + testlogger.New(s.Suite.T()), + we.GetRunID(), + constants.TestLocalDomainEntry, + ) + test.AddWorkflowExecutionStartedEvent(msBuilder, we, "wType", tl, []byte("input"), 100, 200, identity) + di := test.AddDecisionTaskScheduledEvent(msBuilder) + decisionStartedEvent := test.AddDecisionTaskStartedEvent(msBuilder, di.ScheduleID, tl, identity) + decisionCompletedEvent := test.AddDecisionTaskCompletedEvent(msBuilder, di.ScheduleID, + decisionStartedEvent.ID, nil, identity) + test.AddActivityTaskScheduledEvent(msBuilder, decisionCompletedEvent.ID, activityID, + activityType, tl, activityInput, 100, 10, 1, 5) + + ms := execution.CreatePersistenceMutableState(msBuilder) + gwmsResponse := &persistence.GetWorkflowExecutionResponse{State: ms} + + s.mockExecutionMgr.On("GetWorkflowExecution", mock.Anything, mock.Anything).Return(gwmsResponse, nil).Once() + + err := s.mockHistoryEngine.RespondActivityTaskCompleted(context.Background(), &types.HistoryRespondActivityTaskCompletedRequest{ + DomainUUID: constants.TestDomainID, + CompleteRequest: &types.RespondActivityTaskCompletedRequest{ + TaskToken: taskToken, + Result: activityResult, + Identity: identity, + }, + }) + s.NotNil(err) + s.IsType(&types.EntityNotExistsError{}, err) +} + +func (s *engineSuite) TestRespondActivityTaskCompletedConflictOnUpdate() { + + we := types.WorkflowExecution{ + WorkflowID: "wId", + RunID: constants.TestRunID, + } + tl := "testTaskList" + taskToken, _ := json.Marshal(&common.TaskToken{ + WorkflowID: we.WorkflowID, + RunID: we.RunID, + ScheduleID: 5, + }) + identity := "testIdentity" + activity1ID := "activity1" + activity1Type := "activity_type1" + activity1Input := []byte("input1") + activity1Result := []byte("activity1_result") + activity2ID := "activity2" + activity2Type := "activity_type2" + activity2Input := []byte("input2") + + msBuilder := execution.NewMutableStateBuilderWithEventV2( + s.mockHistoryEngine.shard, + testlogger.New(s.Suite.T()), + we.GetRunID(), + constants.TestLocalDomainEntry, + ) + test.AddWorkflowExecutionStartedEvent(msBuilder, we, "wType", tl, []byte("input"), 100, 100, identity) + di := test.AddDecisionTaskScheduledEvent(msBuilder) + decisionStartedEvent1 := test.AddDecisionTaskStartedEvent(msBuilder, di.ScheduleID, tl, identity) + decisionCompletedEvent1 := test.AddDecisionTaskCompletedEvent(msBuilder, di.ScheduleID, + decisionStartedEvent1.ID, nil, identity) + activity1ScheduledEvent, _ := test.AddActivityTaskScheduledEvent(msBuilder, decisionCompletedEvent1.ID, activity1ID, + activity1Type, tl, activity1Input, 100, 10, 1, 5) + activity2ScheduledEvent, _ := test.AddActivityTaskScheduledEvent(msBuilder, decisionCompletedEvent1.ID, activity2ID, + activity2Type, tl, activity2Input, 100, 10, 1, 5) + test.AddActivityTaskStartedEvent(msBuilder, activity1ScheduledEvent.ID, identity) + test.AddActivityTaskStartedEvent(msBuilder, activity2ScheduledEvent.ID, identity) + + ms1 := execution.CreatePersistenceMutableState(msBuilder) + gwmsResponse1 := &persistence.GetWorkflowExecutionResponse{State: ms1} + + ms2 := execution.CreatePersistenceMutableState(msBuilder) + gwmsResponse2 := &persistence.GetWorkflowExecutionResponse{State: ms2} + + s.mockExecutionMgr.On("GetWorkflowExecution", mock.Anything, mock.Anything).Return(gwmsResponse1, nil).Once() + s.mockHistoryV2Mgr.On("AppendHistoryNodes", mock.Anything, mock.Anything).Return(&persistence.AppendHistoryNodesResponse{}, nil).Once() + s.mockExecutionMgr.On("UpdateWorkflowExecution", mock.Anything, mock.Anything).Return(&persistence.UpdateWorkflowExecutionResponse{MutableStateUpdateSessionStats: &persistence.MutableStateUpdateSessionStats{}}, &persistence.ConditionFailedError{}).Once() + + s.mockExecutionMgr.On("GetWorkflowExecution", mock.Anything, mock.Anything).Return(gwmsResponse2, nil).Once() + s.mockHistoryV2Mgr.On("AppendHistoryNodes", mock.Anything, mock.Anything).Return(&persistence.AppendHistoryNodesResponse{}, nil).Once() + s.mockExecutionMgr.On("UpdateWorkflowExecution", mock.Anything, mock.Anything).Return(&persistence.UpdateWorkflowExecutionResponse{MutableStateUpdateSessionStats: &persistence.MutableStateUpdateSessionStats{}}, nil).Once() + + err := s.mockHistoryEngine.RespondActivityTaskCompleted(context.Background(), &types.HistoryRespondActivityTaskCompletedRequest{ + DomainUUID: constants.TestDomainID, + CompleteRequest: &types.RespondActivityTaskCompletedRequest{ + TaskToken: taskToken, + Result: activity1Result, + Identity: identity, + }, + }) + s.Nil(err, s.printHistory(msBuilder)) + executionBuilder := s.getBuilder(constants.TestDomainID, we) + s.Equal(int64(11), executionBuilder.GetExecutionInfo().NextEventID) + s.Equal(int64(3), executionBuilder.GetExecutionInfo().LastProcessedEvent) + s.Equal(persistence.WorkflowStateRunning, executionBuilder.GetExecutionInfo().State) + + s.True(executionBuilder.HasPendingDecision()) + di, ok := executionBuilder.GetDecisionInfo(int64(10)) + s.True(ok) + s.Equal(int32(100), di.DecisionTimeout) + s.Equal(int64(10), di.ScheduleID) + s.Equal(common.EmptyEventID, di.StartedID) +} + +func (s *engineSuite) TestRespondActivityTaskCompletedMaxAttemptsExceeded() { + + we := types.WorkflowExecution{ + WorkflowID: "wId", + RunID: constants.TestRunID, + } + tl := "testTaskList" + taskToken, _ := json.Marshal(&common.TaskToken{ + WorkflowID: we.WorkflowID, + RunID: we.RunID, + ScheduleID: 5, + }) + identity := "testIdentity" + activityID := "activity1_id" + activityType := "activity_type1" + activityInput := []byte("input1") + activityResult := []byte("activity result") + + msBuilder := execution.NewMutableStateBuilderWithEventV2( + s.mockHistoryEngine.shard, + testlogger.New(s.Suite.T()), + we.GetRunID(), + constants.TestLocalDomainEntry, + ) + test.AddWorkflowExecutionStartedEvent(msBuilder, we, "wType", tl, []byte("input"), 100, 100, identity) + di := test.AddDecisionTaskScheduledEvent(msBuilder) + decisionStartedEvent := test.AddDecisionTaskStartedEvent(msBuilder, di.ScheduleID, tl, identity) + decisionCompletedEvent := test.AddDecisionTaskCompletedEvent(msBuilder, di.ScheduleID, + decisionStartedEvent.ID, nil, identity) + activityScheduledEvent, _ := test.AddActivityTaskScheduledEvent(msBuilder, decisionCompletedEvent.ID, activityID, + activityType, tl, activityInput, 100, 10, 1, 5) + test.AddActivityTaskStartedEvent(msBuilder, activityScheduledEvent.ID, identity) + + for i := 0; i < workflow.ConditionalRetryCount; i++ { + ms := execution.CreatePersistenceMutableState(msBuilder) + gwmsResponse := &persistence.GetWorkflowExecutionResponse{State: ms} + + s.mockExecutionMgr.On("GetWorkflowExecution", mock.Anything, mock.Anything).Return(gwmsResponse, nil).Once() + s.mockHistoryV2Mgr.On("AppendHistoryNodes", mock.Anything, mock.Anything).Return(&persistence.AppendHistoryNodesResponse{}, nil).Once() + s.mockExecutionMgr.On("UpdateWorkflowExecution", mock.Anything, mock.Anything).Return(&persistence.UpdateWorkflowExecutionResponse{MutableStateUpdateSessionStats: &persistence.MutableStateUpdateSessionStats{}}, &persistence.ConditionFailedError{}).Once() + } + + err := s.mockHistoryEngine.RespondActivityTaskCompleted(context.Background(), &types.HistoryRespondActivityTaskCompletedRequest{ + DomainUUID: constants.TestDomainID, + CompleteRequest: &types.RespondActivityTaskCompletedRequest{ + TaskToken: taskToken, + Result: activityResult, + Identity: identity, + }, + }) + s.Equal(workflow.ErrMaxAttemptsExceeded, err) +} + +func (s *engineSuite) TestRespondActivityTaskCompletedSuccess() { + + we := types.WorkflowExecution{ + WorkflowID: "wId", + RunID: constants.TestRunID, + } + tl := "testTaskList" + taskToken, _ := json.Marshal(&common.TaskToken{ + WorkflowID: we.WorkflowID, + RunID: we.RunID, + ScheduleID: 5, + }) + identity := "testIdentity" + activityID := "activity1_id" + activityType := "activity_type1" + activityInput := []byte("input1") + activityResult := []byte("activity result") + + msBuilder := execution.NewMutableStateBuilderWithEventV2( + s.mockHistoryEngine.shard, + testlogger.New(s.Suite.T()), + we.GetRunID(), + constants.TestLocalDomainEntry, + ) + test.AddWorkflowExecutionStartedEvent(msBuilder, we, "wType", tl, []byte("input"), 100, 100, identity) + di := test.AddDecisionTaskScheduledEvent(msBuilder) + decisionStartedEvent := test.AddDecisionTaskStartedEvent(msBuilder, di.ScheduleID, tl, identity) + decisionCompletedEvent := test.AddDecisionTaskCompletedEvent(msBuilder, di.ScheduleID, + decisionStartedEvent.ID, nil, identity) + activityScheduledEvent, _ := test.AddActivityTaskScheduledEvent(msBuilder, decisionCompletedEvent.ID, activityID, + activityType, tl, activityInput, 100, 10, 1, 5) + test.AddActivityTaskStartedEvent(msBuilder, activityScheduledEvent.ID, identity) + + ms := execution.CreatePersistenceMutableState(msBuilder) + gwmsResponse := &persistence.GetWorkflowExecutionResponse{State: ms} + + s.mockExecutionMgr.On("GetWorkflowExecution", mock.Anything, mock.Anything).Return(gwmsResponse, nil).Once() + s.mockHistoryV2Mgr.On("AppendHistoryNodes", mock.Anything, mock.Anything).Return(&persistence.AppendHistoryNodesResponse{}, nil).Once() + s.mockExecutionMgr.On("UpdateWorkflowExecution", mock.Anything, mock.Anything).Return(&persistence.UpdateWorkflowExecutionResponse{MutableStateUpdateSessionStats: &persistence.MutableStateUpdateSessionStats{}}, nil).Once() + + err := s.mockHistoryEngine.RespondActivityTaskCompleted(context.Background(), &types.HistoryRespondActivityTaskCompletedRequest{ + DomainUUID: constants.TestDomainID, + CompleteRequest: &types.RespondActivityTaskCompletedRequest{ + TaskToken: taskToken, + Result: activityResult, + Identity: identity, + }, + }) + s.Nil(err, s.printHistory(msBuilder)) + executionBuilder := s.getBuilder(constants.TestDomainID, we) + s.Equal(int64(9), executionBuilder.GetExecutionInfo().NextEventID) + s.Equal(int64(3), executionBuilder.GetExecutionInfo().LastProcessedEvent) + s.Equal(persistence.WorkflowStateRunning, executionBuilder.GetExecutionInfo().State) + + s.True(executionBuilder.HasPendingDecision()) + di, ok := executionBuilder.GetDecisionInfo(int64(8)) + s.True(ok) + s.Equal(int32(100), di.DecisionTimeout) + s.Equal(int64(8), di.ScheduleID) + s.Equal(common.EmptyEventID, di.StartedID) +} + +func (s *engineSuite) TestRespondActivityTaskCompletedByIdSuccess() { + + we := types.WorkflowExecution{ + WorkflowID: "wId", + RunID: constants.TestRunID, + } + tl := "testTaskList" + + identity := "testIdentity" + activityID := "activity1_id" + activityType := "activity_type1" + activityInput := []byte("input1") + activityResult := []byte("activity result") + taskToken, _ := json.Marshal(&common.TaskToken{ + WorkflowID: we.WorkflowID, + ScheduleID: common.EmptyEventID, + ActivityID: activityID, + }) + + msBuilder := execution.NewMutableStateBuilderWithEventV2( + s.mockHistoryEngine.shard, + testlogger.New(s.Suite.T()), + we.GetRunID(), + constants.TestLocalDomainEntry, + ) + test.AddWorkflowExecutionStartedEvent(msBuilder, we, "wType", tl, []byte("input"), 100, 100, identity) + decisionScheduledEvent := test.AddDecisionTaskScheduledEvent(msBuilder) + decisionStartedEvent := test.AddDecisionTaskStartedEvent(msBuilder, decisionScheduledEvent.ScheduleID, tl, identity) + decisionCompletedEvent := test.AddDecisionTaskCompletedEvent(msBuilder, decisionScheduledEvent.ScheduleID, + decisionStartedEvent.ID, nil, identity) + activityScheduledEvent, _ := test.AddActivityTaskScheduledEvent(msBuilder, decisionCompletedEvent.ID, activityID, + activityType, tl, activityInput, 100, 10, 1, 5) + test.AddActivityTaskStartedEvent(msBuilder, activityScheduledEvent.ID, identity) + + ms := execution.CreatePersistenceMutableState(msBuilder) + gwmsResponse := &persistence.GetWorkflowExecutionResponse{State: ms} + gceResponse := &persistence.GetCurrentExecutionResponse{RunID: we.RunID} + + s.mockExecutionMgr.On("GetCurrentExecution", mock.Anything, mock.Anything).Return(gceResponse, nil).Once() + s.mockExecutionMgr.On("GetWorkflowExecution", mock.Anything, mock.Anything).Return(gwmsResponse, nil).Once() + s.mockHistoryV2Mgr.On("AppendHistoryNodes", mock.Anything, mock.Anything).Return(&persistence.AppendHistoryNodesResponse{}, nil).Once() + s.mockExecutionMgr.On("UpdateWorkflowExecution", mock.Anything, mock.Anything).Return(&persistence.UpdateWorkflowExecutionResponse{MutableStateUpdateSessionStats: &persistence.MutableStateUpdateSessionStats{}}, nil).Once() + + err := s.mockHistoryEngine.RespondActivityTaskCompleted(context.Background(), &types.HistoryRespondActivityTaskCompletedRequest{ + DomainUUID: constants.TestDomainID, + CompleteRequest: &types.RespondActivityTaskCompletedRequest{ + TaskToken: taskToken, + Result: activityResult, + Identity: identity, + }, + }) + s.Nil(err, s.printHistory(msBuilder)) + executionBuilder := s.getBuilder(constants.TestDomainID, we) + s.Equal(int64(9), executionBuilder.GetExecutionInfo().NextEventID) + s.Equal(int64(3), executionBuilder.GetExecutionInfo().LastProcessedEvent) + s.Equal(persistence.WorkflowStateRunning, executionBuilder.GetExecutionInfo().State) + + s.True(executionBuilder.HasPendingDecision()) + di, ok := executionBuilder.GetDecisionInfo(int64(8)) + s.True(ok) + s.Equal(int32(100), di.DecisionTimeout) + s.Equal(int64(8), di.ScheduleID) + s.Equal(common.EmptyEventID, di.StartedID) +} + +func (s *engineSuite) TestRespondActivityTaskFailedInvalidToken() { + + invalidToken, _ := json.Marshal("bad token") + identity := "testIdentity" + + err := s.mockHistoryEngine.RespondActivityTaskFailed(context.Background(), &types.HistoryRespondActivityTaskFailedRequest{ + DomainUUID: constants.TestDomainID, + FailedRequest: &types.RespondActivityTaskFailedRequest{ + TaskToken: invalidToken, + Identity: identity, + }, + }) + + s.NotNil(err) + s.IsType(&types.BadRequestError{}, err) +} + +func (s *engineSuite) TestRespondActivityTaskFailedIfNoExecution() { + + taskToken, _ := json.Marshal(&common.TaskToken{ + WorkflowID: "wId", + RunID: constants.TestRunID, + ScheduleID: 2, + }) + identity := "testIdentity" + + s.mockExecutionMgr.On("GetWorkflowExecution", mock.Anything, mock.Anything).Return(nil, + &types.EntityNotExistsError{}).Once() + + err := s.mockHistoryEngine.RespondActivityTaskFailed(context.Background(), &types.HistoryRespondActivityTaskFailedRequest{ + DomainUUID: constants.TestDomainID, + FailedRequest: &types.RespondActivityTaskFailedRequest{ + TaskToken: taskToken, + Identity: identity, + }, + }) + s.NotNil(err) + s.IsType(&types.EntityNotExistsError{}, err) +} + +func (s *engineSuite) TestRespondActivityTaskFailedIfNoRunID() { + + taskToken, _ := json.Marshal(&common.TaskToken{ + WorkflowID: "wId", + ScheduleID: 2, + }) + identity := "testIdentity" + + s.mockExecutionMgr.On("GetCurrentExecution", mock.Anything, mock.Anything).Return(nil, + &types.EntityNotExistsError{}).Once() + + err := s.mockHistoryEngine.RespondActivityTaskFailed(context.Background(), &types.HistoryRespondActivityTaskFailedRequest{ + DomainUUID: constants.TestDomainID, + FailedRequest: &types.RespondActivityTaskFailedRequest{ + TaskToken: taskToken, + Identity: identity, + }, + }) + s.NotNil(err) + s.IsType(&types.EntityNotExistsError{}, err) +} + +func (s *engineSuite) TestRespondActivityTaskFailedIfGetExecutionFailed() { + + taskToken, _ := json.Marshal(&common.TaskToken{ + WorkflowID: "wId", + RunID: constants.TestRunID, + ScheduleID: 2, + }) + identity := "testIdentity" + + s.mockExecutionMgr.On("GetWorkflowExecution", mock.Anything, mock.Anything).Return(nil, + errors.New("FAILED")).Once() + + err := s.mockHistoryEngine.RespondActivityTaskFailed(context.Background(), &types.HistoryRespondActivityTaskFailedRequest{ + DomainUUID: constants.TestDomainID, + FailedRequest: &types.RespondActivityTaskFailedRequest{ + TaskToken: taskToken, + Identity: identity, + }, + }) + s.EqualError(err, "FAILED") +} + +func (s *engineSuite) TestRespondActivityTaskFailededIfNoAIdProvided() { + + taskToken, _ := json.Marshal(&common.TaskToken{ + WorkflowID: "wId", + ScheduleID: common.EmptyEventID, + }) + workflowExecution := types.WorkflowExecution{ + WorkflowID: "wId", + RunID: constants.TestRunID, + } + tasklist := "testTaskList" + identity := "testIdentity" + + msBuilder := execution.NewMutableStateBuilderWithEventV2( + s.mockHistoryEngine.shard, + testlogger.New(s.Suite.T()), + constants.TestRunID, + constants.TestLocalDomainEntry, + ) + test.AddWorkflowExecutionStartedEvent(msBuilder, workflowExecution, "wType", tasklist, []byte("input"), 100, 200, identity) + test.AddDecisionTaskScheduledEvent(msBuilder) + ms := execution.CreatePersistenceMutableState(msBuilder) + gwmsResponse := &persistence.GetWorkflowExecutionResponse{State: ms} + gceResponse := &persistence.GetCurrentExecutionResponse{RunID: constants.TestRunID} + + s.mockExecutionMgr.On("GetCurrentExecution", mock.Anything, mock.Anything).Return(gceResponse, nil).Once() + s.mockExecutionMgr.On("GetWorkflowExecution", mock.Anything, mock.Anything).Return(gwmsResponse, nil).Once() + + err := s.mockHistoryEngine.RespondActivityTaskFailed(context.Background(), &types.HistoryRespondActivityTaskFailedRequest{ + DomainUUID: constants.TestDomainID, + FailedRequest: &types.RespondActivityTaskFailedRequest{ + TaskToken: taskToken, + Identity: identity, + }, + }) + s.EqualError(err, "Neither ActivityID nor ScheduleID is provided") +} + +func (s *engineSuite) TestRespondActivityTaskFailededIfNotFound() { + + taskToken, _ := json.Marshal(&common.TaskToken{ + WorkflowID: "wId", + ScheduleID: common.EmptyEventID, + ActivityID: "aid", + }) + workflowExecution := types.WorkflowExecution{ + WorkflowID: "wId", + RunID: constants.TestRunID, + } + tasklist := "testTaskList" + identity := "testIdentity" + + msBuilder := execution.NewMutableStateBuilderWithEventV2( + s.mockHistoryEngine.shard, + testlogger.New(s.Suite.T()), + constants.TestRunID, + constants.TestLocalDomainEntry, + ) + test.AddWorkflowExecutionStartedEvent(msBuilder, workflowExecution, "wType", tasklist, []byte("input"), 100, 200, identity) + test.AddDecisionTaskScheduledEvent(msBuilder) + ms := execution.CreatePersistenceMutableState(msBuilder) + gwmsResponse := &persistence.GetWorkflowExecutionResponse{State: ms} + gceResponse := &persistence.GetCurrentExecutionResponse{RunID: constants.TestRunID} + + s.mockExecutionMgr.On("GetCurrentExecution", mock.Anything, mock.Anything).Return(gceResponse, nil).Once() + s.mockExecutionMgr.On("GetWorkflowExecution", mock.Anything, mock.Anything).Return(gwmsResponse, nil).Once() + + err := s.mockHistoryEngine.RespondActivityTaskFailed(context.Background(), &types.HistoryRespondActivityTaskFailedRequest{ + DomainUUID: constants.TestDomainID, + FailedRequest: &types.RespondActivityTaskFailedRequest{ + TaskToken: taskToken, + Identity: identity, + }, + }) + s.Error(err) +} + +func (s *engineSuite) TestRespondActivityTaskFailedUpdateExecutionFailed() { + + we := types.WorkflowExecution{ + WorkflowID: "wId", + RunID: constants.TestRunID, + } + tl := "testTaskList" + taskToken, _ := json.Marshal(&common.TaskToken{ + WorkflowID: we.WorkflowID, + RunID: we.RunID, + ScheduleID: 5, + }) + identity := "testIdentity" + activityID := "activity1_id" + activityType := "activity_type1" + activityInput := []byte("input1") + + msBuilder := execution.NewMutableStateBuilderWithEventV2( + s.mockHistoryEngine.shard, + testlogger.New(s.Suite.T()), + we.GetRunID(), + constants.TestLocalDomainEntry, + ) + test.AddWorkflowExecutionStartedEvent(msBuilder, we, "wType", tl, []byte("input"), 100, 100, identity) + di := test.AddDecisionTaskScheduledEvent(msBuilder) + decisionStartedEvent := test.AddDecisionTaskStartedEvent(msBuilder, di.ScheduleID, tl, identity) + decisionCompletedEvent := test.AddDecisionTaskCompletedEvent(msBuilder, di.ScheduleID, + decisionStartedEvent.ID, nil, identity) + activityScheduledEvent, _ := test.AddActivityTaskScheduledEvent(msBuilder, decisionCompletedEvent.ID, activityID, + activityType, tl, activityInput, 100, 10, 1, 5) + test.AddActivityTaskStartedEvent(msBuilder, activityScheduledEvent.ID, identity) + + ms := execution.CreatePersistenceMutableState(msBuilder) + gwmsResponse := &persistence.GetWorkflowExecutionResponse{State: ms} + + s.mockExecutionMgr.On("GetWorkflowExecution", mock.Anything, mock.Anything).Return(gwmsResponse, nil).Once() + s.mockHistoryV2Mgr.On("AppendHistoryNodes", mock.Anything, mock.Anything).Return(&persistence.AppendHistoryNodesResponse{}, nil).Once() + s.mockExecutionMgr.On("UpdateWorkflowExecution", mock.Anything, mock.Anything).Return(&persistence.UpdateWorkflowExecutionResponse{MutableStateUpdateSessionStats: &persistence.MutableStateUpdateSessionStats{}}, errors.New("FAILED")).Once() + s.mockShardManager.On("UpdateShard", mock.Anything, mock.Anything).Return(nil).Once() + + err := s.mockHistoryEngine.RespondActivityTaskFailed(context.Background(), &types.HistoryRespondActivityTaskFailedRequest{ + DomainUUID: constants.TestDomainID, + FailedRequest: &types.RespondActivityTaskFailedRequest{ + TaskToken: taskToken, + Identity: identity, + }, + }) + s.EqualError(err, "FAILED") +} + +func (s *engineSuite) TestRespondActivityTaskFailedIfTaskCompleted() { + + we := types.WorkflowExecution{ + WorkflowID: "wId", + RunID: constants.TestRunID, + } + tl := "testTaskList" + taskToken, _ := json.Marshal(&common.TaskToken{ + WorkflowID: we.WorkflowID, + RunID: we.RunID, + ScheduleID: 5, + }) + identity := "testIdentity" + activityID := "activity1_id" + activityType := "activity_type1" + activityInput := []byte("input1") + failReason := "fail reason" + details := []byte("fail details") + + msBuilder := execution.NewMutableStateBuilderWithEventV2( + s.mockHistoryEngine.shard, + testlogger.New(s.Suite.T()), + we.GetRunID(), + constants.TestLocalDomainEntry, + ) + test.AddWorkflowExecutionStartedEvent(msBuilder, we, "wType", tl, []byte("input"), 100, 100, identity) + di := test.AddDecisionTaskScheduledEvent(msBuilder) + decisionStartedEvent := test.AddDecisionTaskStartedEvent(msBuilder, di.ScheduleID, tl, identity) + decisionCompletedEvent := test.AddDecisionTaskCompletedEvent(msBuilder, di.ScheduleID, + decisionStartedEvent.ID, nil, identity) + activityScheduledEvent, _ := test.AddActivityTaskScheduledEvent(msBuilder, decisionCompletedEvent.ID, activityID, + activityType, tl, activityInput, 100, 10, 1, 5) + activityStartedEvent := test.AddActivityTaskStartedEvent(msBuilder, activityScheduledEvent.ID, identity) + test.AddActivityTaskFailedEvent(msBuilder, activityScheduledEvent.ID, activityStartedEvent.ID, + failReason, details, identity) + test.AddDecisionTaskScheduledEvent(msBuilder) + + ms := execution.CreatePersistenceMutableState(msBuilder) + gwmsResponse := &persistence.GetWorkflowExecutionResponse{State: ms} + + s.mockExecutionMgr.On("GetWorkflowExecution", mock.Anything, mock.Anything).Return(gwmsResponse, nil).Once() + + err := s.mockHistoryEngine.RespondActivityTaskFailed(context.Background(), &types.HistoryRespondActivityTaskFailedRequest{ + DomainUUID: constants.TestDomainID, + FailedRequest: &types.RespondActivityTaskFailedRequest{ + TaskToken: taskToken, + Reason: &failReason, + Details: details, + Identity: identity, + }, + }) + s.NotNil(err) + s.IsType(&types.EntityNotExistsError{}, err) +} + +func (s *engineSuite) TestRespondActivityTaskFailedIfTaskNotStarted() { + + we := types.WorkflowExecution{ + WorkflowID: "wId", + RunID: constants.TestRunID, + } + tl := "testTaskList" + taskToken, _ := json.Marshal(&common.TaskToken{ + WorkflowID: we.WorkflowID, + RunID: we.RunID, + ScheduleID: 5, + }) + identity := "testIdentity" + activityID := "activity1_id" + activityType := "activity_type1" + activityInput := []byte("input1") + + msBuilder := execution.NewMutableStateBuilderWithEventV2( + s.mockHistoryEngine.shard, + testlogger.New(s.Suite.T()), + we.GetRunID(), + constants.TestLocalDomainEntry, + ) + test.AddWorkflowExecutionStartedEvent(msBuilder, we, "wType", tl, []byte("input"), 100, 100, identity) + di := test.AddDecisionTaskScheduledEvent(msBuilder) + decisionStartedEvent := test.AddDecisionTaskStartedEvent(msBuilder, di.ScheduleID, tl, identity) + decisionCompletedEvent := test.AddDecisionTaskCompletedEvent(msBuilder, di.ScheduleID, + decisionStartedEvent.ID, nil, identity) + test.AddActivityTaskScheduledEvent(msBuilder, decisionCompletedEvent.ID, activityID, + activityType, tl, activityInput, 100, 10, 1, 5) + + ms := execution.CreatePersistenceMutableState(msBuilder) + gwmsResponse := &persistence.GetWorkflowExecutionResponse{State: ms} + + s.mockExecutionMgr.On("GetWorkflowExecution", mock.Anything, mock.Anything).Return(gwmsResponse, nil).Once() + + err := s.mockHistoryEngine.RespondActivityTaskFailed(context.Background(), &types.HistoryRespondActivityTaskFailedRequest{ + DomainUUID: constants.TestDomainID, + FailedRequest: &types.RespondActivityTaskFailedRequest{ + TaskToken: taskToken, + Identity: identity, + }, + }) + s.NotNil(err) + s.IsType(&types.EntityNotExistsError{}, err) +} + +func (s *engineSuite) TestRespondActivityTaskFailedConflictOnUpdate() { + + we := types.WorkflowExecution{ + WorkflowID: "wId", + RunID: constants.TestRunID, + } + tl := "testTaskList" + taskToken, _ := json.Marshal(&common.TaskToken{ + WorkflowID: we.WorkflowID, + RunID: we.RunID, + ScheduleID: 5, + }) + identity := "testIdentity" + activity1ID := "activity1" + activity1Type := "activity_type1" + activity1Input := []byte("input1") + failReason := "fail reason" + details := []byte("fail details.") + activity2ID := "activity2" + activity2Type := "activity_type2" + activity2Input := []byte("input2") + activity2Result := []byte("activity2_result") + + msBuilder := execution.NewMutableStateBuilderWithEventV2( + s.mockHistoryEngine.shard, + testlogger.New(s.Suite.T()), + we.GetRunID(), + constants.TestLocalDomainEntry, + ) + test.AddWorkflowExecutionStartedEvent(msBuilder, we, "wType", tl, []byte("input"), 25, 25, identity) + di1 := test.AddDecisionTaskScheduledEvent(msBuilder) + decisionStartedEvent1 := test.AddDecisionTaskStartedEvent(msBuilder, di1.ScheduleID, tl, identity) + decisionCompletedEvent1 := test.AddDecisionTaskCompletedEvent(msBuilder, di1.ScheduleID, + decisionStartedEvent1.ID, nil, identity) + activity1ScheduledEvent, _ := test.AddActivityTaskScheduledEvent(msBuilder, decisionCompletedEvent1.ID, activity1ID, + activity1Type, tl, activity1Input, 100, 10, 1, 5) + activity2ScheduledEvent, _ := test.AddActivityTaskScheduledEvent(msBuilder, decisionCompletedEvent1.ID, activity2ID, + activity2Type, tl, activity2Input, 100, 10, 1, 5) + test.AddActivityTaskStartedEvent(msBuilder, activity1ScheduledEvent.ID, identity) + activity2StartedEvent := test.AddActivityTaskStartedEvent(msBuilder, activity2ScheduledEvent.ID, identity) + + ms1 := execution.CreatePersistenceMutableState(msBuilder) + gwmsResponse1 := &persistence.GetWorkflowExecutionResponse{State: ms1} + + test.AddActivityTaskCompletedEvent(msBuilder, activity2ScheduledEvent.ID, + activity2StartedEvent.ID, activity2Result, identity) + test.AddDecisionTaskScheduledEvent(msBuilder) + + ms2 := execution.CreatePersistenceMutableState(msBuilder) + gwmsResponse2 := &persistence.GetWorkflowExecutionResponse{State: ms2} + + s.mockExecutionMgr.On("GetWorkflowExecution", mock.Anything, mock.Anything).Return(gwmsResponse1, nil).Once() + s.mockHistoryV2Mgr.On("AppendHistoryNodes", mock.Anything, mock.Anything).Return(&persistence.AppendHistoryNodesResponse{}, nil).Once() + s.mockExecutionMgr.On("UpdateWorkflowExecution", mock.Anything, mock.Anything).Return(&persistence.UpdateWorkflowExecutionResponse{MutableStateUpdateSessionStats: &persistence.MutableStateUpdateSessionStats{}}, &persistence.ConditionFailedError{}).Once() + + s.mockExecutionMgr.On("GetWorkflowExecution", mock.Anything, mock.Anything).Return(gwmsResponse2, nil).Once() + s.mockHistoryV2Mgr.On("AppendHistoryNodes", mock.Anything, mock.Anything).Return(&persistence.AppendHistoryNodesResponse{}, nil).Once() + s.mockExecutionMgr.On("UpdateWorkflowExecution", mock.Anything, mock.Anything).Return(&persistence.UpdateWorkflowExecutionResponse{MutableStateUpdateSessionStats: &persistence.MutableStateUpdateSessionStats{}}, nil).Once() + + err := s.mockHistoryEngine.RespondActivityTaskFailed(context.Background(), &types.HistoryRespondActivityTaskFailedRequest{ + DomainUUID: constants.TestDomainID, + FailedRequest: &types.RespondActivityTaskFailedRequest{ + TaskToken: taskToken, + Reason: &failReason, + Details: details, + Identity: identity, + }, + }) + s.Nil(err, s.printHistory(msBuilder)) + executionBuilder := s.getBuilder(constants.TestDomainID, we) + s.Equal(int64(12), executionBuilder.GetExecutionInfo().NextEventID) + s.Equal(int64(3), executionBuilder.GetExecutionInfo().LastProcessedEvent) + s.Equal(persistence.WorkflowStateRunning, executionBuilder.GetExecutionInfo().State) + + s.True(executionBuilder.HasPendingDecision()) + di, ok := executionBuilder.GetDecisionInfo(int64(10)) + s.True(ok) + s.Equal(int32(25), di.DecisionTimeout) + s.Equal(int64(10), di.ScheduleID) + s.Equal(common.EmptyEventID, di.StartedID) +} + +func (s *engineSuite) TestRespondActivityTaskFailedMaxAttemptsExceeded() { + + we := types.WorkflowExecution{ + WorkflowID: "wId", + RunID: constants.TestRunID, + } + tl := "testTaskList" + taskToken, _ := json.Marshal(&common.TaskToken{ + WorkflowID: we.WorkflowID, + RunID: we.RunID, + ScheduleID: 5, + }) + identity := "testIdentity" + activityID := "activity1_id" + activityType := "activity_type1" + activityInput := []byte("input1") + + msBuilder := execution.NewMutableStateBuilderWithEventV2( + s.mockHistoryEngine.shard, + testlogger.New(s.Suite.T()), + we.GetRunID(), + constants.TestLocalDomainEntry, + ) + test.AddWorkflowExecutionStartedEvent(msBuilder, we, "wType", tl, []byte("input"), 100, 100, identity) + di := test.AddDecisionTaskScheduledEvent(msBuilder) + decisionStartedEvent := test.AddDecisionTaskStartedEvent(msBuilder, di.ScheduleID, tl, identity) + decisionCompletedEvent := test.AddDecisionTaskCompletedEvent(msBuilder, di.ScheduleID, + decisionStartedEvent.ID, nil, identity) + activityScheduledEvent, _ := test.AddActivityTaskScheduledEvent(msBuilder, decisionCompletedEvent.ID, activityID, + activityType, tl, activityInput, 100, 10, 1, 5) + test.AddActivityTaskStartedEvent(msBuilder, activityScheduledEvent.ID, identity) + + for i := 0; i < workflow.ConditionalRetryCount; i++ { + ms := execution.CreatePersistenceMutableState(msBuilder) + gwmsResponse := &persistence.GetWorkflowExecutionResponse{State: ms} + + s.mockExecutionMgr.On("GetWorkflowExecution", mock.Anything, mock.Anything).Return(gwmsResponse, nil).Once() + s.mockHistoryV2Mgr.On("AppendHistoryNodes", mock.Anything, mock.Anything).Return(&persistence.AppendHistoryNodesResponse{}, nil).Once() + s.mockExecutionMgr.On("UpdateWorkflowExecution", mock.Anything, mock.Anything).Return(&persistence.UpdateWorkflowExecutionResponse{MutableStateUpdateSessionStats: &persistence.MutableStateUpdateSessionStats{}}, &persistence.ConditionFailedError{}).Once() + } + + err := s.mockHistoryEngine.RespondActivityTaskFailed(context.Background(), &types.HistoryRespondActivityTaskFailedRequest{ + DomainUUID: constants.TestDomainID, + FailedRequest: &types.RespondActivityTaskFailedRequest{ + TaskToken: taskToken, + Identity: identity, + }, + }) + s.Equal(workflow.ErrMaxAttemptsExceeded, err) +} + +func (s *engineSuite) TestRespondActivityTaskFailedSuccess() { + + we := types.WorkflowExecution{ + WorkflowID: "wId", + RunID: constants.TestRunID, + } + tl := "testTaskList" + taskToken, _ := json.Marshal(&common.TaskToken{ + WorkflowID: we.WorkflowID, + RunID: we.RunID, + ScheduleID: 5, + }) + identity := "testIdentity" + activityID := "activity1_id" + activityType := "activity_type1" + activityInput := []byte("input1") + failReason := "failed" + failDetails := []byte("fail details.") + + msBuilder := execution.NewMutableStateBuilderWithEventV2( + s.mockHistoryEngine.shard, + testlogger.New(s.Suite.T()), + we.GetRunID(), + constants.TestLocalDomainEntry, + ) + test.AddWorkflowExecutionStartedEvent(msBuilder, we, "wType", tl, []byte("input"), 100, 100, identity) + di := test.AddDecisionTaskScheduledEvent(msBuilder) + decisionStartedEvent := test.AddDecisionTaskStartedEvent(msBuilder, di.ScheduleID, tl, identity) + decisionCompletedEvent := test.AddDecisionTaskCompletedEvent(msBuilder, di.ScheduleID, + decisionStartedEvent.ID, nil, identity) + activityScheduledEvent, _ := test.AddActivityTaskScheduledEvent(msBuilder, decisionCompletedEvent.ID, activityID, + activityType, tl, activityInput, 100, 10, 1, 5) + test.AddActivityTaskStartedEvent(msBuilder, activityScheduledEvent.ID, identity) + + ms := execution.CreatePersistenceMutableState(msBuilder) + gwmsResponse := &persistence.GetWorkflowExecutionResponse{State: ms} + + s.mockExecutionMgr.On("GetWorkflowExecution", mock.Anything, mock.Anything).Return(gwmsResponse, nil).Once() + s.mockHistoryV2Mgr.On("AppendHistoryNodes", mock.Anything, mock.Anything).Return(&persistence.AppendHistoryNodesResponse{}, nil).Once() + s.mockExecutionMgr.On("UpdateWorkflowExecution", mock.Anything, mock.Anything).Return(&persistence.UpdateWorkflowExecutionResponse{MutableStateUpdateSessionStats: &persistence.MutableStateUpdateSessionStats{}}, nil).Once() + + err := s.mockHistoryEngine.RespondActivityTaskFailed(context.Background(), &types.HistoryRespondActivityTaskFailedRequest{ + DomainUUID: constants.TestDomainID, + FailedRequest: &types.RespondActivityTaskFailedRequest{ + TaskToken: taskToken, + Reason: &failReason, + Details: failDetails, + Identity: identity, + }, + }) + s.Nil(err) + executionBuilder := s.getBuilder(constants.TestDomainID, we) + s.Equal(int64(9), executionBuilder.GetExecutionInfo().NextEventID) + s.Equal(int64(3), executionBuilder.GetExecutionInfo().LastProcessedEvent) + s.Equal(persistence.WorkflowStateRunning, executionBuilder.GetExecutionInfo().State) + + s.True(executionBuilder.HasPendingDecision()) + di, ok := executionBuilder.GetDecisionInfo(int64(8)) + s.True(ok) + s.Equal(int32(100), di.DecisionTimeout) + s.Equal(int64(8), di.ScheduleID) + s.Equal(common.EmptyEventID, di.StartedID) +} + +func (s *engineSuite) TestRespondActivityTaskFailedByIDSuccess() { + + we := types.WorkflowExecution{ + WorkflowID: "wId", + RunID: constants.TestRunID, + } + tl := "testTaskList" + + identity := "testIdentity" + activityID := "activity1_id" + activityType := "activity_type1" + activityInput := []byte("input1") + failReason := "failed" + failDetails := []byte("fail details.") + taskToken, _ := json.Marshal(&common.TaskToken{ + WorkflowID: we.WorkflowID, + ScheduleID: common.EmptyEventID, + ActivityID: activityID, + }) + + msBuilder := execution.NewMutableStateBuilderWithEventV2( + s.mockHistoryEngine.shard, + testlogger.New(s.Suite.T()), + we.GetRunID(), + constants.TestLocalDomainEntry, + ) + test.AddWorkflowExecutionStartedEvent(msBuilder, we, "wType", tl, []byte("input"), 100, 100, identity) + decisionScheduledEvent := test.AddDecisionTaskScheduledEvent(msBuilder) + decisionStartedEvent := test.AddDecisionTaskStartedEvent(msBuilder, decisionScheduledEvent.ScheduleID, tl, identity) + decisionCompletedEvent := test.AddDecisionTaskCompletedEvent(msBuilder, decisionScheduledEvent.ScheduleID, + decisionStartedEvent.ID, nil, identity) + activityScheduledEvent, _ := test.AddActivityTaskScheduledEvent(msBuilder, decisionCompletedEvent.ID, activityID, + activityType, tl, activityInput, 100, 10, 1, 5) + test.AddActivityTaskStartedEvent(msBuilder, activityScheduledEvent.ID, identity) + + ms := execution.CreatePersistenceMutableState(msBuilder) + gwmsResponse := &persistence.GetWorkflowExecutionResponse{State: ms} + gceResponse := &persistence.GetCurrentExecutionResponse{RunID: we.RunID} + + s.mockExecutionMgr.On("GetCurrentExecution", mock.Anything, mock.Anything).Return(gceResponse, nil).Once() + s.mockExecutionMgr.On("GetWorkflowExecution", mock.Anything, mock.Anything).Return(gwmsResponse, nil).Once() + s.mockHistoryV2Mgr.On("AppendHistoryNodes", mock.Anything, mock.Anything).Return(&persistence.AppendHistoryNodesResponse{}, nil).Once() + s.mockExecutionMgr.On("UpdateWorkflowExecution", mock.Anything, mock.Anything).Return(&persistence.UpdateWorkflowExecutionResponse{MutableStateUpdateSessionStats: &persistence.MutableStateUpdateSessionStats{}}, nil).Once() + + err := s.mockHistoryEngine.RespondActivityTaskFailed(context.Background(), &types.HistoryRespondActivityTaskFailedRequest{ + DomainUUID: constants.TestDomainID, + FailedRequest: &types.RespondActivityTaskFailedRequest{ + TaskToken: taskToken, + Reason: &failReason, + Details: failDetails, + Identity: identity, + }, + }) + s.Nil(err) + executionBuilder := s.getBuilder(constants.TestDomainID, we) + s.Equal(int64(9), executionBuilder.GetExecutionInfo().NextEventID) + s.Equal(int64(3), executionBuilder.GetExecutionInfo().LastProcessedEvent) + s.Equal(persistence.WorkflowStateRunning, executionBuilder.GetExecutionInfo().State) + + s.True(executionBuilder.HasPendingDecision()) + di, ok := executionBuilder.GetDecisionInfo(int64(8)) + s.True(ok) + s.Equal(int32(100), di.DecisionTimeout) + s.Equal(int64(8), di.ScheduleID) + s.Equal(common.EmptyEventID, di.StartedID) +} + +func (s *engineSuite) TestRecordActivityTaskHeartBeatSuccess_NoTimer() { + + we := types.WorkflowExecution{ + WorkflowID: "wId", + RunID: constants.TestRunID, + } + tl := "testTaskList" + taskToken, _ := json.Marshal(&common.TaskToken{ + WorkflowID: we.WorkflowID, + RunID: we.RunID, + ScheduleID: 5, + }) + identity := "testIdentity" + activityID := "activity1_id" + activityType := "activity_type1" + activityInput := []byte("input1") + + msBuilder := execution.NewMutableStateBuilderWithEventV2( + s.mockHistoryEngine.shard, + testlogger.New(s.Suite.T()), + we.GetRunID(), + constants.TestLocalDomainEntry, + ) + test.AddWorkflowExecutionStartedEvent(msBuilder, we, "wType", tl, []byte("input"), 100, 100, identity) + di := test.AddDecisionTaskScheduledEvent(msBuilder) + decisionStartedEvent := test.AddDecisionTaskStartedEvent(msBuilder, di.ScheduleID, tl, identity) + decisionCompletedEvent := test.AddDecisionTaskCompletedEvent(msBuilder, di.ScheduleID, + decisionStartedEvent.ID, nil, identity) + activityScheduledEvent, _ := test.AddActivityTaskScheduledEvent(msBuilder, decisionCompletedEvent.ID, activityID, + activityType, tl, activityInput, 100, 10, 1, 0) + test.AddActivityTaskStartedEvent(msBuilder, activityScheduledEvent.ID, identity) + + // No HeartBeat timer running. + ms := execution.CreatePersistenceMutableState(msBuilder) + gwmsResponse := &persistence.GetWorkflowExecutionResponse{State: ms} + s.mockExecutionMgr.On("GetWorkflowExecution", mock.Anything, mock.Anything).Return(gwmsResponse, nil).Once() + s.mockExecutionMgr.On("UpdateWorkflowExecution", mock.Anything, mock.Anything).Return(&persistence.UpdateWorkflowExecutionResponse{MutableStateUpdateSessionStats: &persistence.MutableStateUpdateSessionStats{}}, nil).Once() + + detais := []byte("details") + + _, err := s.mockHistoryEngine.RecordActivityTaskHeartbeat(context.Background(), &types.HistoryRecordActivityTaskHeartbeatRequest{ + DomainUUID: constants.TestDomainID, + HeartbeatRequest: &types.RecordActivityTaskHeartbeatRequest{ + TaskToken: taskToken, + Identity: identity, + Details: detais, + }, + }) + s.Nil(err) +} + +func (s *engineSuite) TestRecordActivityTaskHeartBeatSuccess_TimerRunning() { + + we := types.WorkflowExecution{ + WorkflowID: "wId", + RunID: constants.TestRunID, + } + tl := "testTaskList" + taskToken, _ := json.Marshal(&common.TaskToken{ + WorkflowID: we.WorkflowID, + RunID: we.RunID, + ScheduleID: 5, + }) + identity := "testIdentity" + activityID := "activity1_id" + activityType := "activity_type1" + activityInput := []byte("input1") + + msBuilder := execution.NewMutableStateBuilderWithEventV2( + s.mockHistoryEngine.shard, + testlogger.New(s.Suite.T()), + we.GetRunID(), + constants.TestLocalDomainEntry, + ) + test.AddWorkflowExecutionStartedEvent(msBuilder, we, "wType", tl, []byte("input"), 100, 100, identity) + di := test.AddDecisionTaskScheduledEvent(msBuilder) + decisionStartedEvent := test.AddDecisionTaskStartedEvent(msBuilder, di.ScheduleID, tl, identity) + decisionCompletedEvent := test.AddDecisionTaskCompletedEvent(msBuilder, di.ScheduleID, + decisionStartedEvent.ID, nil, identity) + activityScheduledEvent, _ := test.AddActivityTaskScheduledEvent(msBuilder, decisionCompletedEvent.ID, activityID, + activityType, tl, activityInput, 100, 10, 1, 1) + test.AddActivityTaskStartedEvent(msBuilder, activityScheduledEvent.ID, identity) + + ms := execution.CreatePersistenceMutableState(msBuilder) + gwmsResponse := &persistence.GetWorkflowExecutionResponse{State: ms} + + // HeartBeat timer running. + s.mockExecutionMgr.On("GetWorkflowExecution", mock.Anything, mock.Anything).Return(gwmsResponse, nil).Once() + s.mockExecutionMgr.On("UpdateWorkflowExecution", mock.Anything, mock.Anything).Return(&persistence.UpdateWorkflowExecutionResponse{MutableStateUpdateSessionStats: &persistence.MutableStateUpdateSessionStats{}}, nil).Once() + + detais := []byte("details") + + _, err := s.mockHistoryEngine.RecordActivityTaskHeartbeat(context.Background(), &types.HistoryRecordActivityTaskHeartbeatRequest{ + DomainUUID: constants.TestDomainID, + HeartbeatRequest: &types.RecordActivityTaskHeartbeatRequest{ + TaskToken: taskToken, + Identity: identity, + Details: detais, + }, + }) + s.Nil(err) + executionBuilder := s.getBuilder(constants.TestDomainID, we) + s.Equal(int64(7), executionBuilder.GetExecutionInfo().NextEventID) + s.Equal(int64(3), executionBuilder.GetExecutionInfo().LastProcessedEvent) + s.Equal(persistence.WorkflowStateRunning, executionBuilder.GetExecutionInfo().State) + s.False(executionBuilder.HasPendingDecision()) +} + +func (s *engineSuite) TestRecordActivityTaskHeartBeatByIDSuccess() { + + we := types.WorkflowExecution{ + WorkflowID: "wId", + RunID: constants.TestRunID, + } + tl := "testTaskList" + identity := "testIdentity" + activityID := "activity1_id" + activityType := "activity_type1" + activityInput := []byte("input1") + taskToken, _ := json.Marshal(&common.TaskToken{ + WorkflowID: we.WorkflowID, + RunID: we.RunID, + ScheduleID: common.EmptyEventID, + ActivityID: activityID, + }) + + msBuilder := execution.NewMutableStateBuilderWithEventV2( + s.mockHistoryEngine.shard, + testlogger.New(s.Suite.T()), + we.GetRunID(), + constants.TestLocalDomainEntry, + ) + test.AddWorkflowExecutionStartedEvent(msBuilder, we, "wType", tl, []byte("input"), 100, 100, identity) + di := test.AddDecisionTaskScheduledEvent(msBuilder) + decisionStartedEvent := test.AddDecisionTaskStartedEvent(msBuilder, di.ScheduleID, tl, identity) + decisionCompletedEvent := test.AddDecisionTaskCompletedEvent(msBuilder, di.ScheduleID, + decisionStartedEvent.ID, nil, identity) + activityScheduledEvent, _ := test.AddActivityTaskScheduledEvent(msBuilder, decisionCompletedEvent.ID, activityID, + activityType, tl, activityInput, 100, 10, 1, 0) + test.AddActivityTaskStartedEvent(msBuilder, activityScheduledEvent.ID, identity) + + // No HeartBeat timer running. + ms := execution.CreatePersistenceMutableState(msBuilder) + gwmsResponse := &persistence.GetWorkflowExecutionResponse{State: ms} + s.mockExecutionMgr.On("GetWorkflowExecution", mock.Anything, mock.Anything).Return(gwmsResponse, nil).Once() + s.mockExecutionMgr.On("UpdateWorkflowExecution", mock.Anything, mock.Anything).Return(&persistence.UpdateWorkflowExecutionResponse{MutableStateUpdateSessionStats: &persistence.MutableStateUpdateSessionStats{}}, nil).Once() + + detais := []byte("details") + + _, err := s.mockHistoryEngine.RecordActivityTaskHeartbeat(context.Background(), &types.HistoryRecordActivityTaskHeartbeatRequest{ + DomainUUID: constants.TestDomainID, + HeartbeatRequest: &types.RecordActivityTaskHeartbeatRequest{ + TaskToken: taskToken, + Identity: identity, + Details: detais, + }, + }) + s.Nil(err) +} + +func (s *engineSuite) TestRespondActivityTaskCanceled_Scheduled() { + + we := types.WorkflowExecution{ + WorkflowID: "wId", + RunID: constants.TestRunID, + } + tl := "testTaskList" + taskToken, _ := json.Marshal(&common.TaskToken{ + WorkflowID: we.WorkflowID, + RunID: we.RunID, + ScheduleID: 5, + }) + identity := "testIdentity" + activityID := "activity1_id" + activityType := "activity_type1" + activityInput := []byte("input1") + + msBuilder := execution.NewMutableStateBuilderWithEventV2( + s.mockHistoryEngine.shard, + testlogger.New(s.Suite.T()), + we.GetRunID(), + constants.TestLocalDomainEntry, + ) + test.AddWorkflowExecutionStartedEvent(msBuilder, we, "wType", tl, []byte("input"), 100, 100, identity) + di := test.AddDecisionTaskScheduledEvent(msBuilder) + decisionStartedEvent := test.AddDecisionTaskStartedEvent(msBuilder, di.ScheduleID, tl, identity) + decisionCompletedEvent := test.AddDecisionTaskCompletedEvent(msBuilder, di.ScheduleID, + decisionStartedEvent.ID, nil, identity) + test.AddActivityTaskScheduledEvent(msBuilder, decisionCompletedEvent.ID, activityID, + activityType, tl, activityInput, 100, 10, 1, 1) + + ms := execution.CreatePersistenceMutableState(msBuilder) + gwmsResponse := &persistence.GetWorkflowExecutionResponse{State: ms} + + s.mockExecutionMgr.On("GetWorkflowExecution", mock.Anything, mock.Anything).Return(gwmsResponse, nil).Once() + + err := s.mockHistoryEngine.RespondActivityTaskCanceled(context.Background(), &types.HistoryRespondActivityTaskCanceledRequest{ + DomainUUID: constants.TestDomainID, + CancelRequest: &types.RespondActivityTaskCanceledRequest{ + TaskToken: taskToken, + Identity: identity, + Details: []byte("details"), + }, + }) + s.NotNil(err) + s.IsType(&types.EntityNotExistsError{}, err) +} + +func (s *engineSuite) TestRespondActivityTaskCanceled_Started() { + + we := types.WorkflowExecution{ + WorkflowID: "wId", + RunID: constants.TestRunID, + } + tl := "testTaskList" + taskToken, _ := json.Marshal(&common.TaskToken{ + WorkflowID: we.WorkflowID, + RunID: we.RunID, + ScheduleID: 5, + }) + identity := "testIdentity" + activityID := "activity1_id" + activityType := "activity_type1" + activityInput := []byte("input1") + + msBuilder := execution.NewMutableStateBuilderWithEventV2( + s.mockHistoryEngine.shard, + testlogger.New(s.Suite.T()), + we.GetRunID(), + constants.TestLocalDomainEntry, + ) + test.AddWorkflowExecutionStartedEvent(msBuilder, we, "wType", tl, []byte("input"), 100, 100, identity) + di := test.AddDecisionTaskScheduledEvent(msBuilder) + decisionStartedEvent := test.AddDecisionTaskStartedEvent(msBuilder, di.ScheduleID, tl, identity) + decisionCompletedEvent := test.AddDecisionTaskCompletedEvent(msBuilder, di.ScheduleID, + decisionStartedEvent.ID, nil, identity) + activityScheduledEvent, _ := test.AddActivityTaskScheduledEvent(msBuilder, decisionCompletedEvent.ID, activityID, + activityType, tl, activityInput, 100, 10, 1, 1) + test.AddActivityTaskStartedEvent(msBuilder, activityScheduledEvent.ID, identity) + _, _, err := msBuilder.AddActivityTaskCancelRequestedEvent(decisionCompletedEvent.ID, activityID, identity) + s.Nil(err) + + ms := execution.CreatePersistenceMutableState(msBuilder) + gwmsResponse := &persistence.GetWorkflowExecutionResponse{State: ms} + + s.mockExecutionMgr.On("GetWorkflowExecution", mock.Anything, mock.Anything).Return(gwmsResponse, nil).Once() + s.mockHistoryV2Mgr.On("AppendHistoryNodes", mock.Anything, mock.Anything).Return(&persistence.AppendHistoryNodesResponse{}, nil).Once() + s.mockExecutionMgr.On("UpdateWorkflowExecution", mock.Anything, mock.Anything).Return(&persistence.UpdateWorkflowExecutionResponse{MutableStateUpdateSessionStats: &persistence.MutableStateUpdateSessionStats{}}, nil).Once() + + err = s.mockHistoryEngine.RespondActivityTaskCanceled(context.Background(), &types.HistoryRespondActivityTaskCanceledRequest{ + DomainUUID: constants.TestDomainID, + CancelRequest: &types.RespondActivityTaskCanceledRequest{ + TaskToken: taskToken, + Identity: identity, + Details: []byte("details"), + }, + }) + s.Nil(err) + executionBuilder := s.getBuilder(constants.TestDomainID, we) + s.Equal(int64(10), executionBuilder.GetExecutionInfo().NextEventID) + s.Equal(int64(3), executionBuilder.GetExecutionInfo().LastProcessedEvent) + s.Equal(persistence.WorkflowStateRunning, executionBuilder.GetExecutionInfo().State) + + s.True(executionBuilder.HasPendingDecision()) + di, ok := executionBuilder.GetDecisionInfo(int64(9)) + s.True(ok) + s.Equal(int32(100), di.DecisionTimeout) + s.Equal(int64(9), di.ScheduleID) + s.Equal(common.EmptyEventID, di.StartedID) +} + +func (s *engineSuite) TestRespondActivityTaskCanceledByID_Started() { + + we := types.WorkflowExecution{ + WorkflowID: "wId", + RunID: constants.TestRunID, + } + tl := "testTaskList" + identity := "testIdentity" + activityID := "activity1_id" + activityType := "activity_type1" + activityInput := []byte("input1") + taskToken, _ := json.Marshal(&common.TaskToken{ + WorkflowID: we.WorkflowID, + ScheduleID: common.EmptyEventID, + ActivityID: activityID, + }) + + msBuilder := execution.NewMutableStateBuilderWithEventV2( + s.mockHistoryEngine.shard, + testlogger.New(s.Suite.T()), + we.GetRunID(), + constants.TestLocalDomainEntry, + ) + test.AddWorkflowExecutionStartedEvent(msBuilder, we, "wType", tl, []byte("input"), 100, 100, identity) + decisionScheduledEvent := test.AddDecisionTaskScheduledEvent(msBuilder) + decisionStartedEvent := test.AddDecisionTaskStartedEvent(msBuilder, decisionScheduledEvent.ScheduleID, tl, identity) + decisionCompletedEvent := test.AddDecisionTaskCompletedEvent(msBuilder, decisionScheduledEvent.ScheduleID, + decisionStartedEvent.ID, nil, identity) + activityScheduledEvent, _ := test.AddActivityTaskScheduledEvent(msBuilder, decisionCompletedEvent.ID, activityID, + activityType, tl, activityInput, 100, 10, 1, 1) + test.AddActivityTaskStartedEvent(msBuilder, activityScheduledEvent.ID, identity) + _, _, err := msBuilder.AddActivityTaskCancelRequestedEvent(decisionCompletedEvent.ID, activityID, identity) + s.Nil(err) + + ms := execution.CreatePersistenceMutableState(msBuilder) + gwmsResponse := &persistence.GetWorkflowExecutionResponse{State: ms} + gceResponse := &persistence.GetCurrentExecutionResponse{RunID: we.RunID} + + s.mockExecutionMgr.On("GetCurrentExecution", mock.Anything, mock.Anything).Return(gceResponse, nil).Once() + s.mockExecutionMgr.On("GetWorkflowExecution", mock.Anything, mock.Anything).Return(gwmsResponse, nil).Once() + s.mockHistoryV2Mgr.On("AppendHistoryNodes", mock.Anything, mock.Anything).Return(&persistence.AppendHistoryNodesResponse{}, nil).Once() + s.mockExecutionMgr.On("UpdateWorkflowExecution", mock.Anything, mock.Anything).Return(&persistence.UpdateWorkflowExecutionResponse{MutableStateUpdateSessionStats: &persistence.MutableStateUpdateSessionStats{}}, nil).Once() + + err = s.mockHistoryEngine.RespondActivityTaskCanceled(context.Background(), &types.HistoryRespondActivityTaskCanceledRequest{ + DomainUUID: constants.TestDomainID, + CancelRequest: &types.RespondActivityTaskCanceledRequest{ + TaskToken: taskToken, + Identity: identity, + Details: []byte("details"), + }, + }) + s.Nil(err) + executionBuilder := s.getBuilder(constants.TestDomainID, we) + s.Equal(int64(10), executionBuilder.GetExecutionInfo().NextEventID) + s.Equal(int64(3), executionBuilder.GetExecutionInfo().LastProcessedEvent) + s.Equal(persistence.WorkflowStateRunning, executionBuilder.GetExecutionInfo().State) + + s.True(executionBuilder.HasPendingDecision()) + di, ok := executionBuilder.GetDecisionInfo(int64(9)) + s.True(ok) + s.Equal(int32(100), di.DecisionTimeout) + s.Equal(int64(9), di.ScheduleID) + s.Equal(common.EmptyEventID, di.StartedID) +} + +func (s *engineSuite) TestRespondActivityTaskCanceledIfNoRunID() { + + taskToken, _ := json.Marshal(&common.TaskToken{ + WorkflowID: "wId", + ScheduleID: 2, + }) + identity := "testIdentity" + + s.mockExecutionMgr.On("GetCurrentExecution", mock.Anything, mock.Anything).Return(nil, &types.EntityNotExistsError{}).Once() + + err := s.mockHistoryEngine.RespondActivityTaskCanceled(context.Background(), &types.HistoryRespondActivityTaskCanceledRequest{ + DomainUUID: constants.TestDomainID, + CancelRequest: &types.RespondActivityTaskCanceledRequest{ + TaskToken: taskToken, + Identity: identity, + }, + }) + s.NotNil(err) + s.IsType(&types.EntityNotExistsError{}, err) +} + +func (s *engineSuite) TestRespondActivityTaskCanceledIfNoAIdProvided() { + + taskToken, _ := json.Marshal(&common.TaskToken{ + WorkflowID: "wId", + ScheduleID: common.EmptyEventID, + }) + identity := "testIdentity" + + msBuilder := execution.NewMutableStateBuilderWithEventV2( + s.mockHistoryEngine.shard, + testlogger.New(s.Suite.T()), + constants.TestRunID, + constants.TestLocalDomainEntry, + ) + ms := execution.CreatePersistenceMutableState(msBuilder) + gwmsResponse := &persistence.GetWorkflowExecutionResponse{State: ms} + gceResponse := &persistence.GetCurrentExecutionResponse{RunID: constants.TestRunID} + + s.mockExecutionMgr.On("GetCurrentExecution", mock.Anything, mock.Anything).Return(gceResponse, nil).Once() + s.mockExecutionMgr.On("GetWorkflowExecution", mock.Anything, mock.Anything).Return(gwmsResponse, nil).Once() + + err := s.mockHistoryEngine.RespondActivityTaskCanceled(context.Background(), &types.HistoryRespondActivityTaskCanceledRequest{ + DomainUUID: constants.TestDomainID, + CancelRequest: &types.RespondActivityTaskCanceledRequest{ + TaskToken: taskToken, + Identity: identity, + }, + }) + s.EqualError(err, "Neither ActivityID nor ScheduleID is provided") +} + +func (s *engineSuite) TestRespondActivityTaskCanceledIfNotFound() { + + taskToken, _ := json.Marshal(&common.TaskToken{ + WorkflowID: "wId", + ScheduleID: common.EmptyEventID, + ActivityID: "aid", + }) + identity := "testIdentity" + + msBuilder := execution.NewMutableStateBuilderWithEventV2( + s.mockHistoryEngine.shard, + testlogger.New(s.Suite.T()), + constants.TestRunID, + constants.TestLocalDomainEntry, + ) + ms := execution.CreatePersistenceMutableState(msBuilder) + gwmsResponse := &persistence.GetWorkflowExecutionResponse{State: ms} + gceResponse := &persistence.GetCurrentExecutionResponse{RunID: constants.TestRunID} + + s.mockExecutionMgr.On("GetCurrentExecution", mock.Anything, mock.Anything).Return(gceResponse, nil).Once() + s.mockExecutionMgr.On("GetWorkflowExecution", mock.Anything, mock.Anything).Return(gwmsResponse, nil).Once() + + err := s.mockHistoryEngine.RespondActivityTaskCanceled(context.Background(), &types.HistoryRespondActivityTaskCanceledRequest{ + DomainUUID: constants.TestDomainID, + CancelRequest: &types.RespondActivityTaskCanceledRequest{ + TaskToken: taskToken, + Identity: identity, + }, + }) + s.Error(err) +} + +func (s *engineSuite) TestRequestCancel_RespondDecisionTaskCompleted_NotScheduled() { + + we := types.WorkflowExecution{ + WorkflowID: "wId", + RunID: constants.TestRunID, + } + tl := "testTaskList" + taskToken, _ := json.Marshal(&common.TaskToken{ + WorkflowID: we.WorkflowID, + RunID: we.RunID, + ScheduleID: 2, + }) + identity := "testIdentity" + activityID := "activity1_id" + + msBuilder := execution.NewMutableStateBuilderWithEventV2( + s.mockHistoryEngine.shard, + testlogger.New(s.Suite.T()), + we.GetRunID(), + constants.TestLocalDomainEntry, + ) + test.AddWorkflowExecutionStartedEvent(msBuilder, we, "wType", tl, []byte("input"), 100, 100, identity) + di := test.AddDecisionTaskScheduledEvent(msBuilder) + test.AddDecisionTaskStartedEvent(msBuilder, di.ScheduleID, tl, identity) + + decisions := []*types.Decision{{ + DecisionType: types.DecisionTypeRequestCancelActivityTask.Ptr(), + RequestCancelActivityTaskDecisionAttributes: &types.RequestCancelActivityTaskDecisionAttributes{ + ActivityID: activityID, + }, + }} + + ms := execution.CreatePersistenceMutableState(msBuilder) + gwmsResponse := &persistence.GetWorkflowExecutionResponse{State: ms} + + s.mockExecutionMgr.On("GetWorkflowExecution", mock.Anything, mock.Anything).Return(gwmsResponse, nil).Once() + s.mockHistoryV2Mgr.On("AppendHistoryNodes", mock.Anything, mock.Anything).Return(&persistence.AppendHistoryNodesResponse{}, nil).Once() + s.mockExecutionMgr.On("UpdateWorkflowExecution", mock.Anything, mock.Anything).Return(&persistence.UpdateWorkflowExecutionResponse{MutableStateUpdateSessionStats: &persistence.MutableStateUpdateSessionStats{}}, nil).Once() + + _, err := s.mockHistoryEngine.RespondDecisionTaskCompleted(context.Background(), &types.HistoryRespondDecisionTaskCompletedRequest{ + DomainUUID: constants.TestDomainID, + CompleteRequest: &types.RespondDecisionTaskCompletedRequest{ + TaskToken: taskToken, + Decisions: decisions, + ExecutionContext: []byte("context"), + Identity: identity, + }, + }) + s.Nil(err) + executionBuilder := s.getBuilder(constants.TestDomainID, we) + s.Equal(int64(7), executionBuilder.GetExecutionInfo().NextEventID) + s.Equal(int64(3), executionBuilder.GetExecutionInfo().LastProcessedEvent) + s.Equal(persistence.WorkflowStateRunning, executionBuilder.GetExecutionInfo().State) + s.False(executionBuilder.HasPendingDecision()) +} + +func (s *engineSuite) TestRequestCancel_RespondDecisionTaskCompleted_Scheduled() { + + we := types.WorkflowExecution{ + WorkflowID: "wId", + RunID: constants.TestRunID, + } + tl := "testTaskList" + taskToken, _ := json.Marshal(&common.TaskToken{ + WorkflowID: we.WorkflowID, + RunID: we.RunID, + ScheduleID: 6, + }) + identity := "testIdentity" + activityID := "activity1_id" + activityType := "activity_type1" + activityInput := []byte("input1") + + msBuilder := execution.NewMutableStateBuilderWithEventV2( + s.mockHistoryEngine.shard, + testlogger.New(s.Suite.T()), + we.GetRunID(), + constants.TestLocalDomainEntry, + ) + test.AddWorkflowExecutionStartedEvent(msBuilder, we, "wType", tl, []byte("input"), 100, 100, identity) + di := test.AddDecisionTaskScheduledEvent(msBuilder) + decisionStartedEvent := test.AddDecisionTaskStartedEvent(msBuilder, di.ScheduleID, tl, identity) + decisionCompletedEvent := test.AddDecisionTaskCompletedEvent(msBuilder, di.ScheduleID, + decisionStartedEvent.ID, nil, identity) + test.AddActivityTaskScheduledEvent(msBuilder, decisionCompletedEvent.ID, activityID, + activityType, tl, activityInput, 100, 10, 1, 1) + di2 := test.AddDecisionTaskScheduledEvent(msBuilder) + test.AddDecisionTaskStartedEvent(msBuilder, di2.ScheduleID, tl, identity) + + ms := execution.CreatePersistenceMutableState(msBuilder) + gwmsResponse := &persistence.GetWorkflowExecutionResponse{State: ms} + + decisions := []*types.Decision{{ + DecisionType: types.DecisionTypeRequestCancelActivityTask.Ptr(), + RequestCancelActivityTaskDecisionAttributes: &types.RequestCancelActivityTaskDecisionAttributes{ + ActivityID: activityID, + }, + }} + + s.mockExecutionMgr.On("GetWorkflowExecution", mock.Anything, mock.Anything).Return(gwmsResponse, nil).Once() + s.mockHistoryV2Mgr.On("AppendHistoryNodes", mock.Anything, mock.Anything).Return(&persistence.AppendHistoryNodesResponse{}, nil).Once() + s.mockExecutionMgr.On("UpdateWorkflowExecution", mock.Anything, mock.Anything).Return(&persistence.UpdateWorkflowExecutionResponse{MutableStateUpdateSessionStats: &persistence.MutableStateUpdateSessionStats{}}, nil).Once() + + _, err := s.mockHistoryEngine.RespondDecisionTaskCompleted(context.Background(), &types.HistoryRespondDecisionTaskCompletedRequest{ + DomainUUID: constants.TestDomainID, + CompleteRequest: &types.RespondDecisionTaskCompletedRequest{ + TaskToken: taskToken, + Decisions: decisions, + ExecutionContext: []byte("context"), + Identity: identity, + }, + }) + s.Nil(err) + + executionBuilder := s.getBuilder(constants.TestDomainID, we) + s.Equal(int64(12), executionBuilder.GetExecutionInfo().NextEventID) + s.Equal(int64(7), executionBuilder.GetExecutionInfo().LastProcessedEvent) + s.Equal(persistence.WorkflowStateRunning, executionBuilder.GetExecutionInfo().State) + s.True(executionBuilder.HasPendingDecision()) + di2, ok := executionBuilder.GetDecisionInfo(executionBuilder.GetExecutionInfo().NextEventID - 1) + s.True(ok) + s.Equal(executionBuilder.GetExecutionInfo().NextEventID-1, di2.ScheduleID) + s.Equal(int64(0), di2.Attempt) +} + +func (s *engineSuite) TestRequestCancel_RespondDecisionTaskCompleted_Started() { + + we := types.WorkflowExecution{ + WorkflowID: "wId", + RunID: constants.TestRunID, + } + tl := "testTaskList" + taskToken, _ := json.Marshal(&common.TaskToken{ + WorkflowID: we.WorkflowID, + RunID: we.RunID, + ScheduleID: 7, + }) + identity := "testIdentity" + activityID := "activity1_id" + activityType := "activity_type1" + activityInput := []byte("input1") + + msBuilder := execution.NewMutableStateBuilderWithEventV2( + s.mockHistoryEngine.shard, + testlogger.New(s.Suite.T()), + we.GetRunID(), + constants.TestLocalDomainEntry, + ) + test.AddWorkflowExecutionStartedEvent(msBuilder, we, "wType", tl, []byte("input"), 100, 100, identity) + di := test.AddDecisionTaskScheduledEvent(msBuilder) + decisionStartedEvent := test.AddDecisionTaskStartedEvent(msBuilder, di.ScheduleID, tl, identity) + decisionCompletedEvent := test.AddDecisionTaskCompletedEvent(msBuilder, di.ScheduleID, + decisionStartedEvent.ID, nil, identity) + activityScheduledEvent, _ := test.AddActivityTaskScheduledEvent(msBuilder, decisionCompletedEvent.ID, activityID, + activityType, tl, activityInput, 100, 10, 1, 0) + test.AddActivityTaskStartedEvent(msBuilder, activityScheduledEvent.ID, identity) + di2 := test.AddDecisionTaskScheduledEvent(msBuilder) + test.AddDecisionTaskStartedEvent(msBuilder, di2.ScheduleID, tl, identity) + + ms := execution.CreatePersistenceMutableState(msBuilder) + gwmsResponse := &persistence.GetWorkflowExecutionResponse{State: ms} + + decisions := []*types.Decision{{ + DecisionType: types.DecisionTypeRequestCancelActivityTask.Ptr(), + RequestCancelActivityTaskDecisionAttributes: &types.RequestCancelActivityTaskDecisionAttributes{ + ActivityID: activityID, + }, + }} + + s.mockExecutionMgr.On("GetWorkflowExecution", mock.Anything, mock.Anything).Return(gwmsResponse, nil).Once() + s.mockHistoryV2Mgr.On("AppendHistoryNodes", mock.Anything, mock.Anything).Return(&persistence.AppendHistoryNodesResponse{}, nil).Once() + s.mockExecutionMgr.On("UpdateWorkflowExecution", mock.Anything, mock.Anything).Return(&persistence.UpdateWorkflowExecutionResponse{MutableStateUpdateSessionStats: &persistence.MutableStateUpdateSessionStats{}}, nil).Once() + + _, err := s.mockHistoryEngine.RespondDecisionTaskCompleted(context.Background(), &types.HistoryRespondDecisionTaskCompletedRequest{ + DomainUUID: constants.TestDomainID, + CompleteRequest: &types.RespondDecisionTaskCompletedRequest{ + TaskToken: taskToken, + Decisions: decisions, + ExecutionContext: []byte("context"), + Identity: identity, + }, + }) + s.Nil(err) + + executionBuilder := s.getBuilder(constants.TestDomainID, we) + s.Equal(int64(11), executionBuilder.GetExecutionInfo().NextEventID) + s.Equal(int64(8), executionBuilder.GetExecutionInfo().LastProcessedEvent) + s.Equal(persistence.WorkflowStateRunning, executionBuilder.GetExecutionInfo().State) + s.False(executionBuilder.HasPendingDecision()) +} + +func (s *engineSuite) TestRequestCancel_RespondDecisionTaskCompleted_Completed() { + + we := types.WorkflowExecution{ + WorkflowID: "wId", + RunID: constants.TestRunID, + } + tl := "testTaskList" + taskToken, _ := json.Marshal(&common.TaskToken{ + WorkflowID: we.WorkflowID, + RunID: we.RunID, + ScheduleID: 6, + }) + identity := "testIdentity" + activityID := "activity1_id" + activityType := "activity_type1" + activityInput := []byte("input1") + workflowResult := []byte("workflow result") + + msBuilder := execution.NewMutableStateBuilderWithEventV2( + s.mockHistoryEngine.shard, + testlogger.New(s.Suite.T()), + we.GetRunID(), + constants.TestLocalDomainEntry, + ) + test.AddWorkflowExecutionStartedEvent(msBuilder, we, "wType", tl, []byte("input"), 100, 100, identity) + di := test.AddDecisionTaskScheduledEvent(msBuilder) + decisionStartedEvent := test.AddDecisionTaskStartedEvent(msBuilder, di.ScheduleID, tl, identity) + decisionCompletedEvent := test.AddDecisionTaskCompletedEvent(msBuilder, di.ScheduleID, + decisionStartedEvent.ID, nil, identity) + test.AddActivityTaskScheduledEvent(msBuilder, decisionCompletedEvent.ID, activityID, + activityType, tl, activityInput, 100, 10, 1, 0) + di2 := test.AddDecisionTaskScheduledEvent(msBuilder) + test.AddDecisionTaskStartedEvent(msBuilder, di2.ScheduleID, tl, identity) + + decisions := []*types.Decision{ + { + DecisionType: types.DecisionTypeRequestCancelActivityTask.Ptr(), + RequestCancelActivityTaskDecisionAttributes: &types.RequestCancelActivityTaskDecisionAttributes{ + ActivityID: activityID, + }, + }, + { + DecisionType: types.DecisionTypeCompleteWorkflowExecution.Ptr(), + CompleteWorkflowExecutionDecisionAttributes: &types.CompleteWorkflowExecutionDecisionAttributes{ + Result: workflowResult, + }, + }, + } + + ms := execution.CreatePersistenceMutableState(msBuilder) + gwmsResponse := &persistence.GetWorkflowExecutionResponse{State: ms} + s.mockExecutionMgr.On("GetWorkflowExecution", mock.Anything, mock.Anything).Return(gwmsResponse, nil).Once() + s.mockHistoryV2Mgr.On("AppendHistoryNodes", mock.Anything, mock.Anything).Return(&persistence.AppendHistoryNodesResponse{}, nil).Once() + s.mockExecutionMgr.On("UpdateWorkflowExecution", mock.Anything, mock.Anything).Return(&persistence.UpdateWorkflowExecutionResponse{MutableStateUpdateSessionStats: &persistence.MutableStateUpdateSessionStats{}}, nil).Once() + + _, err := s.mockHistoryEngine.RespondDecisionTaskCompleted(context.Background(), &types.HistoryRespondDecisionTaskCompletedRequest{ + DomainUUID: constants.TestDomainID, + CompleteRequest: &types.RespondDecisionTaskCompletedRequest{ + TaskToken: taskToken, + Decisions: decisions, + ExecutionContext: []byte("context"), + Identity: identity, + }, + }) + s.Nil(err) + + executionBuilder := s.getBuilder(constants.TestDomainID, we) + s.Equal(int64(11), executionBuilder.GetExecutionInfo().NextEventID) + s.Equal(int64(7), executionBuilder.GetExecutionInfo().LastProcessedEvent) + s.Equal(persistence.WorkflowStateCompleted, executionBuilder.GetExecutionInfo().State) + s.False(executionBuilder.HasPendingDecision()) +} + +func (s *engineSuite) TestRequestCancel_RespondDecisionTaskCompleted_NoHeartBeat() { + + we := types.WorkflowExecution{ + WorkflowID: "wId", + RunID: constants.TestRunID, + } + tl := "testTaskList" + taskToken, _ := json.Marshal(&common.TaskToken{ + WorkflowID: we.WorkflowID, + RunID: we.RunID, + ScheduleID: 7, + }) + identity := "testIdentity" + activityID := "activity1_id" + activityType := "activity_type1" + activityInput := []byte("input1") + + msBuilder := execution.NewMutableStateBuilderWithEventV2( + s.mockHistoryEngine.shard, + testlogger.New(s.Suite.T()), + we.GetRunID(), + constants.TestLocalDomainEntry, + ) + test.AddWorkflowExecutionStartedEvent(msBuilder, we, "wType", tl, []byte("input"), 100, 100, identity) + di := test.AddDecisionTaskScheduledEvent(msBuilder) + decisionStartedEvent := test.AddDecisionTaskStartedEvent(msBuilder, di.ScheduleID, tl, identity) + decisionCompletedEvent := test.AddDecisionTaskCompletedEvent(msBuilder, di.ScheduleID, + decisionStartedEvent.ID, nil, identity) + activityScheduledEvent, _ := test.AddActivityTaskScheduledEvent(msBuilder, decisionCompletedEvent.ID, activityID, + activityType, tl, activityInput, 100, 10, 1, 0) + test.AddActivityTaskStartedEvent(msBuilder, activityScheduledEvent.ID, identity) + di2 := test.AddDecisionTaskScheduledEvent(msBuilder) + test.AddDecisionTaskStartedEvent(msBuilder, di2.ScheduleID, tl, identity) + + ms := execution.CreatePersistenceMutableState(msBuilder) + gwmsResponse := &persistence.GetWorkflowExecutionResponse{State: ms} + + decisions := []*types.Decision{{ + DecisionType: types.DecisionTypeRequestCancelActivityTask.Ptr(), + RequestCancelActivityTaskDecisionAttributes: &types.RequestCancelActivityTaskDecisionAttributes{ + ActivityID: activityID, + }, + }} + + s.mockExecutionMgr.On("GetWorkflowExecution", mock.Anything, mock.Anything).Return(gwmsResponse, nil).Once() + s.mockHistoryV2Mgr.On("AppendHistoryNodes", mock.Anything, mock.Anything).Return(&persistence.AppendHistoryNodesResponse{}, nil).Once() + s.mockExecutionMgr.On("UpdateWorkflowExecution", mock.Anything, mock.Anything).Return(&persistence.UpdateWorkflowExecutionResponse{MutableStateUpdateSessionStats: &persistence.MutableStateUpdateSessionStats{}}, nil).Once() + + _, err := s.mockHistoryEngine.RespondDecisionTaskCompleted(context.Background(), &types.HistoryRespondDecisionTaskCompletedRequest{ + DomainUUID: constants.TestDomainID, + CompleteRequest: &types.RespondDecisionTaskCompletedRequest{ + TaskToken: taskToken, + Decisions: decisions, + ExecutionContext: []byte("context"), + Identity: identity, + }, + }) + s.Nil(err) + + executionBuilder := s.getBuilder(constants.TestDomainID, we) + s.Equal(int64(11), executionBuilder.GetExecutionInfo().NextEventID) + s.Equal(int64(8), executionBuilder.GetExecutionInfo().LastProcessedEvent) + s.Equal(persistence.WorkflowStateRunning, executionBuilder.GetExecutionInfo().State) + s.False(executionBuilder.HasPendingDecision()) + + // Try recording activity heartbeat + s.mockExecutionMgr.On("UpdateWorkflowExecution", mock.Anything, mock.Anything).Return(&persistence.UpdateWorkflowExecutionResponse{MutableStateUpdateSessionStats: &persistence.MutableStateUpdateSessionStats{}}, nil).Once() + + activityTaskToken, _ := json.Marshal(&common.TaskToken{ + WorkflowID: "wId", + RunID: we.GetRunID(), + ScheduleID: 5, + }) + + hbResponse, err := s.mockHistoryEngine.RecordActivityTaskHeartbeat(context.Background(), &types.HistoryRecordActivityTaskHeartbeatRequest{ + DomainUUID: constants.TestDomainID, + HeartbeatRequest: &types.RecordActivityTaskHeartbeatRequest{ + TaskToken: activityTaskToken, + Identity: identity, + Details: []byte("details"), + }, + }) + s.Nil(err) + s.NotNil(hbResponse) + s.True(hbResponse.CancelRequested) + + // Try cancelling the request. + s.mockHistoryV2Mgr.On("AppendHistoryNodes", mock.Anything, mock.Anything).Return(&persistence.AppendHistoryNodesResponse{}, nil).Once() + s.mockExecutionMgr.On("UpdateWorkflowExecution", mock.Anything, mock.Anything).Return(&persistence.UpdateWorkflowExecutionResponse{MutableStateUpdateSessionStats: &persistence.MutableStateUpdateSessionStats{}}, nil).Once() + + err = s.mockHistoryEngine.RespondActivityTaskCanceled(context.Background(), &types.HistoryRespondActivityTaskCanceledRequest{ + DomainUUID: constants.TestDomainID, + CancelRequest: &types.RespondActivityTaskCanceledRequest{ + TaskToken: activityTaskToken, + Identity: identity, + Details: []byte("details"), + }, + }) + s.Nil(err) + + executionBuilder = s.getBuilder(constants.TestDomainID, we) + s.Equal(int64(13), executionBuilder.GetExecutionInfo().NextEventID) + s.Equal(int64(8), executionBuilder.GetExecutionInfo().LastProcessedEvent) + s.Equal(persistence.WorkflowStateRunning, executionBuilder.GetExecutionInfo().State) + s.True(executionBuilder.HasPendingDecision()) +} + +func (s *engineSuite) TestRequestCancel_RespondDecisionTaskCompleted_Success() { + + we := types.WorkflowExecution{ + WorkflowID: "wId", + RunID: constants.TestRunID, + } + tl := "testTaskList" + taskToken, _ := json.Marshal(&common.TaskToken{ + WorkflowID: we.WorkflowID, + RunID: we.RunID, + ScheduleID: 7, + }) + identity := "testIdentity" + activityID := "activity1_id" + activityType := "activity_type1" + activityInput := []byte("input1") + + msBuilder := execution.NewMutableStateBuilderWithEventV2( + s.mockHistoryEngine.shard, + testlogger.New(s.Suite.T()), + we.GetRunID(), + constants.TestLocalDomainEntry, + ) + test.AddWorkflowExecutionStartedEvent(msBuilder, we, "wType", tl, []byte("input"), 100, 100, identity) + di := test.AddDecisionTaskScheduledEvent(msBuilder) + decisionStartedEvent := test.AddDecisionTaskStartedEvent(msBuilder, di.ScheduleID, tl, identity) + decisionCompletedEvent := test.AddDecisionTaskCompletedEvent(msBuilder, di.ScheduleID, + decisionStartedEvent.ID, nil, identity) + activityScheduledEvent, _ := test.AddActivityTaskScheduledEvent(msBuilder, decisionCompletedEvent.ID, activityID, + activityType, tl, activityInput, 100, 10, 1, 1) + test.AddActivityTaskStartedEvent(msBuilder, activityScheduledEvent.ID, identity) + di2 := test.AddDecisionTaskScheduledEvent(msBuilder) + test.AddDecisionTaskStartedEvent(msBuilder, di2.ScheduleID, tl, identity) + + ms := execution.CreatePersistenceMutableState(msBuilder) + gwmsResponse := &persistence.GetWorkflowExecutionResponse{State: ms} + + decisions := []*types.Decision{{ + DecisionType: types.DecisionTypeRequestCancelActivityTask.Ptr(), + RequestCancelActivityTaskDecisionAttributes: &types.RequestCancelActivityTaskDecisionAttributes{ + ActivityID: activityID, + }, + }} + + s.mockExecutionMgr.On("GetWorkflowExecution", mock.Anything, mock.Anything).Return(gwmsResponse, nil).Once() + s.mockHistoryV2Mgr.On("AppendHistoryNodes", mock.Anything, mock.Anything).Return(&persistence.AppendHistoryNodesResponse{}, nil).Once() + s.mockExecutionMgr.On("UpdateWorkflowExecution", mock.Anything, mock.Anything).Return(&persistence.UpdateWorkflowExecutionResponse{MutableStateUpdateSessionStats: &persistence.MutableStateUpdateSessionStats{}}, nil).Once() + + _, err := s.mockHistoryEngine.RespondDecisionTaskCompleted(context.Background(), &types.HistoryRespondDecisionTaskCompletedRequest{ + DomainUUID: constants.TestDomainID, + CompleteRequest: &types.RespondDecisionTaskCompletedRequest{ + TaskToken: taskToken, + Decisions: decisions, + ExecutionContext: []byte("context"), + Identity: identity, + }, + }) + s.Nil(err) + + executionBuilder := s.getBuilder(constants.TestDomainID, we) + s.Equal(int64(11), executionBuilder.GetExecutionInfo().NextEventID) + s.Equal(int64(8), executionBuilder.GetExecutionInfo().LastProcessedEvent) + s.Equal(persistence.WorkflowStateRunning, executionBuilder.GetExecutionInfo().State) + s.False(executionBuilder.HasPendingDecision()) + + // Try recording activity heartbeat + s.mockExecutionMgr.On("UpdateWorkflowExecution", mock.Anything, mock.Anything).Return(&persistence.UpdateWorkflowExecutionResponse{MutableStateUpdateSessionStats: &persistence.MutableStateUpdateSessionStats{}}, nil).Once() + + activityTaskToken, _ := json.Marshal(&common.TaskToken{ + WorkflowID: "wId", + RunID: we.GetRunID(), + ScheduleID: 5, + }) + + hbResponse, err := s.mockHistoryEngine.RecordActivityTaskHeartbeat(context.Background(), &types.HistoryRecordActivityTaskHeartbeatRequest{ + DomainUUID: constants.TestDomainID, + HeartbeatRequest: &types.RecordActivityTaskHeartbeatRequest{ + TaskToken: activityTaskToken, + Identity: identity, + Details: []byte("details"), + }, + }) + s.Nil(err) + s.NotNil(hbResponse) + s.True(hbResponse.CancelRequested) + + // Try cancelling the request. + s.mockHistoryV2Mgr.On("AppendHistoryNodes", mock.Anything, mock.Anything).Return(&persistence.AppendHistoryNodesResponse{}, nil).Once() + s.mockExecutionMgr.On("UpdateWorkflowExecution", mock.Anything, mock.Anything).Return(&persistence.UpdateWorkflowExecutionResponse{MutableStateUpdateSessionStats: &persistence.MutableStateUpdateSessionStats{}}, nil).Once() + + err = s.mockHistoryEngine.RespondActivityTaskCanceled(context.Background(), &types.HistoryRespondActivityTaskCanceledRequest{ + DomainUUID: constants.TestDomainID, + CancelRequest: &types.RespondActivityTaskCanceledRequest{ + TaskToken: activityTaskToken, + Identity: identity, + Details: []byte("details"), + }, + }) + s.Nil(err) + + executionBuilder = s.getBuilder(constants.TestDomainID, we) + s.Equal(int64(13), executionBuilder.GetExecutionInfo().NextEventID) + s.Equal(int64(8), executionBuilder.GetExecutionInfo().LastProcessedEvent) + s.Equal(persistence.WorkflowStateRunning, executionBuilder.GetExecutionInfo().State) + s.True(executionBuilder.HasPendingDecision()) +} + +func (s *engineSuite) TestRequestCancel_RespondDecisionTaskCompleted_SuccessWithQueries() { + we := types.WorkflowExecution{ + WorkflowID: "wId", + RunID: constants.TestRunID, + } + tl := "testTaskList" + taskToken, _ := json.Marshal(&common.TaskToken{ + WorkflowID: we.WorkflowID, + RunID: we.RunID, + ScheduleID: 7, + }) + identity := "testIdentity" + activityID := "activity1_id" + activityType := "activity_type1" + activityInput := []byte("input1") + + msBuilder := execution.NewMutableStateBuilderWithEventV2( + s.mockHistoryEngine.shard, + testlogger.New(s.Suite.T()), + we.GetRunID(), + constants.TestLocalDomainEntry, + ) + test.AddWorkflowExecutionStartedEvent(msBuilder, we, "wType", tl, []byte("input"), 100, 100, identity) + di := test.AddDecisionTaskScheduledEvent(msBuilder) + decisionStartedEvent := test.AddDecisionTaskStartedEvent(msBuilder, di.ScheduleID, tl, identity) + decisionCompletedEvent := test.AddDecisionTaskCompletedEvent(msBuilder, di.ScheduleID, + decisionStartedEvent.ID, nil, identity) + activityScheduledEvent, _ := test.AddActivityTaskScheduledEvent(msBuilder, decisionCompletedEvent.ID, activityID, + activityType, tl, activityInput, 100, 10, 1, 1) + test.AddActivityTaskStartedEvent(msBuilder, activityScheduledEvent.ID, identity) + di2 := test.AddDecisionTaskScheduledEvent(msBuilder) + test.AddDecisionTaskStartedEvent(msBuilder, di2.ScheduleID, tl, identity) + + ms := execution.CreatePersistenceMutableState(msBuilder) + gwmsResponse := &persistence.GetWorkflowExecutionResponse{State: ms} + + decisions := []*types.Decision{{ + DecisionType: types.DecisionTypeRequestCancelActivityTask.Ptr(), + RequestCancelActivityTaskDecisionAttributes: &types.RequestCancelActivityTaskDecisionAttributes{ + ActivityID: activityID, + }, + }} + + s.mockExecutionMgr.On("GetWorkflowExecution", mock.Anything, mock.Anything).Return(gwmsResponse, nil).Once() + s.mockHistoryV2Mgr.On("AppendHistoryNodes", mock.Anything, mock.Anything).Return(&persistence.AppendHistoryNodesResponse{}, nil).Once() + s.mockExecutionMgr.On("UpdateWorkflowExecution", mock.Anything, mock.Anything).Return(&persistence.UpdateWorkflowExecutionResponse{MutableStateUpdateSessionStats: &persistence.MutableStateUpdateSessionStats{}}, nil).Once() + + // load mutable state such that it already exists in memory when respond decision task is called + // this enables us to set query registry on it + ctx, release, err := s.mockHistoryEngine.executionCache.GetOrCreateWorkflowExecutionForBackground(constants.TestDomainID, we) + s.NoError(err) + loadedMS, err := ctx.LoadWorkflowExecution(context.Background()) + s.NoError(err) + qr := query.NewRegistry() + id1, _ := qr.BufferQuery(&types.WorkflowQuery{}) + id2, _ := qr.BufferQuery(&types.WorkflowQuery{}) + id3, _ := qr.BufferQuery(&types.WorkflowQuery{}) + loadedMS.SetQueryRegistry(qr) + release(nil) + result1 := &types.WorkflowQueryResult{ + ResultType: types.QueryResultTypeAnswered.Ptr(), + Answer: []byte{1, 2, 3}, + } + result2 := &types.WorkflowQueryResult{ + ResultType: types.QueryResultTypeFailed.Ptr(), + ErrorMessage: "error reason", + } + queryResults := map[string]*types.WorkflowQueryResult{ + id1: result1, + id2: result2, + } + _, err = s.mockHistoryEngine.RespondDecisionTaskCompleted(s.constructCallContext(cc.GoWorkerConsistentQueryVersion), &types.HistoryRespondDecisionTaskCompletedRequest{ + DomainUUID: constants.TestDomainID, + CompleteRequest: &types.RespondDecisionTaskCompletedRequest{ + TaskToken: taskToken, + Decisions: decisions, + ExecutionContext: []byte("context"), + Identity: identity, + QueryResults: queryResults, + }, + }) + s.Nil(err) + + executionBuilder := s.getBuilder(constants.TestDomainID, we) + s.Equal(int64(11), executionBuilder.GetExecutionInfo().NextEventID) + s.Equal(int64(8), executionBuilder.GetExecutionInfo().LastProcessedEvent) + s.Equal(persistence.WorkflowStateRunning, executionBuilder.GetExecutionInfo().State) + s.False(executionBuilder.HasPendingDecision()) + s.Len(qr.GetCompletedIDs(), 2) + completed1, err := qr.GetTerminationState(id1) + s.NoError(err) + s.Equal(result1, completed1.QueryResult) + s.Equal(query.TerminationTypeCompleted, completed1.TerminationType) + completed2, err := qr.GetTerminationState(id2) + s.NoError(err) + s.Equal(result2, completed2.QueryResult) + s.Equal(query.TerminationTypeCompleted, completed2.TerminationType) + s.Len(qr.GetBufferedIDs(), 0) + s.Len(qr.GetFailedIDs(), 0) + s.Len(qr.GetUnblockedIDs(), 1) + unblocked1, err := qr.GetTerminationState(id3) + s.NoError(err) + s.Nil(unblocked1.QueryResult) + s.Equal(query.TerminationTypeUnblocked, unblocked1.TerminationType) + + // Try recording activity heartbeat + s.mockExecutionMgr.On("UpdateWorkflowExecution", mock.Anything, mock.Anything).Return(&persistence.UpdateWorkflowExecutionResponse{MutableStateUpdateSessionStats: &persistence.MutableStateUpdateSessionStats{}}, nil).Once() + + activityTaskToken, _ := json.Marshal(&common.TaskToken{ + WorkflowID: "wId", + RunID: we.GetRunID(), + ScheduleID: 5, + }) + + hbResponse, err := s.mockHistoryEngine.RecordActivityTaskHeartbeat(context.Background(), &types.HistoryRecordActivityTaskHeartbeatRequest{ + DomainUUID: constants.TestDomainID, + HeartbeatRequest: &types.RecordActivityTaskHeartbeatRequest{ + TaskToken: activityTaskToken, + Identity: identity, + Details: []byte("details"), + }, + }) + s.Nil(err) + s.NotNil(hbResponse) + s.True(hbResponse.CancelRequested) + + // Try cancelling the request. + s.mockHistoryV2Mgr.On("AppendHistoryNodes", mock.Anything, mock.Anything).Return(&persistence.AppendHistoryNodesResponse{}, nil).Once() + s.mockExecutionMgr.On("UpdateWorkflowExecution", mock.Anything, mock.Anything).Return(&persistence.UpdateWorkflowExecutionResponse{MutableStateUpdateSessionStats: &persistence.MutableStateUpdateSessionStats{}}, nil).Once() + + err = s.mockHistoryEngine.RespondActivityTaskCanceled(context.Background(), &types.HistoryRespondActivityTaskCanceledRequest{ + DomainUUID: constants.TestDomainID, + CancelRequest: &types.RespondActivityTaskCanceledRequest{ + TaskToken: activityTaskToken, + Identity: identity, + Details: []byte("details"), + }, + }) + s.Nil(err) + + executionBuilder = s.getBuilder(constants.TestDomainID, we) + s.Equal(int64(13), executionBuilder.GetExecutionInfo().NextEventID) + s.Equal(int64(8), executionBuilder.GetExecutionInfo().LastProcessedEvent) + s.Equal(persistence.WorkflowStateRunning, executionBuilder.GetExecutionInfo().State) + s.True(executionBuilder.HasPendingDecision()) +} + +func (s *engineSuite) TestRequestCancel_RespondDecisionTaskCompleted_SuccessWithConsistentQueriesUnsupported() { + we := types.WorkflowExecution{ + WorkflowID: "wId", + RunID: constants.TestRunID, + } + tl := "testTaskList" + taskToken, _ := json.Marshal(&common.TaskToken{ + WorkflowID: we.WorkflowID, + RunID: we.RunID, + ScheduleID: 7, + }) + identity := "testIdentity" + activityID := "activity1_id" + activityType := "activity_type1" + activityInput := []byte("input1") + + msBuilder := execution.NewMutableStateBuilderWithEventV2( + s.mockHistoryEngine.shard, + testlogger.New(s.Suite.T()), + we.GetRunID(), + constants.TestLocalDomainEntry, + ) + test.AddWorkflowExecutionStartedEvent(msBuilder, we, "wType", tl, []byte("input"), 100, 100, identity) + di := test.AddDecisionTaskScheduledEvent(msBuilder) + decisionStartedEvent := test.AddDecisionTaskStartedEvent(msBuilder, di.ScheduleID, tl, identity) + decisionCompletedEvent := test.AddDecisionTaskCompletedEvent(msBuilder, di.ScheduleID, + decisionStartedEvent.ID, nil, identity) + activityScheduledEvent, _ := test.AddActivityTaskScheduledEvent(msBuilder, decisionCompletedEvent.ID, activityID, + activityType, tl, activityInput, 100, 10, 1, 1) + test.AddActivityTaskStartedEvent(msBuilder, activityScheduledEvent.ID, identity) + di2 := test.AddDecisionTaskScheduledEvent(msBuilder) + test.AddDecisionTaskStartedEvent(msBuilder, di2.ScheduleID, tl, identity) + + ms := execution.CreatePersistenceMutableState(msBuilder) + gwmsResponse := &persistence.GetWorkflowExecutionResponse{State: ms} + + decisions := []*types.Decision{{ + DecisionType: types.DecisionTypeRequestCancelActivityTask.Ptr(), + RequestCancelActivityTaskDecisionAttributes: &types.RequestCancelActivityTaskDecisionAttributes{ + ActivityID: activityID, + }, + }} + + s.mockExecutionMgr.On("GetWorkflowExecution", mock.Anything, mock.Anything).Return(gwmsResponse, nil).Once() + s.mockHistoryV2Mgr.On("AppendHistoryNodes", mock.Anything, mock.Anything).Return(&persistence.AppendHistoryNodesResponse{}, nil).Once() + s.mockExecutionMgr.On("UpdateWorkflowExecution", mock.Anything, mock.Anything).Return(&persistence.UpdateWorkflowExecutionResponse{MutableStateUpdateSessionStats: &persistence.MutableStateUpdateSessionStats{}}, nil).Once() + + // load mutable state such that it already exists in memory when respond decision task is called + // this enables us to set query registry on it + ctx, release, err := s.mockHistoryEngine.executionCache.GetOrCreateWorkflowExecutionForBackground(constants.TestDomainID, we) + s.NoError(err) + loadedMS, err := ctx.LoadWorkflowExecution(context.Background()) + s.NoError(err) + qr := query.NewRegistry() + qr.BufferQuery(&types.WorkflowQuery{}) + qr.BufferQuery(&types.WorkflowQuery{}) + qr.BufferQuery(&types.WorkflowQuery{}) + loadedMS.SetQueryRegistry(qr) + release(nil) + _, err = s.mockHistoryEngine.RespondDecisionTaskCompleted(s.constructCallContext("0.0.0"), &types.HistoryRespondDecisionTaskCompletedRequest{ + DomainUUID: constants.TestDomainID, + CompleteRequest: &types.RespondDecisionTaskCompletedRequest{ + TaskToken: taskToken, + Decisions: decisions, + ExecutionContext: []byte("context"), + Identity: identity, + }, + }) + s.Nil(err) + + executionBuilder := s.getBuilder(constants.TestDomainID, we) + s.Equal(int64(11), executionBuilder.GetExecutionInfo().NextEventID) + s.Equal(int64(8), executionBuilder.GetExecutionInfo().LastProcessedEvent) + s.Equal(persistence.WorkflowStateRunning, executionBuilder.GetExecutionInfo().State) + s.False(executionBuilder.HasPendingDecision()) + s.Len(qr.GetBufferedIDs(), 0) + s.Len(qr.GetCompletedIDs(), 0) + s.Len(qr.GetUnblockedIDs(), 0) + s.Len(qr.GetFailedIDs(), 3) +} + +func (s *engineSuite) constructCallContext(featureVersion string) context.Context { + ctx := context.Background() + ctx, call := encoding.NewInboundCall(ctx) + err := call.ReadFromRequest(&transport.Request{ + Headers: transport.NewHeaders().With(common.ClientImplHeaderName, cc.GoSDK).With(common.FeatureVersionHeaderName, featureVersion), + }) + s.NoError(err) + return ctx +} + +func (s *engineSuite) TestStarTimer_DuplicateTimerID() { + + we := types.WorkflowExecution{ + WorkflowID: "wId", + RunID: constants.TestRunID, + } + tl := "testTaskList" + taskToken, _ := json.Marshal(&common.TaskToken{ + WorkflowID: we.WorkflowID, + RunID: we.RunID, + ScheduleID: 2, + }) + identity := "testIdentity" + timerID := "t1" + + msBuilder := execution.NewMutableStateBuilderWithEventV2( + s.mockHistoryEngine.shard, + testlogger.New(s.Suite.T()), + we.GetRunID(), + constants.TestLocalDomainEntry, + ) + + test.AddWorkflowExecutionStartedEvent(msBuilder, we, "wType", tl, []byte("input"), 100, 100, identity) + di := test.AddDecisionTaskScheduledEvent(msBuilder) + test.AddDecisionTaskStartedEvent(msBuilder, di.ScheduleID, tl, identity) + + ms := execution.CreatePersistenceMutableState(msBuilder) + gwmsResponse := &persistence.GetWorkflowExecutionResponse{State: ms} + + decisions := []*types.Decision{{ + DecisionType: types.DecisionTypeStartTimer.Ptr(), + StartTimerDecisionAttributes: &types.StartTimerDecisionAttributes{ + TimerID: timerID, + StartToFireTimeoutSeconds: common.Int64Ptr(1), + }, + }} + + s.mockExecutionMgr.On("GetWorkflowExecution", mock.Anything, mock.Anything).Return(gwmsResponse, nil).Once() + s.mockHistoryV2Mgr.On("AppendHistoryNodes", mock.Anything, mock.Anything).Return(&persistence.AppendHistoryNodesResponse{}, nil).Once() + s.mockExecutionMgr.On("UpdateWorkflowExecution", mock.Anything, mock.Anything).Return(&persistence.UpdateWorkflowExecutionResponse{MutableStateUpdateSessionStats: &persistence.MutableStateUpdateSessionStats{}}, nil).Once() + + _, err := s.mockHistoryEngine.RespondDecisionTaskCompleted(context.Background(), &types.HistoryRespondDecisionTaskCompletedRequest{ + DomainUUID: constants.TestDomainID, + CompleteRequest: &types.RespondDecisionTaskCompletedRequest{ + TaskToken: taskToken, + Decisions: decisions, + ExecutionContext: []byte("context"), + Identity: identity, + }, + }) + s.Nil(err) + + executionBuilder := s.getBuilder(constants.TestDomainID, we) + s.Equal(persistence.WorkflowStateRunning, executionBuilder.GetExecutionInfo().State) + + // Try to add the same timer ID again. + di2 := test.AddDecisionTaskScheduledEvent(executionBuilder) + test.AddDecisionTaskStartedEvent(executionBuilder, di2.ScheduleID, tl, identity) + taskToken2, _ := json.Marshal(&common.TaskToken{ + WorkflowID: we.WorkflowID, + RunID: we.RunID, + ScheduleID: di2.ScheduleID, + }) + + ms2 := execution.CreatePersistenceMutableState(executionBuilder) + gwmsResponse2 := &persistence.GetWorkflowExecutionResponse{State: ms2} + + decisionFailedEvent := false + s.mockExecutionMgr.On("GetWorkflowExecution", mock.Anything, mock.Anything).Return(gwmsResponse2, nil).Once() + s.mockHistoryV2Mgr.On("AppendHistoryNodes", mock.Anything, mock.Anything).Return(&persistence.AppendHistoryNodesResponse{}, nil).Run(func(arguments mock.Arguments) { + req := arguments.Get(1).(*persistence.AppendHistoryNodesRequest) + decTaskIndex := len(req.Events) - 1 + if decTaskIndex >= 0 && *req.Events[decTaskIndex].EventType == types.EventTypeDecisionTaskFailed { + decisionFailedEvent = true + } + }).Once() + s.mockExecutionMgr.On("UpdateWorkflowExecution", mock.Anything, mock.Anything).Return(&persistence.UpdateWorkflowExecutionResponse{MutableStateUpdateSessionStats: &persistence.MutableStateUpdateSessionStats{}}, nil).Once() + + _, err = s.mockHistoryEngine.RespondDecisionTaskCompleted(context.Background(), &types.HistoryRespondDecisionTaskCompletedRequest{ + DomainUUID: constants.TestDomainID, + CompleteRequest: &types.RespondDecisionTaskCompletedRequest{ + TaskToken: taskToken2, + Decisions: decisions, + ExecutionContext: []byte("context"), + Identity: identity, + }, + }) + s.Nil(err) + + s.True(decisionFailedEvent) + executionBuilder = s.getBuilder(constants.TestDomainID, we) + s.Equal(persistence.WorkflowStateRunning, executionBuilder.GetExecutionInfo().State) + s.True(executionBuilder.HasPendingDecision()) + di3, ok := executionBuilder.GetDecisionInfo(executionBuilder.GetExecutionInfo().NextEventID) + s.True(ok, "DI.ScheduleID: %v, ScheduleID: %v, StartedID: %v", di2.ScheduleID, + executionBuilder.GetExecutionInfo().DecisionScheduleID, executionBuilder.GetExecutionInfo().DecisionStartedID) + s.Equal(executionBuilder.GetExecutionInfo().NextEventID, di3.ScheduleID) + s.Equal(int64(1), di3.Attempt) +} + +func (s *engineSuite) TestUserTimer_RespondDecisionTaskCompleted() { + + we := types.WorkflowExecution{ + WorkflowID: "wId", + RunID: constants.TestRunID, + } + tl := "testTaskList" + taskToken, _ := json.Marshal(&common.TaskToken{ + WorkflowID: we.WorkflowID, + RunID: we.RunID, + ScheduleID: 6, + }) + identity := "testIdentity" + timerID := "t1" + + msBuilder := execution.NewMutableStateBuilderWithEventV2( + s.mockHistoryEngine.shard, + testlogger.New(s.Suite.T()), + we.GetRunID(), + constants.TestLocalDomainEntry, + ) + // Verify cancel timer with a start event. + test.AddWorkflowExecutionStartedEvent(msBuilder, we, "wType", tl, []byte("input"), 100, 100, identity) + di := test.AddDecisionTaskScheduledEvent(msBuilder) + decisionStartedEvent := test.AddDecisionTaskStartedEvent(msBuilder, di.ScheduleID, tl, identity) + decisionCompletedEvent := test.AddDecisionTaskCompletedEvent(msBuilder, di.ScheduleID, + decisionStartedEvent.ID, nil, identity) + test.AddTimerStartedEvent(msBuilder, decisionCompletedEvent.ID, timerID, 10) + di2 := test.AddDecisionTaskScheduledEvent(msBuilder) + test.AddDecisionTaskStartedEvent(msBuilder, di2.ScheduleID, tl, identity) + + ms := execution.CreatePersistenceMutableState(msBuilder) + gwmsResponse := &persistence.GetWorkflowExecutionResponse{State: ms} + + decisions := []*types.Decision{{ + DecisionType: types.DecisionTypeCancelTimer.Ptr(), + CancelTimerDecisionAttributes: &types.CancelTimerDecisionAttributes{ + TimerID: timerID, + }, + }} + + s.mockExecutionMgr.On("GetWorkflowExecution", mock.Anything, mock.Anything).Return(gwmsResponse, nil).Once() + s.mockHistoryV2Mgr.On("AppendHistoryNodes", mock.Anything, mock.Anything).Return(&persistence.AppendHistoryNodesResponse{}, nil).Once() + s.mockExecutionMgr.On("UpdateWorkflowExecution", mock.Anything, mock.Anything).Return(&persistence.UpdateWorkflowExecutionResponse{MutableStateUpdateSessionStats: &persistence.MutableStateUpdateSessionStats{}}, nil).Once() + + _, err := s.mockHistoryEngine.RespondDecisionTaskCompleted(context.Background(), &types.HistoryRespondDecisionTaskCompletedRequest{ + DomainUUID: constants.TestDomainID, + CompleteRequest: &types.RespondDecisionTaskCompletedRequest{ + TaskToken: taskToken, + Decisions: decisions, + ExecutionContext: []byte("context"), + Identity: identity, + }, + }) + s.Nil(err) + + executionBuilder := s.getBuilder(constants.TestDomainID, we) + s.Equal(int64(10), executionBuilder.GetExecutionInfo().NextEventID) + s.Equal(int64(7), executionBuilder.GetExecutionInfo().LastProcessedEvent) + s.Equal(persistence.WorkflowStateRunning, executionBuilder.GetExecutionInfo().State) + s.False(executionBuilder.HasPendingDecision()) +} + +func (s *engineSuite) TestCancelTimer_RespondDecisionTaskCompleted_NoStartTimer() { + + we := types.WorkflowExecution{ + WorkflowID: "wId", + RunID: constants.TestRunID, + } + tl := "testTaskList" + taskToken, _ := json.Marshal(&common.TaskToken{ + WorkflowID: we.WorkflowID, + RunID: we.RunID, + ScheduleID: 2, + }) + identity := "testIdentity" + timerID := "t1" + + msBuilder := execution.NewMutableStateBuilderWithEventV2( + s.mockHistoryEngine.shard, + testlogger.New(s.Suite.T()), + we.GetRunID(), + constants.TestLocalDomainEntry, + ) + // Verify cancel timer with a start event. + test.AddWorkflowExecutionStartedEvent(msBuilder, we, "wType", tl, []byte("input"), 100, 100, identity) + di := test.AddDecisionTaskScheduledEvent(msBuilder) + test.AddDecisionTaskStartedEvent(msBuilder, di.ScheduleID, tl, identity) + + ms := execution.CreatePersistenceMutableState(msBuilder) + gwmsResponse := &persistence.GetWorkflowExecutionResponse{State: ms} + + decisions := []*types.Decision{{ + DecisionType: types.DecisionTypeCancelTimer.Ptr(), + CancelTimerDecisionAttributes: &types.CancelTimerDecisionAttributes{ + TimerID: timerID, + }, + }} + + s.mockExecutionMgr.On("GetWorkflowExecution", mock.Anything, mock.Anything).Return(gwmsResponse, nil).Once() + s.mockHistoryV2Mgr.On("AppendHistoryNodes", mock.Anything, mock.Anything).Return(&persistence.AppendHistoryNodesResponse{}, nil).Once() + s.mockExecutionMgr.On("UpdateWorkflowExecution", mock.Anything, mock.Anything).Return(&persistence.UpdateWorkflowExecutionResponse{MutableStateUpdateSessionStats: &persistence.MutableStateUpdateSessionStats{}}, nil).Once() + + _, err := s.mockHistoryEngine.RespondDecisionTaskCompleted(context.Background(), &types.HistoryRespondDecisionTaskCompletedRequest{ + DomainUUID: constants.TestDomainID, + CompleteRequest: &types.RespondDecisionTaskCompletedRequest{ + TaskToken: taskToken, + Decisions: decisions, + ExecutionContext: []byte("context"), + Identity: identity, + }, + }) + s.Nil(err) + + executionBuilder := s.getBuilder(constants.TestDomainID, we) + s.Equal(int64(6), executionBuilder.GetExecutionInfo().NextEventID) + s.Equal(int64(3), executionBuilder.GetExecutionInfo().LastProcessedEvent) + s.Equal(persistence.WorkflowStateRunning, executionBuilder.GetExecutionInfo().State) + s.False(executionBuilder.HasPendingDecision()) +} + +func (s *engineSuite) TestCancelTimer_RespondDecisionTaskCompleted_TimerFired() { + + we := types.WorkflowExecution{ + WorkflowID: "wId", + RunID: constants.TestRunID, + } + tl := "testTaskList" + taskToken, _ := json.Marshal(&common.TaskToken{ + WorkflowID: we.WorkflowID, + RunID: we.RunID, + ScheduleID: 6, + }) + identity := "testIdentity" + timerID := "t1" + + msBuilder := execution.NewMutableStateBuilderWithEventV2( + s.mockHistoryEngine.shard, + testlogger.New(s.Suite.T()), + we.GetRunID(), + constants.TestLocalDomainEntry, + ) + // Verify cancel timer with a start event. + test.AddWorkflowExecutionStartedEvent(msBuilder, we, "wType", tl, []byte("input"), 100, 100, identity) + di := test.AddDecisionTaskScheduledEvent(msBuilder) + decisionStartedEvent := test.AddDecisionTaskStartedEvent(msBuilder, di.ScheduleID, tl, identity) + decisionCompletedEvent := test.AddDecisionTaskCompletedEvent(msBuilder, di.ScheduleID, + decisionStartedEvent.ID, nil, identity) + test.AddTimerStartedEvent(msBuilder, decisionCompletedEvent.ID, timerID, 10) + di2 := test.AddDecisionTaskScheduledEvent(msBuilder) + test.AddDecisionTaskStartedEvent(msBuilder, di2.ScheduleID, tl, identity) + test.AddTimerFiredEvent(msBuilder, timerID) + _, _, err := msBuilder.CloseTransactionAsMutation(time.Now(), execution.TransactionPolicyActive) + s.Nil(err) + + ms := execution.CreatePersistenceMutableState(msBuilder) + gwmsResponse := &persistence.GetWorkflowExecutionResponse{State: ms} + s.True(len(gwmsResponse.State.BufferedEvents) > 0) + + decisions := []*types.Decision{{ + DecisionType: types.DecisionTypeCancelTimer.Ptr(), + CancelTimerDecisionAttributes: &types.CancelTimerDecisionAttributes{ + TimerID: timerID, + }, + }} + + s.mockExecutionMgr.On("GetWorkflowExecution", mock.Anything, mock.Anything).Return(gwmsResponse, nil).Once() + s.mockHistoryV2Mgr.On("AppendHistoryNodes", mock.Anything, mock.Anything).Return(&persistence.AppendHistoryNodesResponse{}, nil).Once() + s.mockExecutionMgr.On("UpdateWorkflowExecution", mock.Anything, mock.MatchedBy(func(input *persistence.UpdateWorkflowExecutionRequest) bool { + // need to check whether the buffered events are cleared + s.True(input.UpdateWorkflowMutation.ClearBufferedEvents) + return true + })).Return(&persistence.UpdateWorkflowExecutionResponse{MutableStateUpdateSessionStats: &persistence.MutableStateUpdateSessionStats{}}, nil).Once() + + _, err = s.mockHistoryEngine.RespondDecisionTaskCompleted(context.Background(), &types.HistoryRespondDecisionTaskCompletedRequest{ + DomainUUID: constants.TestDomainID, + CompleteRequest: &types.RespondDecisionTaskCompletedRequest{ + TaskToken: taskToken, + Decisions: decisions, + ExecutionContext: []byte("context"), + Identity: identity, + }, + }) + s.Nil(err) + + executionBuilder := s.getBuilder(constants.TestDomainID, we) + s.Equal(int64(10), executionBuilder.GetExecutionInfo().NextEventID) + s.Equal(int64(7), executionBuilder.GetExecutionInfo().LastProcessedEvent) + s.Equal(persistence.WorkflowStateRunning, executionBuilder.GetExecutionInfo().State) + s.False(executionBuilder.HasPendingDecision()) + s.False(executionBuilder.HasBufferedEvents()) +} + +func (s *engineSuite) TestSignalWorkflowExecution_InvalidRequest() { + signalRequest := &types.HistorySignalWorkflowExecutionRequest{} + err := s.mockHistoryEngine.SignalWorkflowExecution(context.Background(), signalRequest) + s.Error(err) +} + +func (s *engineSuite) TestSignalWorkflowExecution() { + we := types.WorkflowExecution{ + WorkflowID: constants.TestWorkflowID, + RunID: constants.TestRunID, + } + tasklist := "testTaskList" + identity := "testIdentity" + signalName := "my signal name" + input := []byte("test input") + signalRequest := &types.HistorySignalWorkflowExecutionRequest{ + DomainUUID: constants.TestDomainID, + SignalRequest: &types.SignalWorkflowExecutionRequest{ + Domain: constants.TestDomainID, + WorkflowExecution: &we, + Identity: identity, + SignalName: signalName, + Input: input, + }, + } + + msBuilder := execution.NewMutableStateBuilderWithEventV2( + s.mockHistoryEngine.shard, + testlogger.New(s.Suite.T()), + we.GetRunID(), + constants.TestLocalDomainEntry, + ) + test.AddWorkflowExecutionStartedEvent(msBuilder, we, "wType", tasklist, []byte("input"), 100, 200, identity) + test.AddDecisionTaskScheduledEvent(msBuilder) + ms := execution.CreatePersistenceMutableState(msBuilder) + ms.ExecutionInfo.DomainID = constants.TestDomainID + gwmsResponse := &persistence.GetWorkflowExecutionResponse{State: ms} + + s.mockExecutionMgr.On("GetWorkflowExecution", mock.Anything, mock.Anything).Return(gwmsResponse, nil).Once() + s.mockHistoryV2Mgr.On("AppendHistoryNodes", mock.Anything, mock.Anything).Return(&persistence.AppendHistoryNodesResponse{}, nil).Once() + s.mockExecutionMgr.On("UpdateWorkflowExecution", mock.Anything, mock.Anything).Return(&persistence.UpdateWorkflowExecutionResponse{MutableStateUpdateSessionStats: &persistence.MutableStateUpdateSessionStats{}}, nil).Once() + + err := s.mockHistoryEngine.SignalWorkflowExecution(context.Background(), signalRequest) + s.Nil(err) +} + +// Test signal decision by adding request ID +func (s *engineSuite) TestSignalWorkflowExecution_DuplicateRequest_WorkflowOpen() { + we := types.WorkflowExecution{ + WorkflowID: constants.TestWorkflowID, + RunID: constants.TestRunID, + } + tasklist := "testTaskList" + identity := "testIdentity" + signalName := "my signal name 2" + input := []byte("test input 2") + requestID := uuid.New() + signalRequest := &types.HistorySignalWorkflowExecutionRequest{ + DomainUUID: constants.TestDomainID, + SignalRequest: &types.SignalWorkflowExecutionRequest{ + Domain: constants.TestDomainID, + WorkflowExecution: &we, + Identity: identity, + SignalName: signalName, + Input: input, + RequestID: requestID, + }, + } + + msBuilder := execution.NewMutableStateBuilderWithEventV2( + s.mockHistoryEngine.shard, + testlogger.New(s.Suite.T()), + we.GetRunID(), + constants.TestLocalDomainEntry, + ) + test.AddWorkflowExecutionStartedEvent(msBuilder, we, "wType", tasklist, []byte("input"), 100, 200, identity) + test.AddDecisionTaskScheduledEvent(msBuilder) + ms := execution.CreatePersistenceMutableState(msBuilder) + // assume duplicate request id + ms.SignalRequestedIDs = make(map[string]struct{}) + ms.SignalRequestedIDs[requestID] = struct{}{} + ms.ExecutionInfo.DomainID = constants.TestDomainID + gwmsResponse := &persistence.GetWorkflowExecutionResponse{State: ms} + + s.mockExecutionMgr.On("GetWorkflowExecution", mock.Anything, mock.Anything).Return(gwmsResponse, nil).Once() + + err := s.mockHistoryEngine.SignalWorkflowExecution(context.Background(), signalRequest) + s.Nil(err) +} + +func (s *engineSuite) TestSignalWorkflowExecution_DuplicateRequest_WorkflowCompleted() { + we := types.WorkflowExecution{ + WorkflowID: constants.TestWorkflowID, + RunID: constants.TestRunID, + } + tasklist := "testTaskList" + identity := "testIdentity" + signalName := "my signal name 2" + input := []byte("test input 2") + requestID := uuid.New() + signalRequest := &types.HistorySignalWorkflowExecutionRequest{ + DomainUUID: constants.TestDomainID, + SignalRequest: &types.SignalWorkflowExecutionRequest{ + Domain: constants.TestDomainID, + WorkflowExecution: &we, + Identity: identity, + SignalName: signalName, + Input: input, + RequestID: requestID, + }, + } + + msBuilder := execution.NewMutableStateBuilderWithEventV2( + s.mockHistoryEngine.shard, + testlogger.New(s.Suite.T()), + we.GetRunID(), + constants.TestLocalDomainEntry, + ) + test.AddWorkflowExecutionStartedEvent(msBuilder, we, "wType", tasklist, []byte("input"), 100, 200, identity) + test.AddDecisionTaskScheduledEvent(msBuilder) + ms := execution.CreatePersistenceMutableState(msBuilder) + // assume duplicate request id + ms.SignalRequestedIDs = make(map[string]struct{}) + ms.SignalRequestedIDs[requestID] = struct{}{} + ms.ExecutionInfo.DomainID = constants.TestDomainID + ms.ExecutionInfo.State = persistence.WorkflowStateCompleted + gwmsResponse := &persistence.GetWorkflowExecutionResponse{State: ms} + + s.mockExecutionMgr.On("GetWorkflowExecution", mock.Anything, mock.Anything).Return(gwmsResponse, nil).Once() + + err := s.mockHistoryEngine.SignalWorkflowExecution(context.Background(), signalRequest) + s.Nil(err) +} + +func (s *engineSuite) TestSignalWorkflowExecution_WorkflowCompleted() { + we := &types.WorkflowExecution{ + WorkflowID: constants.TestWorkflowID, + RunID: constants.TestRunID, + } + tasklist := "testTaskList" + identity := "testIdentity" + signalName := "my signal name" + input := []byte("test input") + signalRequest := &types.HistorySignalWorkflowExecutionRequest{ + DomainUUID: constants.TestDomainID, + SignalRequest: &types.SignalWorkflowExecutionRequest{ + Domain: constants.TestDomainID, + WorkflowExecution: we, + Identity: identity, + SignalName: signalName, + Input: input, + }, + } + + msBuilder := execution.NewMutableStateBuilderWithEventV2( + s.mockHistoryEngine.shard, + testlogger.New(s.Suite.T()), + we.GetRunID(), + constants.TestLocalDomainEntry, + ) + test.AddWorkflowExecutionStartedEvent(msBuilder, *we, "wType", tasklist, []byte("input"), 100, 200, identity) + test.AddDecisionTaskScheduledEvent(msBuilder) + ms := execution.CreatePersistenceMutableState(msBuilder) + ms.ExecutionInfo.State = persistence.WorkflowStateCompleted + gwmsResponse := &persistence.GetWorkflowExecutionResponse{State: ms} + + s.mockExecutionMgr.On("GetWorkflowExecution", mock.Anything, mock.Anything).Return(gwmsResponse, nil).Once() + + err := s.mockHistoryEngine.SignalWorkflowExecution(context.Background(), signalRequest) + s.EqualError(err, "workflow execution already completed") +} + +func (s *engineSuite) TestRemoveSignalMutableState() { + removeRequest := &types.RemoveSignalMutableStateRequest{} + err := s.mockHistoryEngine.RemoveSignalMutableState(context.Background(), removeRequest) + s.Error(err) + + workflowExecution := types.WorkflowExecution{ + WorkflowID: "wId", + RunID: constants.TestRunID, + } + tasklist := "testTaskList" + identity := "testIdentity" + requestID := uuid.New() + removeRequest = &types.RemoveSignalMutableStateRequest{ + DomainUUID: constants.TestDomainID, + WorkflowExecution: &workflowExecution, + RequestID: requestID, + } + + msBuilder := execution.NewMutableStateBuilderWithEventV2( + s.mockHistoryEngine.shard, + testlogger.New(s.Suite.T()), + constants.TestRunID, + constants.TestLocalDomainEntry, + ) + test.AddWorkflowExecutionStartedEvent(msBuilder, workflowExecution, "wType", tasklist, []byte("input"), 100, 200, identity) + test.AddDecisionTaskScheduledEvent(msBuilder) + ms := execution.CreatePersistenceMutableState(msBuilder) + ms.ExecutionInfo.DomainID = constants.TestDomainID + gwmsResponse := &persistence.GetWorkflowExecutionResponse{State: ms} + + s.mockExecutionMgr.On("GetWorkflowExecution", mock.Anything, mock.Anything).Return(gwmsResponse, nil).Once() + s.mockExecutionMgr.On("UpdateWorkflowExecution", mock.Anything, mock.Anything).Return(&persistence.UpdateWorkflowExecutionResponse{MutableStateUpdateSessionStats: &persistence.MutableStateUpdateSessionStats{}}, nil).Once() + + err = s.mockHistoryEngine.RemoveSignalMutableState(context.Background(), removeRequest) + s.Nil(err) +} + +func (s *engineSuite) TestReapplyEvents_ReturnSuccess() { + workflowExecution := types.WorkflowExecution{ + WorkflowID: "test-reapply", + RunID: constants.TestRunID, + } + history := []*types.HistoryEvent{ + { + ID: 1, + EventType: types.EventTypeWorkflowExecutionSignaled.Ptr(), + Version: 1, + }, + } + msBuilder := execution.NewMutableStateBuilderWithEventV2( + s.mockHistoryEngine.shard, + testlogger.New(s.Suite.T()), + workflowExecution.GetRunID(), + constants.TestLocalDomainEntry, + ) + ms := execution.CreatePersistenceMutableState(msBuilder) + gwmsResponse := &persistence.GetWorkflowExecutionResponse{State: ms} + gceResponse := &persistence.GetCurrentExecutionResponse{RunID: constants.TestRunID} + s.mockExecutionMgr.On("GetCurrentExecution", mock.Anything, mock.Anything).Return(gceResponse, nil).Once() + s.mockExecutionMgr.On("GetWorkflowExecution", mock.Anything, mock.Anything).Return(gwmsResponse, nil).Once() + s.mockEventsReapplier.EXPECT().ReapplyEvents(gomock.Any(), gomock.Any(), gomock.Any(), gomock.Any()).Times(1) + + err := s.mockHistoryEngine.ReapplyEvents( + context.Background(), + constants.TestDomainID, + workflowExecution.WorkflowID, + workflowExecution.RunID, + history, + ) + s.NoError(err) +} + +func (s *engineSuite) TestReapplyEvents_IgnoreSameVersionEvents() { + workflowExecution := types.WorkflowExecution{ + WorkflowID: "test-reapply-same-version", + RunID: constants.TestRunID, + } + history := []*types.HistoryEvent{ + { + ID: 1, + EventType: types.EventTypeTimerStarted.Ptr(), + Version: common.EmptyVersion, + }, + } + msBuilder := execution.NewMutableStateBuilderWithEventV2( + s.mockHistoryEngine.shard, + testlogger.New(s.Suite.T()), + workflowExecution.GetRunID(), + constants.TestLocalDomainEntry, + ) + + ms := execution.CreatePersistenceMutableState(msBuilder) + gwmsResponse := &persistence.GetWorkflowExecutionResponse{State: ms} + gceResponse := &persistence.GetCurrentExecutionResponse{RunID: constants.TestRunID} + s.mockExecutionMgr.On("GetCurrentExecution", mock.Anything, mock.Anything).Return(gceResponse, nil).Once() + s.mockExecutionMgr.On("GetWorkflowExecution", mock.Anything, mock.Anything).Return(gwmsResponse, nil).Once() + s.mockEventsReapplier.EXPECT().ReapplyEvents(gomock.Any(), gomock.Any(), gomock.Any(), gomock.Any()).Times(0) + + err := s.mockHistoryEngine.ReapplyEvents( + context.Background(), + constants.TestDomainID, + workflowExecution.WorkflowID, + workflowExecution.RunID, + history, + ) + s.NoError(err) +} + +func (s *engineSuite) TestReapplyEvents_ResetWorkflow() { + workflowExecution := types.WorkflowExecution{ + WorkflowID: "test-reapply-reset-workflow", + RunID: constants.TestRunID, + } + history := []*types.HistoryEvent{ + { + ID: 1, + EventType: types.EventTypeWorkflowExecutionSignaled.Ptr(), + Version: 100, + }, + } + msBuilder := execution.NewMutableStateBuilderWithEventV2( + s.mockHistoryEngine.shard, + testlogger.New(s.Suite.T()), + workflowExecution.GetRunID(), + constants.TestLocalDomainEntry, + ) + ms := execution.CreatePersistenceMutableState(msBuilder) + ms.ExecutionInfo.State = persistence.WorkflowStateCompleted + ms.ExecutionInfo.LastProcessedEvent = 1 + token, err := msBuilder.GetCurrentBranchToken() + s.NoError(err) + item := persistence.NewVersionHistoryItem(1, 1) + versionHistory := persistence.NewVersionHistory(token, []*persistence.VersionHistoryItem{item}) + ms.VersionHistories = persistence.NewVersionHistories(versionHistory) + gwmsResponse := &persistence.GetWorkflowExecutionResponse{State: ms} + gceResponse := &persistence.GetCurrentExecutionResponse{RunID: constants.TestRunID} + s.mockExecutionMgr.On("GetCurrentExecution", mock.Anything, mock.Anything).Return(gceResponse, nil).Once() + s.mockExecutionMgr.On("GetWorkflowExecution", mock.Anything, mock.Anything).Return(gwmsResponse, nil).Once() + s.mockEventsReapplier.EXPECT().ReapplyEvents(gomock.Any(), gomock.Any(), gomock.Any(), gomock.Any()).Times(0) + s.mockWorkflowResetter.EXPECT().ResetWorkflow(gomock.Any(), gomock.Any(), gomock.Any(), gomock.Any(), gomock.Any(), + gomock.Any(), gomock.Any(), gomock.Any(), gomock.Any(), gomock.Any(), gomock.Any(), gomock.Any(), gomock.Any(), + gomock.Any(), + ).Return(nil).Times(1) + err = s.mockHistoryEngine.ReapplyEvents( + context.Background(), + constants.TestDomainID, + workflowExecution.WorkflowID, + workflowExecution.RunID, + history, + ) + s.NoError(err) +} + +func (s *engineSuite) getBuilder(testDomainID string, we types.WorkflowExecution) execution.MutableState { + context, release, err := s.mockHistoryEngine.executionCache.GetOrCreateWorkflowExecutionForBackground(testDomainID, we) + if err != nil { + return nil + } + defer release(nil) + + return context.GetWorkflowExecution() +} + +func (s *engineSuite) getActivityScheduledEvent( + msBuilder execution.MutableState, + scheduleID int64, +) *types.HistoryEvent { + event, _ := msBuilder.GetActivityScheduledEvent(context.Background(), scheduleID) + return event +} + +func (s *engineSuite) printHistory(builder execution.MutableState) string { + return thrift.FromHistory(builder.GetHistoryBuilder().GetHistory()).String() +} + +func TestRecordChildExecutionCompleted(t *testing.T) { + testCases := []struct { + name string + request *types.RecordChildExecutionCompletedRequest + mockSetup func(*execution.MockMutableState) + wantErr bool + assertErr func(t *testing.T, err error) + }{ + { + name: "workflow not running", + request: &types.RecordChildExecutionCompletedRequest{ + DomainUUID: "58f7998e-9c00-4827-bbd3-6a891b3ca0ca", + InitiatedID: 1, + WorkflowExecution: &types.WorkflowExecution{ + WorkflowID: "wid", + RunID: "4353ddce-ca34-4c78-9785-dc0b83af4bbc", + }, + CompletedExecution: &types.WorkflowExecution{ + WorkflowID: "wid1", + RunID: "312b2440-2859-4e50-a59f-d92a300a072d", + }, + }, + mockSetup: func(ms *execution.MockMutableState) { + ms.EXPECT().IsWorkflowExecutionRunning().Return(false) + }, + wantErr: true, + assertErr: func(t *testing.T, err error) { + assert.Equal(t, workflow.ErrNotExists, err) + }, + }, + { + name: "stale mutable state - not containing initiated event", + request: &types.RecordChildExecutionCompletedRequest{ + DomainUUID: "58f7998e-9c00-4827-bbd3-6a891b3ca0ca", + InitiatedID: 10, + WorkflowExecution: &types.WorkflowExecution{ + WorkflowID: "wid", + RunID: "4353ddce-ca34-4c78-9785-dc0b83af4bbc", + }, + CompletedExecution: &types.WorkflowExecution{ + WorkflowID: "wid1", + RunID: "312b2440-2859-4e50-a59f-d92a300a072d", + }, + }, + mockSetup: func(ms *execution.MockMutableState) { + ms.EXPECT().IsWorkflowExecutionRunning().Return(true) + ms.EXPECT().GetChildExecutionInfo(int64(10)).Return(nil, false) + ms.EXPECT().GetNextEventID().Return(int64(10)).Times(2) + }, + wantErr: true, + assertErr: func(t *testing.T, err error) { + assert.Equal(t, workflow.ErrStaleState, err) + }, + }, + { + name: "pending child execution not found", + request: &types.RecordChildExecutionCompletedRequest{ + DomainUUID: "58f7998e-9c00-4827-bbd3-6a891b3ca0ca", + InitiatedID: 10, + WorkflowExecution: &types.WorkflowExecution{ + WorkflowID: "wid", + RunID: "4353ddce-ca34-4c78-9785-dc0b83af4bbc", + }, + CompletedExecution: &types.WorkflowExecution{ + WorkflowID: "wid1", + RunID: "312b2440-2859-4e50-a59f-d92a300a072d", + }, + }, + mockSetup: func(ms *execution.MockMutableState) { + ms.EXPECT().IsWorkflowExecutionRunning().Return(true) + ms.EXPECT().GetChildExecutionInfo(int64(10)).Return(nil, false) + ms.EXPECT().GetNextEventID().Return(int64(11)).Times(1) + }, + wantErr: true, + assertErr: func(t *testing.T, err error) { + assert.Equal(t, &types.EntityNotExistsError{Message: "Pending child execution not found."}, err) + }, + }, + { + name: "stale mutable state - not containing started event", + request: &types.RecordChildExecutionCompletedRequest{ + DomainUUID: "58f7998e-9c00-4827-bbd3-6a891b3ca0ca", + InitiatedID: 10, + WorkflowExecution: &types.WorkflowExecution{ + WorkflowID: "wid", + RunID: "4353ddce-ca34-4c78-9785-dc0b83af4bbc", + }, + CompletedExecution: &types.WorkflowExecution{ + WorkflowID: "wid1", + RunID: "312b2440-2859-4e50-a59f-d92a300a072d", + }, + StartedID: 11, + }, + mockSetup: func(ms *execution.MockMutableState) { + ms.EXPECT().IsWorkflowExecutionRunning().Return(true) + ms.EXPECT().GetChildExecutionInfo(int64(10)).Return(&persistence.ChildExecutionInfo{StartedID: common.EmptyEventID}, true) + ms.EXPECT().GetNextEventID().Return(int64(11)).Times(2) + }, + wantErr: true, + assertErr: func(t *testing.T, err error) { + assert.Equal(t, workflow.ErrStaleState, err) + }, + }, + { + name: "pending child execution not started", + request: &types.RecordChildExecutionCompletedRequest{ + DomainUUID: "58f7998e-9c00-4827-bbd3-6a891b3ca0ca", + InitiatedID: 10, + WorkflowExecution: &types.WorkflowExecution{ + WorkflowID: "wid", + RunID: "4353ddce-ca34-4c78-9785-dc0b83af4bbc", + }, + CompletedExecution: &types.WorkflowExecution{ + WorkflowID: "wid1", + RunID: "312b2440-2859-4e50-a59f-d92a300a072d", + }, + StartedID: 11, + }, + mockSetup: func(ms *execution.MockMutableState) { + ms.EXPECT().IsWorkflowExecutionRunning().Return(true) + ms.EXPECT().GetChildExecutionInfo(int64(10)).Return(&persistence.ChildExecutionInfo{StartedID: common.EmptyEventID}, true) + ms.EXPECT().GetNextEventID().Return(int64(12)).Times(1) + }, + wantErr: true, + assertErr: func(t *testing.T, err error) { + assert.Equal(t, &types.EntityNotExistsError{Message: "Pending child execution not started."}, err) + }, + }, + { + name: "pending child execution workflowID mismatch", + request: &types.RecordChildExecutionCompletedRequest{ + DomainUUID: "58f7998e-9c00-4827-bbd3-6a891b3ca0ca", + InitiatedID: 10, + WorkflowExecution: &types.WorkflowExecution{ + WorkflowID: "wid", + RunID: "4353ddce-ca34-4c78-9785-dc0b83af4bbc", + }, + CompletedExecution: &types.WorkflowExecution{ + WorkflowID: "wid1", + RunID: "312b2440-2859-4e50-a59f-d92a300a072d", + }, + StartedID: 11, + }, + mockSetup: func(ms *execution.MockMutableState) { + ms.EXPECT().IsWorkflowExecutionRunning().Return(true) + ms.EXPECT().GetChildExecutionInfo(int64(10)).Return(&persistence.ChildExecutionInfo{StartedID: 11, StartedWorkflowID: "wid0"}, true) + }, + wantErr: true, + assertErr: func(t *testing.T, err error) { + assert.Equal(t, &types.EntityNotExistsError{Message: "Pending child execution workflowID mismatch."}, err) + }, + }, + { + name: "success - child workflow completed", + request: &types.RecordChildExecutionCompletedRequest{ + DomainUUID: "58f7998e-9c00-4827-bbd3-6a891b3ca0ca", + InitiatedID: 10, + WorkflowExecution: &types.WorkflowExecution{ + WorkflowID: "wid", + RunID: "4353ddce-ca34-4c78-9785-dc0b83af4bbc", + }, + CompletedExecution: &types.WorkflowExecution{ + WorkflowID: "wid1", + RunID: "312b2440-2859-4e50-a59f-d92a300a072d", + }, + CompletionEvent: &types.HistoryEvent{ + EventType: types.EventTypeWorkflowExecutionCompleted.Ptr(), + WorkflowExecutionCompletedEventAttributes: &types.WorkflowExecutionCompletedEventAttributes{ + Result: []byte("success"), + }, + }, + StartedID: 11, + }, + mockSetup: func(ms *execution.MockMutableState) { + ms.EXPECT().IsWorkflowExecutionRunning().Return(true) + ms.EXPECT().GetChildExecutionInfo(int64(10)).Return(&persistence.ChildExecutionInfo{StartedID: 11, StartedWorkflowID: "wid1"}, true) + ms.EXPECT().AddChildWorkflowExecutionCompletedEvent(int64(10), gomock.Any(), gomock.Any()).Return(nil, nil) + }, + wantErr: false, + }, + } + + for _, tc := range testCases { + t.Run(tc.name, func(t *testing.T) { + ctrl := gomock.NewController(t) + mockShard := shard.NewTestContext(t, ctrl, &persistence.ShardInfo{}, config.NewForTest()) + mockDomainCache := mockShard.Resource.DomainCache + testDomainEntry := cache.NewLocalDomainCacheEntryForTest( + &persistence.DomainInfo{ID: constants.TestDomainID}, &persistence.DomainConfig{}, "", + ) + mockDomainCache.EXPECT().GetDomainByID(gomock.Any()).Return(testDomainEntry, nil).AnyTimes() + mockDomainCache.EXPECT().GetDomainName(gomock.Any()).Return(constants.TestDomainID, nil).AnyTimes() + ms := execution.NewMockMutableState(ctrl) + tc.mockSetup(ms) + + historyEngine := &historyEngineImpl{ + shard: mockShard, + clusterMetadata: mockShard.GetClusterMetadata(), + timeSource: mockShard.GetTimeSource(), + metricsClient: metrics.NewClient(tally.NoopScope, metrics.History), + logger: mockShard.GetLogger(), + updateWithActionFn: func(_ context.Context, _ *execution.Cache, _ string, _ types.WorkflowExecution, _ bool, _ time.Time, actionFn func(wfContext execution.Context, mutableState execution.MutableState) error) error { + return actionFn(nil, ms) + }, + } - eft.Engine.Start() - eft.Engine.Stop() + err := historyEngine.RecordChildExecutionCompleted(context.Background(), tc.request) + if tc.wantErr { + tc.assertErr(t, err) + } else { + assert.NoError(t, err) + } + }) + } } From a640d040f8253853741a43566da41407341e69a5 Mon Sep 17 00:00:00 2001 From: taylan isikdemir Date: Wed, 8 May 2024 10:52:11 -0700 Subject: [PATCH 3/4] address feedback --- service/history/engine/testdata/engine_for_tests.go | 1 + 1 file changed, 1 insertion(+) diff --git a/service/history/engine/testdata/engine_for_tests.go b/service/history/engine/testdata/engine_for_tests.go index 5bd1a1f67c0..9000af027ea 100644 --- a/service/history/engine/testdata/engine_for_tests.go +++ b/service/history/engine/testdata/engine_for_tests.go @@ -50,6 +50,7 @@ type EngineForTest struct { // Add mocks or other fields here } +// NewEngineFn is defined as an alias for engineimpl.NewEngineWithShardContext to avoid circular dependency type NewEngineFn func( shard shard.Context, visibilityMgr persistence.VisibilityManager, From 7f86ea2de4cb128a8116954e7f0ad56ccd825f19 Mon Sep 17 00:00:00 2001 From: taylan isikdemir Date: Wed, 8 May 2024 12:36:44 -0700 Subject: [PATCH 4/4] add factory tests --- service/history/queue/factory_test.go | 136 ++++++++++++++++++ .../queue/timer_queue_processor_base_test.go | 5 +- .../queue/transfer_queue_processor_test.go | 5 +- 3 files changed, 144 insertions(+), 2 deletions(-) create mode 100644 service/history/queue/factory_test.go diff --git a/service/history/queue/factory_test.go b/service/history/queue/factory_test.go new file mode 100644 index 00000000000..3dfd068ba90 --- /dev/null +++ b/service/history/queue/factory_test.go @@ -0,0 +1,136 @@ +// Copyright (c) 2017-2020 Uber Technologies Inc. + +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: + +// The above copyright notice and this permission notice shall be included in all +// copies or substantial portions of the Software. + +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +// SOFTWARE. + +package queue + +import ( + "testing" + + "github.com/golang/mock/gomock" + "go.uber.org/goleak" + + "github.com/uber/cadence/common/persistence" + "github.com/uber/cadence/common/reconciliation/invariant" + "github.com/uber/cadence/service/history/config" + "github.com/uber/cadence/service/history/execution" + "github.com/uber/cadence/service/history/reset" + "github.com/uber/cadence/service/history/shard" + "github.com/uber/cadence/service/history/task" + "github.com/uber/cadence/service/history/workflowcache" + "github.com/uber/cadence/service/worker/archiver" +) + +func TestNewTransferQueueProcessor(t *testing.T) { + defer goleak.VerifyNone(t) + ctrl := gomock.NewController(t) + mockShard := shard.NewTestContext( + t, ctrl, &persistence.ShardInfo{ + ShardID: 10, + RangeID: 1, + TransferAckLevel: 0, + }, + config.NewForTest()) + defer mockShard.Finish(t) + + mockProcessor := task.NewMockProcessor(ctrl) + mockResetter := reset.NewMockWorkflowResetter(ctrl) + mockArchiver := &archiver.ClientMock{} + mockInvariant := invariant.NewMockInvariant(ctrl) + mockWorkflowCache := workflowcache.NewMockWFCache(ctrl) + ratelimit := func(domain string) bool { return false } + + f := NewProcessorFactory() + processor := f.NewTransferQueueProcessor( + mockShard, + mockShard.GetEngine(), + mockProcessor, + execution.NewCache(mockShard), + mockResetter, + mockArchiver, + mockInvariant, + mockWorkflowCache, + ratelimit) + + if processor == nil { + t.Error("NewTransferQueueProcessor returned nil") + } +} + +func TestNewTimerQueueProcessor(t *testing.T) { + defer goleak.VerifyNone(t, + // TODO(CDNC-8881): TimerGate should not start background goroutine in constructor. Make it start/stoppable + goleak.IgnoreTopFunction("github.com/uber/cadence/service/history/queue.NewLocalTimerGate.func1"), + ) + ctrl := gomock.NewController(t) + mockShard := shard.NewTestContext( + t, ctrl, &persistence.ShardInfo{ + ShardID: 10, + RangeID: 1, + TransferAckLevel: 0, + }, + config.NewForTest()) + defer mockShard.Finish(t) + + mockProcessor := task.NewMockProcessor(ctrl) + mockArchiver := &archiver.ClientMock{} + mockInvariant := invariant.NewMockInvariant(ctrl) + + f := NewProcessorFactory() + processor := f.NewTimerQueueProcessor( + mockShard, + mockShard.GetEngine(), + mockProcessor, + execution.NewCache(mockShard), + mockArchiver, + mockInvariant) + + if processor == nil { + t.Error("NewTimerQueueProcessor returned nil") + } +} + +func TestNewCrossClusterQueueProcessor(t *testing.T) { + defer goleak.VerifyNone(t, + // TODO(CDNC-8881): TimerGate should not start background goroutine in constructor. Make it start/stoppable + goleak.IgnoreTopFunction("github.com/uber/cadence/service/history/queue.NewLocalTimerGate.func1"), + ) + ctrl := gomock.NewController(t) + mockShard := shard.NewTestContext( + t, ctrl, &persistence.ShardInfo{ + ShardID: 10, + RangeID: 1, + TransferAckLevel: 0, + }, + config.NewForTest()) + defer mockShard.Finish(t) + + mockProcessor := task.NewMockProcessor(ctrl) + + f := NewProcessorFactory() + processor := f.NewCrossClusterQueueProcessor( + mockShard, + mockShard.GetEngine(), + execution.NewCache(mockShard), + mockProcessor) + + if processor == nil { + t.Error("NewCrossClusterQueueProcessor returned nil") + } +} diff --git a/service/history/queue/timer_queue_processor_base_test.go b/service/history/queue/timer_queue_processor_base_test.go index 0ec893dc5f2..22f9dacf5ee 100644 --- a/service/history/queue/timer_queue_processor_base_test.go +++ b/service/history/queue/timer_queue_processor_base_test.go @@ -94,7 +94,10 @@ func (s *timerQueueProcessorBaseSuite) SetupTest() { func (s *timerQueueProcessorBaseSuite) TearDownTest() { s.controller.Finish() s.mockShard.Finish(s.T()) - goleak.VerifyNone(s.T()) + defer goleak.VerifyNone(s.T(), + // TODO(CDNC-8881): TimerGate should not start background goroutine in constructor. Make it start/stoppable + goleak.IgnoreTopFunction("github.com/uber/cadence/service/history/queue.NewLocalTimerGate.func1"), + ) } func (s *timerQueueProcessorBaseSuite) TestIsProcessNow() { diff --git a/service/history/queue/transfer_queue_processor_test.go b/service/history/queue/transfer_queue_processor_test.go index 7dada053e44..388c0d34a90 100644 --- a/service/history/queue/transfer_queue_processor_test.go +++ b/service/history/queue/transfer_queue_processor_test.go @@ -41,7 +41,10 @@ import ( func TestTransferQueueProcessor_RequireStartStop(t *testing.T) { // some goroutine leak not from this test - defer goleak.VerifyNone(t) + defer goleak.VerifyNone(t, + // TODO(CDNC-8881): TimerGate should not start background goroutine in constructor. Make it start/stoppable + goleak.IgnoreTopFunction("github.com/uber/cadence/service/history/queue.NewLocalTimerGate.func1"), + ) ctrl := gomock.NewController(t) mockShard := shard.NewTestContext( t, ctrl, &persistence.ShardInfo{