@@ -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,50 @@ 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
82
+ act .WithStateEnterCallback (stateEnter ),
76
83
)
77
84
78
85
return spec , nil
79
86
}
80
87
81
88
func state1to2 (state gen.Atom , data t18data , message t18transitionState1toState2 , proc gen.Process ) (gen.Atom , t18data , error ) {
82
- data .count ++
89
+ data .transitions ++
83
90
return gen .Atom ("state2" ), data , nil
84
91
}
85
92
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
93
+ func queryData (state gen.Atom , data t18data , message t18query , proc gen.Process ) (gen.Atom , t18data , t18data , error ) {
94
+ return state , data , data , nil
95
+ }
96
+
97
+ func stateEnter (oldState gen.Atom , newState gen.Atom , data t18data , proc gen.Process ) (gen.Atom , t18data , error ) {
98
+ data .stateEnterCallbacks ++
99
+
100
+ if newState == gen .Atom ("state2" ) {
101
+ data .transitions ++
102
+ return gen .Atom ("state3" ), data , nil
103
+
104
+ }
105
+ return newState , data , nil
106
+ }
107
+
108
+ func state3Enter (state gen.Atom , data t18data , proc gen.Process ) (gen.Atom , t18data , error ) {
109
+ data .stateEnterCallbacks ++
110
+ return state , data , nil
89
111
}
90
112
91
113
func (t * t18 ) TestStateMachine (input any ) {
@@ -100,31 +122,40 @@ func (t *t18) TestStateMachine(input any) {
100
122
return
101
123
}
102
124
103
- // send message to transition from state 1 to 2
125
+ // Send a message to transition to state 2. The state enter callback should
126
+ // automatically transition to state 3 where another state enter callback
127
+ // does not trigger any further state transitions.
104
128
err = t .Send (pid , t18transitionState1toState2 {})
105
-
106
129
if err != nil {
107
- t .Log ().Error ("sending to the statemachine process failed: %s" , err )
130
+ t .Log ().Error ("send 't18transitionState1toState2' failed: %s" , err )
108
131
t .testcase .err <- err
109
132
return
110
133
}
111
134
112
- // send call to transition from result 2 to 1
113
- result , err := t .Call (pid , t18transitionState2toState1 {})
135
+ // Query the data from the state machine (and test StateCallHandler behavior)
136
+ result , err := t .Call (pid , t18query {})
114
137
if err != nil {
115
- t .Log ().Error ("call to the statemachine process failed: %s" , err )
138
+ t .Log ().Error ("call 't18query' failed: %s" , err )
116
139
t .testcase .err <- err
117
140
return
118
141
}
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 )
142
+
143
+ // We expect 2 state transitions (state1 -> state2 -> state3)
144
+ data := result .(t18data )
145
+ if data .transitions != 2 {
146
+ t .testcase .err <- fmt .Errorf ("expected 2 state transitions, got %v" , result )
122
147
return
123
148
}
124
149
125
- // statemachine process should crash on invalid state transition
150
+ // We expect a chain of 2 state enter callback functions to be called, one
151
+ // for state2 and one for state3.
152
+ if data .stateEnterCallbacks != 2 {
153
+ t .testcase .err <- fmt .Errorf ("expected 2 state enter function invocations, got %d" , data .stateEnterCallbacks )
154
+ }
155
+
156
+ // Statemachine process should crash on invalid state transition
126
157
err = t .testcase .expectProcessToTerminate (pid , t , func (p gen.Process ) error {
127
- return p .Send (pid , t18transitionState2toState1 {}) // we are in state1
158
+ return p .Send (pid , t18transitionState2toState1 {}) // we are in state3
128
159
})
129
160
if err != nil {
130
161
t .testcase .err <- err
0 commit comments