Beispiel #1
0
func TestOnSignalReceived(t *testing.T) {
	signal := "the-signal"
	ctx := deciderTestContext()
	decider := Transition("some-state")
	composedDecider := OnSignalReceived(signal, decider)

	for _, e := range s.SWFHistoryEventTypes() {
		switch e {
		case swf.EventTypeWorkflowExecutionSignaled:
			event := &swf.HistoryEvent{
				EventType: s.S(e),
				EventId:   s.L(129),
				WorkflowExecutionSignaledEventAttributes: &swf.WorkflowExecutionSignaledEventAttributes{
					SignalName: s.S("the-signal"),
				},
			}
			data := &TestingType{Field: "yes"}
			outcome := composedDecider(ctx, event, data)
			expected := decider(ctx, event, data)
			if !reflect.DeepEqual(outcome, expected) {
				t.Fatal("Outcomes not equal", outcome, expected)
			}
		default:
			event := &swf.HistoryEvent{
				EventType: s.S(e),
			}
			outcome := composedDecider(ctx, event, nil)
			if !reflect.DeepEqual(outcome, ctx.Pass()) {
				t.Fatal("Outcome does not equal Pass", outcome)
			}
		}
	}
}
Beispiel #2
0
func testContextWithSignal(scheduledEventId int, event *swf.SignalExternalWorkflowExecutionInitiatedEventAttributes) func() *FSMContext {
	return func() *FSMContext {
		correlator := &EventCorrelator{}
		correlator.Track(&swf.HistoryEvent{
			EventId:   s.I(scheduledEventId),
			EventType: s.S(swf.EventTypeSignalExternalWorkflowExecutionInitiated),
			SignalExternalWorkflowExecutionInitiatedEventAttributes: event,
		})

		return NewFSMContext(nil,
			swf.WorkflowType{Name: s.S("foo"), Version: s.S("1")},
			swf.WorkflowExecution{WorkflowId: s.S("id"), RunId: s.S("runid")},
			correlator, "state", nil, 1)
	}
}
Beispiel #3
0
func TestOnChildStarted(t *testing.T) {
	decider := func(ctx *FSMContext, h *swf.HistoryEvent, data interface{}) Outcome {
		return ctx.Goto("some-state", data, ctx.EmptyDecisions())
	}

	composedDecider := OnChildStarted(decider)

	for _, et := range s.SWFHistoryEventTypes() {
		ctx := deciderTestContext()
		switch et {
		case enums.EventTypeChildWorkflowExecutionStarted:
			event := s.EventFromPayload(129, &swf.ChildWorkflowExecutionStartedEventAttributes{})
			data := new(TestData)
			outcome := composedDecider(ctx, event, data)
			expected := decider(ctx, event, data)
			if !reflect.DeepEqual(outcome, expected) {
				t.Fatal("Outcomes not equal", outcome, expected)
			}
		default:
			event := &swf.HistoryEvent{
				EventType: s.S(et),
			}
			if composedDecider(ctx, event, new(TestData)).State != "" {
				t.Fatal("Non nil decision")
			}
		}
	}
}
Beispiel #4
0
func TestOnData(t *testing.T) {
	decider := Transition("some-state")
	typed := Typed(new(TestingType))
	data := &TestingType{Field: "yes"}
	ctx := deciderTestContext()

	predicate := typed.PredicateFunc(func(data *TestingType) bool {
		return data.Field == "yes"
	})

	composedDecider := OnData(predicate, decider)

	event := &swf.HistoryEvent{
		EventId:        s.L(129),
		EventTimestamp: aws.Time(time.Now()),
		EventType:      s.S(swf.EventTypeWorkflowExecutionStarted),
	}

	outcome := composedDecider(ctx, event, data)
	expected := decider(ctx, event, data)

	if !reflect.DeepEqual(outcome, expected) {
		t.Fatal("Outcomes not equal", outcome, expected)
	}

	data.Field = "nope"
	outcome = composedDecider(ctx, event, data)

	if reflect.DeepEqual(outcome, expected) {
		t.Fatal("Outcomes should not be equal", outcome, expected)
	}
}
Beispiel #5
0
// DefaultCanceledState is the canceled state used in an FSM if one has not been set.
// It simply responds with a CancelWorkflow which attempts to Cancel the workflow.
// This state will only get events if you previously attempted to cancel the workflow and it failed.
func (f *FSM) DefaultCanceledState() *FSMState {
	return &FSMState{
		Name: CanceledState,
		Decider: func(fsm *FSMContext, h *swf.HistoryEvent, data interface{}) Outcome {
			f.log("state=complete at=attempt-cancel event=%s", h)
			return fsm.CancelWorkflow(data, s.S("default-canceled-state"))
		},
	}
}
Beispiel #6
0
func TestFailWorkflow(t *testing.T) {
	// arrange
	data := &TestingType{"Some data"}
	fsmContext := NewFSMContext(nil,
		swf.WorkflowType{Name: s.S("foo"), Version: s.S("1")},
		swf.WorkflowExecution{WorkflowId: s.S("id"), RunId: s.S("runid")},
		nil, "state", nil, 1)
	details := "Some failure message"
	// act
	failDecider := FailWorkflow(s.S(details))
	outcome := failDecider(fsmContext, nil, data)

	// assert
	assert.Equal(t, data, outcome.Data, "Expected data to be passed into failed outcome")
	failDecision := FindDecision(outcome.Decisions, failWorkflowPredicate)
	assert.NotNil(t, failDecision, "Expected to find a fail workflow decision in the outcome")
	assert.Equal(t, details, *failDecision.FailWorkflowExecutionDecisionAttributes.Details,
		"Expected details in the fail decision to match what was passed in")
}
Beispiel #7
0
func TestOnActivityFailedTimedOutCanceled(t *testing.T) {
	activity := "test-activity"
	decider := Transition("some-state")
	composedDecider := OnActivityFailedTimedOutCanceled(activity, decider)

	ctx := testContextWithActivity(123, &swf.ActivityTaskScheduledEventAttributes{
		ActivityId: s.S("the-id"),
		ActivityType: &swf.ActivityType{
			Name:    s.S(activity),
			Version: s.S("1"),
		},
	},
	)

	for _, e := range s.SWFHistoryEventTypes() {
		switch e {
		case swf.EventTypeActivityTaskFailed, swf.EventTypeActivityTaskTimedOut, swf.EventTypeActivityTaskCanceled:
			event := &swf.HistoryEvent{
				EventType: s.S(e),
				EventId:   s.L(129),
				ActivityTaskCanceledEventAttributes: &swf.ActivityTaskCanceledEventAttributes{ScheduledEventId: s.L(123)},
				ActivityTaskFailedEventAttributes:   &swf.ActivityTaskFailedEventAttributes{ScheduledEventId: s.L(123)},
				ActivityTaskTimedOutEventAttributes: &swf.ActivityTaskTimedOutEventAttributes{ScheduledEventId: s.L(123)},
			}
			data := &TestingType{Field: "yes"}
			outcome := composedDecider(ctx(), event, data)
			expected := decider(ctx(), event, data)
			if !reflect.DeepEqual(outcome, expected) {
				t.Fatal("Outcomes not equal", outcome, expected)
			}
		default:
			event := &swf.HistoryEvent{
				EventType: s.S(e),
			}
			outcome := composedDecider(ctx(), event, nil)
			if !reflect.DeepEqual(outcome, ctx().Pass()) {
				t.Fatal("Outcome does not equal Pass", outcome)
			}
		}
	}
}
Beispiel #8
0
func TestFSMWhenStartingNewWorkflowExpectsPreprocScheduled(t *testing.T) {
	// arrange
	// {"CustomerId": 1, "SimulationResultId": 172, "S3SimulationFolder": "Customer_1/simulation172_2016-01-22"}

	simulationStateManager := &simulationStateManager{}
	simulationStateManager.FSM = simulationStateManager.setupFSM()
	events := []*swf.HistoryEvent{
		&swf.HistoryEvent{EventType: sugar.S("DecisionTaskStarted"), EventId: sugar.I(3)},
		&swf.HistoryEvent{EventType: sugar.S("DecisionTaskScheduled"), EventId: sugar.I(2)},
		sugar.EventFromPayload(1, &swf.WorkflowExecutionStartedEventAttributes{
			Input: fsm.StartFSMWorkflowInput(simulationStateManager.FSM, testData),
		}),
	}
	firstDecisionTask := testDecisionTask(0, events)

	// act
	_, decisions, _, err := simulationStateManager.Tick(firstDecisionTask)

	// assert
	assert.Nil(t, err, "Should be no errors")
	assert.NotNil(t, decisions, "Should have returned some decisions")
	assert.True(t, Find(decisions, scheduleActivityPredicateFunc("preproc")), "Should have scheduled preproc")
}
Beispiel #9
0
func TestFSMWhenInPreprocStateAndPreprocFailsExpectsWorkflowFailed(t *testing.T) {
	// arrange
	simulationStateManager := &simulationStateManager{}
	simulationStateManager.FSM = simulationStateManager.setupFSM()

	serializedState := &fsm.SerializedState{}
	serializedState.StateName = "preproc"
	serializedState.StateData = simulationStateManager.FSM.Serialize(testData)
	serializedState.StateVersion = 1

	markerRecordedEvent := sugar.EventFromPayload(5, &swf.MarkerRecordedEventAttributes{
		MarkerName: sugar.S(fsm.StateMarker),
		Details:    sugar.S(simulationStateManager.FSM.Serialize(serializedState)),
	})

	events := []*swf.HistoryEvent{
		&swf.HistoryEvent{EventType: sugar.S("DecisionTaskStarted"), EventId: sugar.I(9)},
		&swf.HistoryEvent{EventType: sugar.S("DecisionTaskScheduled"), EventId: sugar.I(8)},
		sugar.EventFromPayload(7, &swf.ActivityTaskFailedEventAttributes{
			ScheduledEventId: sugar.I(6),
		}),
		sugar.EventFromPayload(6, &swf.ActivityTaskScheduledEventAttributes{
			ActivityId:   sugar.S(testActivityInfo.ActivityId),
			ActivityType: testActivityInfo.ActivityType,
		}),
		markerRecordedEvent,
	}
	first := testDecisionTask(5, events)

	// act
	_, decisions, _, err := simulationStateManager.Tick(first)

	// assert
	assert.Nil(t, err, "Should be no errors")
	assert.NotNil(t, decisions, "Should have returned some decisions")
	assert.True(t, Find(decisions, workflowCancelledPredicate), "Should have failed the workflow because preproc failed")
}
Beispiel #10
0
func DecisionsToEvents(decisions []*swf.Decision) []*swf.HistoryEvent {
	var events []*swf.HistoryEvent
	for _, d := range decisions {
		if scheduleActivityPredicate(d) {
			event := &swf.HistoryEvent{
				EventType: sugar.S("ActivityTaskCompleted"),
				EventId:   sugar.I(7),
				ActivityTaskCompletedEventAttributes: &swf.ActivityTaskCompletedEventAttributes{
					ScheduledEventId: sugar.I(6),
				},
			}
			events = append(events, event)
			event = &swf.HistoryEvent{
				EventType: sugar.S("ActivityTaskScheduled"),
				EventId:   sugar.I(6),
				ActivityTaskScheduledEventAttributes: &swf.ActivityTaskScheduledEventAttributes{
					ActivityId:   sugar.S(testActivityInfo.ActivityId),
					ActivityType: testActivityInfo.ActivityType,
				},
			}
			events = append(events, event)
		}
		if stateMarkerPredicate(d) {
			event := &swf.HistoryEvent{
				EventType: sugar.S("MarkerRecorded"),
				EventId:   sugar.I(5),
				MarkerRecordedEventAttributes: &swf.MarkerRecordedEventAttributes{
					MarkerName: sugar.S(fsm.StateMarker),
					Details:    d.RecordMarkerDecisionAttributes.Details,
				},
			}
			events = append(events, event)

		}
	}
	return events
}
Beispiel #11
0
func (s *simulationStateManager) startWorkflowExecution() error {
	_, err := s.swfAPI.StartWorkflowExecution(&swf.StartWorkflowExecutionInput{
		Domain:                       sugar.S(config.Viper.GetString("env")),
		WorkflowId:                   sugar.S(uuid.NewV4().String()),
		ExecutionStartToCloseTimeout: sugar.S("120"),
		TaskStartToCloseTimeout:      sugar.S("120"),
		ChildPolicy:                  sugar.S(swf.ChildPolicyTerminate),
		//you will have previously regiestered a WorkflowType that this FSM will work.
		WorkflowType: &swf.WorkflowType{Name: sugar.S(config.Workflow.Name), Version: sugar.S(config.Workflow.Version)},
		Input:        fsm.StartFSMWorkflowInput(s.FSM, &StateData{SimulationResultID: 10, CustomerID: 1, S3SimulationFolder: "folder/test"}),
	})
	if err != nil {
		panic(err)
	}
	return nil
}
Beispiel #12
0
func TestFSMWhenInPreprocStateAndPreprocSuccessfullyCompletesExpectsWorkflowComplete(t *testing.T) {
	// arrange
	simulationStateManager := &simulationStateManager{}
	simulationStateManager.FSM = simulationStateManager.setupFSM()

	serializedState := &fsm.SerializedState{}
	serializedState.StateName = "preproc"
	serializedState.StateData = simulationStateManager.FSM.Serialize(testData)
	serializedState.StateVersion = 1

	markerRecordedEvent := sugar.EventFromPayload(5, &swf.MarkerRecordedEventAttributes{
		MarkerName: sugar.S(fsm.StateMarker),
		Details:    sugar.S(simulationStateManager.FSM.Serialize(serializedState)),
	})

	preprocResult := `{"CustomerId":1,"SimulationResultId":172,"S3SimulationFolder":"Customer_1/simulation172_2016-01-22","FileLocation":"Customer_1/simulation172_2016-01-22/b308147a-a73c-493f-bf10-478219419057_scanpattern.zip","ZoxFileLocation":"Customer_1/simulation172_2016-01-22/035c0f01-d53a-4b36-bbaa-21650a0e2a64_voxel.zip","CoarseZoxFileLocation":"Customer_1/simulation172_2016-01-22/035c0f01-d53a-4b36-bbaa-21650a0e2a64_voxel.zip","MediumZoxFileLocation":"Customer_1/simulation172_2016-01-22/035c0f01-d53a-4b36-bbaa-21650a0e2a64_voxel.zip","FineZoxFileLocation":"Customer_1/simulation172_2016-01-22/035c0f01-d53a-4b36-bbaa-21650a0e2a64_voxel.zip","sizeX":0.001,"sizeY":0.001,"sizeZ":0.001}`
	events := []*swf.HistoryEvent{
		&swf.HistoryEvent{EventType: sugar.S("DecisionTaskStarted"), EventId: sugar.I(9)},
		&swf.HistoryEvent{EventType: sugar.S("DecisionTaskScheduled"), EventId: sugar.I(8)},
		sugar.EventFromPayload(7, &swf.ActivityTaskCompletedEventAttributes{
			ScheduledEventId: sugar.I(6),
			Result:           sugar.S(preprocResult),
		}),
		sugar.EventFromPayload(6, &swf.ActivityTaskScheduledEventAttributes{
			ActivityId:   sugar.S(testActivityInfo.ActivityId),
			ActivityType: testActivityInfo.ActivityType,
		}),
		markerRecordedEvent,
	}
	first := testDecisionTask(5, events)

	// act
	_, decisions, _, err := simulationStateManager.Tick(first)

	// assert
	assert.Nil(t, err, "Should be no errors")
	assert.NotNil(t, decisions, "Should have returned some decisions")
	assert.True(t, Find(decisions, workflowCompletedPredicate), "Should have completed the workflow")
	workflowCopmletedDecision := FindDecision(decisions, workflowCompletedPredicate)
	assert.Equal(t, preprocResult, *workflowCopmletedDecision.CompleteWorkflowExecutionDecisionAttributes.Result, "Should have passed the result from preproc onto next decision")
}
Beispiel #13
0
func deciderTestContext() *FSMContext {
	return NewFSMContext(nil,
		swf.WorkflowType{Name: s.S("foo"), Version: s.S("1")},
		swf.WorkflowExecution{WorkflowID: s.S("id"), RunID: s.S("runid")},
		nil, "state", nil, 1)
}
Beispiel #14
0
package simulationworkflow

