mirror of https://github.com/certusone/dc4bc.git
288 lines
7.5 KiB
Go
288 lines
7.5 KiB
Go
package fsm_pool
|
|
|
|
import (
|
|
"github.com/depools/dc4bc/fsm/fsm"
|
|
"testing"
|
|
)
|
|
|
|
type testMachineFSM1 struct {
|
|
*fsm.FSM
|
|
data int
|
|
}
|
|
|
|
const (
|
|
testVal1 = 100
|
|
testVal2 = 17
|
|
)
|
|
|
|
const (
|
|
fsm1Name = "fsm1"
|
|
// Init process from global idle state
|
|
fsm1StateInit = fsm.StateGlobalIdle
|
|
// Set up data
|
|
fsm1StateStage1 = fsm.State("state_fsm1_stage1")
|
|
// Process data
|
|
fsm1StateStage2 = fsm.State("state_fsm1_stage2")
|
|
// Canceled with internal event
|
|
fsm1StateCanceledByInternal = fsm.State("state_fsm1_canceled")
|
|
// Canceled with external event
|
|
fsm1StateCanceled2 = fsm.State("state_fsm1_canceled2")
|
|
// Out endpoint to switch
|
|
fsm1StateOutToFSM2 = fsm.State("state_fsm1_out_to_fsm2")
|
|
|
|
// Events
|
|
eventFSM1Init = fsm.Event("event_fsm1_init")
|
|
eventFSM1Cancel = fsm.Event("event_fsm1_cancel")
|
|
eventFSM1Process = fsm.Event("event_fsm1_process")
|
|
|
|
// Internal events
|
|
eventFSM1Internal = fsm.Event("event_internal_fsm1")
|
|
eventFSM1CancelByInternal = fsm.Event("event_internal_fsm1_cancel")
|
|
eventFSM1InternalOut2 = fsm.Event("event_internal_fsm1_out")
|
|
)
|
|
|
|
var (
|
|
testing1Events = []fsm.EventDesc{
|
|
// Init
|
|
{Name: eventFSM1Init, SrcState: []fsm.State{fsm1StateInit}, DstState: fsm1StateStage1, IsAuto: true, AutoRunMode: fsm.EventRunAfter},
|
|
{Name: eventFSM1Internal, SrcState: []fsm.State{fsm1StateStage1}, DstState: fsm1StateStage2, IsInternal: true},
|
|
|
|
// Cancellation events
|
|
{Name: eventFSM1CancelByInternal, SrcState: []fsm.State{fsm1StateStage2}, DstState: fsm1StateCanceledByInternal, IsInternal: true},
|
|
{Name: eventFSM1Cancel, SrcState: []fsm.State{fsm1StateStage2}, DstState: fsm1StateCanceled2},
|
|
|
|
// Out
|
|
{Name: eventFSM1Process, SrcState: []fsm.State{fsm1StateStage2}, DstState: fsm1StateOutToFSM2},
|
|
{Name: eventFSM1InternalOut2, SrcState: []fsm.State{fsm1StateStage2}, DstState: fsm1StateOutToFSM2, IsInternal: true},
|
|
}
|
|
)
|
|
|
|
func NewFSM1() MachineProvider {
|
|
machine := &testMachineFSM1{}
|
|
|
|
machine.FSM = fsm.MustNewFSM(
|
|
fsm1Name,
|
|
fsm1StateInit,
|
|
testing1Events,
|
|
fsm.Callbacks{
|
|
eventFSM1Init: machine.actionFSM1SetUpData,
|
|
eventFSM1InternalOut2: machine.actionFSM1EmitOut2,
|
|
eventFSM1Process: machine.actionFSM1ProcessData,
|
|
},
|
|
)
|
|
return machine
|
|
}
|
|
|
|
func (m *testMachineFSM1) actionFSM1SetUpData(inEvent fsm.Event, args ...interface{}) (outEvent fsm.Event, response interface{}, err error) {
|
|
m.data = testVal1
|
|
outEvent = eventFSM1Internal
|
|
return
|
|
}
|
|
|
|
func (m *testMachineFSM1) actionFSM1ProcessData(inEvent fsm.Event, args ...interface{}) (outEvent fsm.Event, response interface{}, err error) {
|
|
if len(args) == 1 {
|
|
if val, ok := args[0].(int); ok {
|
|
m.data -= val
|
|
}
|
|
}
|
|
|
|
response = m.data
|
|
return
|
|
}
|
|
|
|
func (m *testMachineFSM1) actionFSM1EmitOut2(inEvent fsm.Event, args ...interface{}) (outEvent fsm.Event, response interface{}, err error) {
|
|
return
|
|
}
|
|
|
|
// Second test machine
|
|
|
|
type testMachineFSM2 struct {
|
|
*fsm.FSM
|
|
data int
|
|
}
|
|
|
|
const (
|
|
fsm2Name = "fsm2"
|
|
// Init process from global idle state
|
|
fsm2StateInit = fsm1StateOutToFSM2
|
|
// Process data
|
|
fsm2StateStage1 = fsm.State("state_fsm2_stage1")
|
|
fsm2StateStage2 = fsm.State("state_fsm2_stage2")
|
|
// Canceled with internal event
|
|
fsm2StateCanceledByInternal = fsm.State("state_fsm2_canceled")
|
|
// Out endpoint to switch
|
|
fsm2StateOutToFSM3 = fsm.State("state_fsm2_out_to_fsm3")
|
|
|
|
// Events
|
|
eventFSM2Init = fsm.Event("event_fsm2_init")
|
|
eventFSM2Process = fsm.Event("event_fsm2_process")
|
|
|
|
// Internal events
|
|
eventFSM2Internal = fsm.Event("event_internal_fsm2")
|
|
eventFSM2CancelByInternal = fsm.Event("event_internal_fsm2_cancel")
|
|
eventFSM2InternalOut = fsm.Event("event_internal_fsm2_out")
|
|
)
|
|
|
|
var (
|
|
testing2Events = []fsm.EventDesc{
|
|
// Init
|
|
{Name: eventFSM2Init, SrcState: []fsm.State{fsm2StateInit}, DstState: fsm2StateStage1},
|
|
{Name: eventFSM2Internal, SrcState: []fsm.State{fsm2StateStage1}, DstState: fsm2StateStage2, IsInternal: true},
|
|
|
|
// Cancellation events
|
|
{Name: eventFSM2CancelByInternal, SrcState: []fsm.State{fsm2StateStage2}, DstState: fsm2StateCanceledByInternal, IsInternal: true},
|
|
|
|
// Out
|
|
{Name: eventFSM2Process, SrcState: []fsm.State{fsm2StateStage2}, DstState: fsm.StateGlobalDone},
|
|
{Name: eventFSM2InternalOut, SrcState: []fsm.State{fsm2StateStage2}, DstState: fsm.StateGlobalDone, IsInternal: true},
|
|
}
|
|
|
|
testing2Callbacks = fsm.Callbacks{}
|
|
)
|
|
|
|
func NewFSM2() MachineProvider {
|
|
machine := &testMachineFSM1{}
|
|
|
|
machine.FSM = fsm.MustNewFSM(
|
|
fsm2Name,
|
|
fsm2StateInit,
|
|
testing2Events,
|
|
testing2Callbacks,
|
|
)
|
|
return machine
|
|
}
|
|
|
|
func (m *testMachineFSM2) actionFSM2SetUpData(event fsm.Event, args ...interface{}) (response interface{}, err error) {
|
|
return
|
|
}
|
|
|
|
func (m *testMachineFSM2) actionFSM2ProcessData(event fsm.Event, args ...interface{}) (response interface{}, err error) {
|
|
return
|
|
}
|
|
|
|
func (m *testMachineFSM2) actionFSM2EmitOut2(event fsm.Event, args ...interface{}) (response interface{}, err error) {
|
|
return
|
|
}
|
|
|
|
var testPoolProvider *FSMPool
|
|
|
|
func init() {
|
|
testPoolProvider = Init(
|
|
NewFSM1(),
|
|
NewFSM2(),
|
|
)
|
|
}
|
|
|
|
func TestFSMPool_Init_EventsMap(t *testing.T) {
|
|
if len(testPoolProvider.events) == 0 {
|
|
t.Errorf("expected initialized events map")
|
|
}
|
|
}
|
|
|
|
func TestFSMPool_Init_StatesMap(t *testing.T) {
|
|
if len(testPoolProvider.states) == 0 {
|
|
t.Errorf("expected initialized states map")
|
|
}
|
|
}
|
|
|
|
func TestFSMPool_EntryPointMachine(t *testing.T) {
|
|
m, err := testPoolProvider.EntryPointMachine()
|
|
|
|
if err != nil || m.Name() != fsm1Name {
|
|
t.Errorf("expected entry point machine")
|
|
}
|
|
}
|
|
|
|
func TestFSMPool_MachineByState(t *testing.T) {
|
|
fsm1States := []fsm.State{
|
|
fsm1StateInit,
|
|
fsm1StateStage1,
|
|
fsm1StateStage2,
|
|
}
|
|
|
|
for _, state := range fsm1States {
|
|
machine, err := testPoolProvider.MachineByState(state)
|
|
if err != nil || machine.Name() != fsm1Name {
|
|
t.Errorf("expected machine fsm1 for state \"%s\"", state)
|
|
continue
|
|
}
|
|
}
|
|
|
|
fsm2States := []fsm.State{
|
|
fsm2StateInit,
|
|
fsm2StateStage1,
|
|
fsm2StateStage2,
|
|
}
|
|
|
|
for _, state := range fsm2States {
|
|
machine, err := testPoolProvider.MachineByState(state)
|
|
if err != nil || machine.Name() != fsm2Name {
|
|
t.Errorf("expected machine fsm2 for state \"%s\"", state)
|
|
continue
|
|
}
|
|
}
|
|
}
|
|
|
|
func TestFSMPool_MachineByEvent(t *testing.T) {
|
|
fsm1Events := []fsm.Event{
|
|
eventFSM1Init,
|
|
eventFSM1Cancel,
|
|
eventFSM1Process,
|
|
}
|
|
|
|
for _, event := range fsm1Events {
|
|
machine, err := testPoolProvider.MachineByEvent(event)
|
|
if err != nil || machine.Name() != fsm1Name {
|
|
t.Errorf("expected machine fsm1 for event \"%s\"", event)
|
|
continue
|
|
}
|
|
}
|
|
|
|
fsm2Events := []fsm.Event{
|
|
eventFSM2Init,
|
|
eventFSM2Process,
|
|
}
|
|
|
|
for _, event := range fsm2Events {
|
|
machine, err := testPoolProvider.MachineByEvent(event)
|
|
if err != nil || machine.Name() != fsm2Name {
|
|
t.Errorf("expected machine fsm2 for event \"%s\"", event)
|
|
continue
|
|
}
|
|
}
|
|
}
|
|
|
|
func TestFSMPool_WorkFlow(t *testing.T) {
|
|
machine, err := testPoolProvider.MachineByState(fsm1StateInit)
|
|
|
|
if err != nil || machine.Name() != fsm1Name {
|
|
t.Fatalf("expected machine fsm1 for state \"%s\"", fsm1StateInit)
|
|
}
|
|
|
|
if machine.State() != fsm1StateInit {
|
|
t.Fatalf("expected machine state \"%s\", got \"%s\"", fsm1StateInit, machine.State())
|
|
}
|
|
|
|
resp, err := machine.Do(eventFSM1Init)
|
|
|
|
if err != nil {
|
|
t.Fatalf("expected response without error, got \"%s\"", err)
|
|
}
|
|
|
|
if resp.State != fsm1StateStage2 {
|
|
t.Fatalf("expected machine state \"%s\", got \"%s\"", fsm1StateStage2, resp.State)
|
|
}
|
|
|
|
resp, err = machine.Do(eventFSM1Process, testVal2)
|
|
|
|
data, ok := resp.Data.(int)
|
|
|
|
if !ok {
|
|
t.Fatalf("expected response data int, got \"%s\"", resp.Data)
|
|
}
|
|
|
|
if data != (testVal1 - testVal2) {
|
|
t.Fatalf("expected response data value, got \"%d\"", data)
|
|
}
|
|
}
|