func NewTestListener(t TestConfig) *TestListener { if t.DefaultWaitTimeout == 0 { t.DefaultWaitTimeout = 10 } tl := &TestListener{ decisionOutcomes: make(chan DecisionOutcome, 1000), historyInterest: make(map[string]chan *swf.HistoryEvent, 1000), decisionInterest: make(map[string]chan *swf.Decision, 1000), stateInterest: make(map[string]chan string, 1000), dataInterest: make(map[string]chan *StateData, 1000), DefaultWait: time.Duration(t.DefaultWaitTimeout) * time.Second, TestID: strings.Join([]string{t.Testing.TestName(), uuid.New()}, "-"), testAdapter: t.Testing, dataType: t.FSM.DataType, serializer: t.FSM.Serializer, } t.FSM.ReplicationHandler = TestReplicator(tl.decisionOutcomes) t.FSM.DecisionInterceptor = fsm.NewComposedDecisionInterceptor( t.FSM.DecisionInterceptor, TestDecisionInterceptor(tl.TestID, t.StubbedWorkflows, t.ShortStubbedWorkflows), ) t.FSM.TaskList = tl.TestFsmTaskList() if t.StubFSM != nil { t.StubFSM.ReplicationHandler = TestReplicator(tl.decisionOutcomes) } for _, w := range t.Workers { if t.FailActivitiesOnce { w.ActivityInterceptor = activity.NewComposedDecisionInterceptor( w.ActivityInterceptor, TestFailOnceActivityInterceptor(), ) } w.TaskList = tl.TestWorkerTaskList(w) w.AllowPanics = true } tl.Start() return tl }
func TestThrottleInterceptors(t *te.T) { interceptor := fsm.NewComposedDecisionInterceptor( TestThrotteSignalsOnceInterceptor(), TestThrotteCancelsOnceInterceptor(), TestThrotteChildrenOnceInterceptor(), TestThrotteTimersOnceInterceptor(10), ) ctx := interceptorTestContext() first := &fsm.Outcome{ State: "steady", Data: &TestData{}, Decisions: []*swf.Decision{ { DecisionType: S(swf.DecisionTypeSignalExternalWorkflowExecution), SignalExternalWorkflowExecutionDecisionAttributes: &swf.SignalExternalWorkflowExecutionDecisionAttributes{ SignalName: S("the-signal"), WorkflowId: S("to-signal"), }, }, { DecisionType: S(swf.DecisionTypeRequestCancelExternalWorkflowExecution), RequestCancelExternalWorkflowExecutionDecisionAttributes: &swf.RequestCancelExternalWorkflowExecutionDecisionAttributes{ WorkflowId: S("to-cancel"), }, }, { DecisionType: S(swf.DecisionTypeStartChildWorkflowExecution), StartChildWorkflowExecutionDecisionAttributes: &swf.StartChildWorkflowExecutionDecisionAttributes{ WorkflowId: S("the-child"), WorkflowType: &swf.WorkflowType{Name: S("foo"), Version: S("1")}, }, }, { DecisionType: S(swf.DecisionTypeStartTimer), StartTimerDecisionAttributes: &swf.StartTimerDecisionAttributes{ TimerId: S("the-timer"), StartToFireTimeout: S("12345"), }, }, }, } firstTask := &swf.PollForDecisionTaskOutput{ Events: []*swf.HistoryEvent{ { EventType: S(swf.EventTypeWorkflowExecutionStarted), //triggers the timers interceptor EventId: L(1), }, }, PreviousStartedEventId: L(0), } interceptor.AfterDecision(firstTask, ctx, first) if *first.Decisions[0].SignalExternalWorkflowExecutionDecisionAttributes.WorkflowId == "to-signal" { t.Fatal("signal not intercepted in after", PrettyDecision(*first.Decisions[0])) } if *first.Decisions[1].RequestCancelExternalWorkflowExecutionDecisionAttributes.WorkflowId == "to-cancel" { t.Fatal("cancel not intercepted in after", PrettyDecision(*first.Decisions[1])) } if *first.Decisions[2].StartChildWorkflowExecutionDecisionAttributes.WorkflowId == "the-child" { t.Fatal("child not intercepted in after", PrettyDecision(*first.Decisions[2])) } if *first.Decisions[3].StartTimerDecisionAttributes.TimerId == "the-timer" { t.Fatal("timer not intercepted in after", PrettyDecision(*first.Decisions[3])) } secondTask := &swf.PollForDecisionTaskOutput{ Events: []*swf.HistoryEvent{ { EventType: S(swf.EventTypeStartTimerFailed), EventId: L(4), StartTimerFailedEventAttributes: &swf.StartTimerFailedEventAttributes{ TimerId: first.Decisions[3].StartTimerDecisionAttributes.TimerId, }, }, { EventType: S(swf.EventTypeStartChildWorkflowExecutionFailed), EventId: L(3), StartChildWorkflowExecutionFailedEventAttributes: &swf.StartChildWorkflowExecutionFailedEventAttributes{ WorkflowId: S(fmt.Sprintf("fail-on-purpose-%s", "the-child")), }, }, { EventType: S(swf.EventTypeRequestCancelExternalWorkflowExecutionFailed), EventId: L(2), RequestCancelExternalWorkflowExecutionFailedEventAttributes: &swf.RequestCancelExternalWorkflowExecutionFailedEventAttributes{ WorkflowId: S(fmt.Sprintf("fail-on-purpose-%s", "to-cancel")), }, }, { EventType: S(swf.EventTypeSignalExternalWorkflowExecutionFailed), EventId: L(1), SignalExternalWorkflowExecutionFailedEventAttributes: &swf.SignalExternalWorkflowExecutionFailedEventAttributes{ WorkflowId: S(fmt.Sprintf("fail-on-purpose-%s-%s", "to-signal", "the-signal")), }, }, }, PreviousStartedEventId: L(0), } second := &fsm.Outcome{ State: "steady", Data: &TestData{}, Decisions: []*swf.Decision{ { DecisionType: S(swf.DecisionTypeSignalExternalWorkflowExecution), SignalExternalWorkflowExecutionDecisionAttributes: &swf.SignalExternalWorkflowExecutionDecisionAttributes{ SignalName: S("the-signal"), WorkflowId: S("to-signal"), }, }, { DecisionType: S(swf.DecisionTypeRequestCancelExternalWorkflowExecution), RequestCancelExternalWorkflowExecutionDecisionAttributes: &swf.RequestCancelExternalWorkflowExecutionDecisionAttributes{ WorkflowId: S("to-cancel"), }, }, { DecisionType: S(swf.DecisionTypeStartChildWorkflowExecution), StartChildWorkflowExecutionDecisionAttributes: &swf.StartChildWorkflowExecutionDecisionAttributes{ WorkflowId: S("the-child"), WorkflowType: &swf.WorkflowType{Name: S("foo"), Version: S("1")}, }, }, { DecisionType: S(swf.DecisionTypeStartTimer), StartTimerDecisionAttributes: &swf.StartTimerDecisionAttributes{ TimerId: S("the-timer"), StartToFireTimeout: S("12345"), }, }, }, } interceptor.BeforeDecision(secondTask, ctx, second) if secondTask.Events[0].StartTimerFailedEventAttributes.Cause == nil || *secondTask.Events[0].StartTimerFailedEventAttributes.Cause != swf.StartTimerFailedCauseTimerCreationRateExceeded { t.Fatal("timer failed not rewriten ", PrettyHistoryEvent(secondTask.Events[0])) } if secondTask.Events[1].StartChildWorkflowExecutionFailedEventAttributes.Cause == nil || *secondTask.Events[1].StartChildWorkflowExecutionFailedEventAttributes.Cause != swf.StartChildWorkflowExecutionFailedCauseChildCreationRateExceeded { t.Fatal("start child failed not rewriten ", PrettyHistoryEvent(secondTask.Events[1])) } if secondTask.Events[2].RequestCancelExternalWorkflowExecutionFailedEventAttributes.Cause == nil || *secondTask.Events[2].RequestCancelExternalWorkflowExecutionFailedEventAttributes.Cause != swf.RequestCancelExternalWorkflowExecutionFailedCauseRequestCancelExternalWorkflowExecutionRateExceeded { t.Fatal("request cancel failed not rewriten ", PrettyHistoryEvent(secondTask.Events[2])) } if secondTask.Events[3].SignalExternalWorkflowExecutionFailedEventAttributes.Cause == nil || *secondTask.Events[3].SignalExternalWorkflowExecutionFailedEventAttributes.Cause != swf.SignalExternalWorkflowExecutionFailedCauseSignalExternalWorkflowExecutionRateExceeded { t.Fatal("start timer failed not rewriten ", PrettyHistoryEvent(secondTask.Events[3])) } interceptor.AfterDecision(secondTask, ctx, second) if *second.Decisions[0].SignalExternalWorkflowExecutionDecisionAttributes.WorkflowId != "to-signal" { t.Fatal("signal not cleared in after", PrettyDecision(*second.Decisions[0])) } if *second.Decisions[1].RequestCancelExternalWorkflowExecutionDecisionAttributes.WorkflowId != "to-cancel" { t.Fatal("cancel not cleared in after", PrettyDecision(*second.Decisions[1])) } if *second.Decisions[2].StartChildWorkflowExecutionDecisionAttributes.WorkflowId != "the-child" { t.Fatal("child not cleared in after", PrettyDecision(*second.Decisions[2])) } if *second.Decisions[3].StartTimerDecisionAttributes.TimerId != "the-timer" { t.Fatal("timer not cleared in after", PrettyDecision(*second.Decisions[3])) } }