import (
	// "github.com/3dsim/workflow/logger"
	"github.com/aws/aws-sdk-go/aws"
	"github.com/aws/aws-sdk-go/service/swf"
	"github.com/sclasen/swfsm/fsm"
	"github.com/sclasen/swfsm/sugar"
	"github.com/stretchr/testify/assert"

	"time"

	"testing"
)

var testActivityInfo = fsm.ActivityInfo{ActivityId: "activityId", ActivityType: &swf.ActivityType{Name: sugar.S("activity"), Version: sugar.S("activityVersion")}}
var testWorkflowExecution = &swf.WorkflowExecution{WorkflowId: sugar.S("workflow-id"), RunId: sugar.S("run-id")}
var testWorkflowType = &swf.WorkflowType{Name: sugar.S("workflow-name"), Version: sugar.S("workflow-version")}

var testData = &StateData{
	CustomerID:         1,
	S3SimulationFolder: "Customer_1/simulation172_2016-01-22",
	SimulationResultID: 172,
}

func TestFSMWhenStartingNewWorkflowExpectsPreprocScheduled(t *testing.T) {
	// arrange
	// {"CustomerId": 1, "SimulationResultId": 172, "S3SimulationFolder": "Customer_1/simulation172_2016-01-22"}

	simulationStateManager := &simulationStateManager{}
	simulationStateManager.FSM = simulationStateManager.setupFSM()
Beispiel #15
0
	decisions := f.EmptyDecisions()
	switch *lastEvent.EventType {
	case swf.EventTypeActivityTaskCompleted:
		logger.Log.Info("Previous scheduled activity completed successfully")
		decision := &swf.Decision{}
		decision.DecisionType = aws.String(swf.DecisionTypeCompleteWorkflowExecution)
		decision.CompleteWorkflowExecutionDecisionAttributes = &swf.CompleteWorkflowExecutionDecisionAttributes{
			Result: lastEvent.ActivityTaskCompletedEventAttributes.Result,
		}
		decisions = append(decisions, decision)
	case swf.EventTypeActivityTaskFailed:
		logger.Log.Error("Activity task failed", "lastEvent", lastEvent)
		decision := &swf.Decision{}
		decision.DecisionType = aws.String(swf.DecisionTypeFailWorkflowExecution)
		decision.FailWorkflowExecutionDecisionAttributes = &swf.FailWorkflowExecutionDecisionAttributes{
			Reason: sugar.S("Preproc failed"),
		}
		decisions = append(decisions, decision)
	}
	//if the event was unexpected just stay here
	return f.Stay(stateData, decisions)
}

func (s *simulationStateManager) startWorkflowExecution() error {
	_, err := s.swfAPI.StartWorkflowExecution(&swf.StartWorkflowExecutionInput{
		Domain:                       sugar.S(config.Viper.GetString("env")),
		WorkflowId:                   sugar.S(uuid.NewV4().String()),
		ExecutionStartToCloseTimeout: sugar.S("120"),
		TaskStartToCloseTimeout:      sugar.S("120"),
		ChildPolicy:                  sugar.S(swf.ChildPolicyTerminate),
		//you will have previously regiestered a WorkflowType that this FSM will work.