@@ -8,13 +8,8 @@ import (
8
8
"ergo.services/ergo"
9
9
"ergo.services/ergo/act"
10
10
"ergo.services/ergo/gen"
11
- "ergo.services/ergo/lib"
12
11
)
13
12
14
- //
15
- // this is the template for writing new tests
16
- //
17
-
18
13
var (
19
14
t18cases []* testcase
20
15
)
@@ -45,148 +40,87 @@ func (t *t18) HandleMessage(from gen.PID, message any) error {
45
40
return nil
46
41
}
47
42
48
- func factory_t18statemachine () gen.ProcessBehavior {
49
- return & t18statemachine {}
50
- }
51
-
52
- type t18statemachine struct {
53
- act.StateMachine [t18data ]
54
- tc * testcase
43
+ // Test state transitions with messages and calls
44
+ func factory_t18_state_transitions () gen.ProcessBehavior {
45
+ return & t18_state_transitions {}
55
46
}
56
47
57
- type t18data struct {
58
- transitions int
59
- stateEnterCallbacks int
60
- testEventReceived bool
48
+ type t18_state_transitions struct {
49
+ act.StateMachine [t18_state_transitions_data ]
61
50
}
62
51
63
- type t18transitionState1toState2 struct {
52
+ type t18_state_transitions_data struct {
53
+ transitions int
64
54
}
65
55
66
- type t18transitionState2toState1 struct {
56
+ type t18_state2 struct {
67
57
}
68
58
69
- type t18query struct {
59
+ type t18_get_transitions struct {
70
60
}
71
61
72
- type t18event struct {
73
- payload string
74
- }
75
-
76
- func (sm * t18statemachine ) Init (args ... any ) (act.StateMachineSpec [t18data ], error ) {
62
+ func (sm * t18_state_transitions ) Init (args ... any ) (act.StateMachineSpec [t18_state_transitions_data ], error ) {
77
63
spec := act .NewStateMachineSpec (gen .Atom ("state1" ),
78
64
// initial data
79
- act .WithData (t18data {}),
80
-
81
- // set up a message handler for the transition state1 -> state2
82
- act .WithStateMessageHandler (gen .Atom ("state1" ), state1to2 ),
83
-
84
- // set up a call handler to query the data
85
- act .WithStateCallHandler (gen .Atom ("state3" ), queryData ),
65
+ act .WithData (t18_state_transitions_data {}),
86
66
87
- // set up a state enter callback
88
- act .WithStateEnterCallback ( stateEnter ),
67
+ // set up a message handler for the transition [state1] -> [state2]
68
+ act .WithStateMessageHandler ( gen . Atom ( "state1" ), t18_move_to_state2 ),
89
69
90
- // register event handler
91
- act .WithEventHandler (gen.Event { Name : "testEvent" , Node : "t18node@localhost" }, handleTestEvent ),
70
+ // set up a call handler to query the number of state transitions
71
+ act .WithStateCallHandler (gen .Atom ( "state2" ), t18_total_transitions ),
92
72
)
93
73
94
74
return spec , nil
95
75
}
96
76
97
- func state1to2 (state gen.Atom , data t18data , message t18transitionState1toState2 , proc gen.Process ) (gen.Atom , t18data , error ) {
77
+ func t18_move_to_state2 (state gen.Atom , data t18_state_transitions_data , message t18_state2 , proc gen.Process ) (gen.Atom , t18_state_transitions_data , error ) {
98
78
data .transitions ++
99
79
return gen .Atom ("state2" ), data , nil
100
80
}
101
81
102
- func queryData (state gen.Atom , data t18data , message t18query , proc gen.Process ) (gen.Atom , t18data , t18data , error ) {
103
- return state , data , data , nil
104
- }
105
-
106
- func stateEnter (oldState gen.Atom , newState gen.Atom , data t18data , proc gen.Process ) (gen.Atom , t18data , error ) {
107
- data .stateEnterCallbacks ++
108
-
109
- if newState == gen .Atom ("state2" ) {
110
- data .transitions ++
111
- return gen .Atom ("state3" ), data , nil
112
-
113
- }
114
- return newState , data , nil
115
- }
116
-
117
- func handleTestEvent (state gen.Atom , data t18data , event t18event , proc gen.Process ) (gen.Atom , t18data , error ) {
118
- data .testEventReceived = true
119
- return state , data , nil
82
+ func t18_total_transitions (state gen.Atom , data t18_state_transitions_data , message t18_get_transitions , proc gen.Process ) (gen.Atom , t18_state_transitions_data , int , error ) {
83
+ return state , data , data .transitions , nil
120
84
}
121
85
122
86
func (t * t18 ) TestStateMachine (input any ) {
123
87
defer func () {
124
88
t .testcase = nil
125
89
}()
126
90
127
- // Register the event first, otherwise the StateMachine will not be able
128
- // to start monitoring.
129
- testEvent := gen .Atom ("testEvent" )
130
- token , err := t .RegisterEvent (testEvent , gen.EventOptions {})
131
-
132
- pid , err := t .Spawn (factory_t18statemachine , gen.ProcessOptions {})
91
+ pid , err := t .Spawn (factory_t18_state_transitions , gen.ProcessOptions {})
133
92
if err != nil {
134
93
t .Log ().Error ("unable to spawn statemachine process: %s" , err )
135
94
t .testcase .err <- err
136
95
return
137
96
}
138
97
139
- // Send a message to transition to state 2. The state enter callback should
140
- // automatically transition to state 3 where another state enter callback
141
- // does not trigger any further state transitions.
142
- err = t .Send (pid , t18transitionState1toState2 {})
98
+ // Send a message to transition to state 2.
99
+ err = t .Send (pid , t18_state2 {})
143
100
if err != nil {
144
- t .Log ().Error ("send 't18transitionState1toState2 ' failed: %s" , err )
101
+ t .Log ().Error ("send 't18_state2 ' failed: %s" , err )
145
102
t .testcase .err <- err
146
103
return
147
104
}
148
105
149
106
// Query the data from the state machine (and test StateCallHandler behavior)
150
- result , err := t .Call (pid , t18query {})
107
+ result , err := t .Call (pid , t18_get_transitions {})
151
108
if err != nil {
152
- t .Log ().Error ("call 't18query ' failed: %s" , err )
109
+ t .Log ().Error ("call 't18_get_transitions ' failed: %s" , err )
153
110
t .testcase .err <- err
154
111
return
155
112
}
156
113
157
- // We expect 2 state transitions (state1 -> state2 -> state3)
158
- data := result .(t18data )
159
- if data .transitions != 2 {
160
- t .testcase .err <- fmt .Errorf ("expected 2 state transitions, got %v" , result )
161
- return
162
- }
163
-
164
- // We expect a chain of 2 state enter callback functions to be called, one
165
- // for state2 and one for state3.
166
- if data .stateEnterCallbacks != 2 {
167
- t .testcase .err <- fmt .Errorf ("expected 2 state enter function invocations, got %d" , data .stateEnterCallbacks )
168
- return
169
- }
170
-
171
- event := t18event {lib .RandomString (8 )}
172
- t .SendEvent (testEvent , token , event )
173
-
174
- // Query the data from the state machine
175
- result , err = t .Call (pid , t18query {})
176
- if err != nil {
177
- t .Log ().Error ("call 't18query' failed: %s" , err )
178
- t .testcase .err <- err
179
- return
180
- }
181
- data = result .(t18data )
182
- if data .testEventReceived == false {
183
- t .testcase .err <- fmt .Errorf ("expected test event to be received" )
114
+ // We expect 1 state transitions: [state1] -> [state2]
115
+ data := result .(int )
116
+ if data != 1 {
117
+ t .testcase .err <- fmt .Errorf ("expected 1 state transitions, got %v" , result )
184
118
return
185
119
}
186
120
187
121
// Statemachine process should crash on invalid state transition
188
122
err = t .testcase .expectProcessToTerminate (pid , t , func (p gen.Process ) error {
189
- return p .Send (pid , t18transitionState2toState1 {}) // we are in state3
123
+ return p .Send (pid , t18_state2 {}) // we are in state2
190
124
})
191
125
if err != nil {
192
126
t .testcase .err <- err
0 commit comments