@@ -54,7 +54,8 @@ type t18statemachine struct {
54
54
}
55
55
56
56
type t18data struct {
57
- count int
57
+ transitions int
58
+ stateEnterCallbacks int
58
59
}
59
60
60
61
type t18transitionState1toState2 struct {
@@ -63,29 +64,48 @@ type t18transitionState1toState2 struct {
63
64
type t18transitionState2toState1 struct {
64
65
}
65
66
67
+ type t18query struct {
68
+ }
69
+
66
70
func (sm * t18statemachine ) Init (args ... any ) (act.StateMachineSpec [t18data ], error ) {
67
71
spec := act .NewStateMachineSpec (gen .Atom ("state1" ),
68
72
// initial data
69
- act .WithData (t18data {count : 1 }),
73
+ act .WithData (t18data {}),
70
74
71
75
// set up a message handler for the transition state1 -> state2
72
76
act .WithStateMessageHandler (gen .Atom ("state1" ), state1to2 ),
73
77
74
- // set up a call handler for the transition state2 -> state1
75
- act .WithStateCallHandler (gen .Atom ("state2" ), state2to1 ),
78
+ // set up a call handler to query the data
79
+ act .WithStateCallHandler (gen .Atom ("state3" ), queryData ),
80
+
81
+ // set up a state enter callback for state2
82
+ act .WithStateEnterCallback (gen .Atom ("state2" ), state2Enter ),
83
+
84
+ // set up a state enter callback for state3 to test chaining state enter callbacks
85
+ act .WithStateEnterCallback (gen .Atom ("state3" ), state3Enter ),
76
86
)
77
87
78
88
return spec , nil
79
89
}
80
90
81
91
func state1to2 (state gen.Atom , data t18data , message t18transitionState1toState2 , proc gen.Process ) (gen.Atom , t18data , error ) {
82
- data .count ++
92
+ data .transitions ++
83
93
return gen .Atom ("state2" ), data , nil
84
94
}
85
95
86
- func state2to1 (state gen.Atom , data t18data , message t18transitionState2toState1 , proc gen.Process ) (gen.Atom , t18data , int , error ) {
87
- data .count ++
88
- return gen .Atom ("state1" ), data , data .count , nil
96
+ func queryData (state gen.Atom , data t18data , message t18query , proc gen.Process ) (gen.Atom , t18data , t18data , error ) {
97
+ return state , data , data , nil
98
+ }
99
+
100
+ func state2Enter (state gen.Atom , data t18data , proc gen.Process ) (gen.Atom , t18data , error ) {
101
+ data .stateEnterCallbacks ++
102
+ data .transitions ++
103
+ return gen .Atom ("state3" ), data , nil
104
+ }
105
+
106
+ func state3Enter (state gen.Atom , data t18data , proc gen.Process ) (gen.Atom , t18data , error ) {
107
+ data .stateEnterCallbacks ++
108
+ return state , data , nil
89
109
}
90
110
91
111
func (t * t18 ) TestStateMachine (input any ) {
@@ -100,31 +120,40 @@ func (t *t18) TestStateMachine(input any) {
100
120
return
101
121
}
102
122
103
- // send message to transition from state 1 to 2
123
+ // Send a message to transition to state 2. The state enter callback should
124
+ // automatically transition to state 3 where another state enter callback
125
+ // does not trigger any further state transitions.
104
126
err = t .Send (pid , t18transitionState1toState2 {})
105
-
106
127
if err != nil {
107
- t .Log ().Error ("sending to the statemachine process failed: %s" , err )
128
+ t .Log ().Error ("send 't18transitionState1toState2' failed: %s" , err )
108
129
t .testcase .err <- err
109
130
return
110
131
}
111
132
112
- // send call to transition from result 2 to 1
113
- result , err := t .Call (pid , t18transitionState2toState1 {})
133
+ // Query the data from the state machine (and test StateCallHandler behavior)
134
+ result , err := t .Call (pid , t18query {})
114
135
if err != nil {
115
- t .Log ().Error ("call to the statemachine process failed: %s" , err )
136
+ t .Log ().Error ("call 't18query' failed: %s" , err )
116
137
t .testcase .err <- err
117
138
return
118
139
}
119
- // initial count was 1, after 2 state transitions we expect the count to be 3
120
- if result != 3 {
121
- t .testcase .err <- fmt .Errorf ("expected 3, got %v" , result )
140
+
141
+ // We expect 2 state transitions (state1 -> state2 -> state3)
142
+ data := result .(t18data )
143
+ if data .transitions != 2 {
144
+ t .testcase .err <- fmt .Errorf ("expected 2 state transitions, got %v" , result )
122
145
return
123
146
}
124
147
125
- // statemachine process should crash on invalid state transition
148
+ // We expect a chain of 2 state enter callback functions to be called, one
149
+ // for state2 and one for state3.
150
+ if data .stateEnterCallbacks != 2 {
151
+ t .testcase .err <- fmt .Errorf ("expected 2 state enter function invocations, got %d" , data .stateEnterCallbacks )
152
+ }
153
+
154
+ // Statemachine process should crash on invalid state transition
126
155
err = t .testcase .expectProcessToTerminate (pid , t , func (p gen.Process ) error {
127
- return p .Send (pid , t18transitionState2toState1 {}) // we are in state1
156
+ return p .Send (pid , t18transitionState2toState1 {}) // we are in state3
128
157
})
129
158
if err != nil {
130
159
t .testcase .err <- err
0 commit comments