[statemachine] add additional tests

- test for multiple source states
- test for not allowing transition to self
This commit is contained in:
Eric Mastro 2023-02-22 14:46:10 +11:00
parent c80e3e5e2c
commit 24ad3fdea9
No known key found for this signature in database
GPG Key ID: AD065ECE27A873B9
3 changed files with 74 additions and 35 deletions

View File

@ -14,10 +14,20 @@ proc newSalesAgent*(sales: Sales,
requestState: RequestState, requestState: RequestState,
slotState: SlotState, slotState: SlotState,
restoredFromChain: bool): SalesAgent = restoredFromChain: bool): SalesAgent =
let saleUnknown = SaleUnknown.new()
let saleDownloading = SaleDownloading.new()
let saleProving = SaleProving.new()
let saleFilling = SaleFilling.new()
let saleFilled = SaleFilled.new()
let saleCancelled = SaleCancelled.new()
let saleFailed = SaleFailed.new()
let saleErrored = SaleErrored.new()
let agent = SalesAgent.new(@[ let agent = SalesAgent.new(@[
Transition.new( Transition.new(
SaleUnknown(), saleUnknown,
SaleDownloading.new(), saleDownloading,
proc(m: Machine, s: State): bool = proc(m: Machine, s: State): bool =
let agent = SalesAgent(m) let agent = SalesAgent(m)
agent.requestState.value == RequestState.New and agent.requestState.value == RequestState.New and
@ -25,25 +35,25 @@ proc newSalesAgent*(sales: Sales,
), ),
Transition.new( Transition.new(
@[ @[
SaleUnknown(), saleUnknown,
SaleDownloading(), saleDownloading,
SaleProving(), saleProving,
SaleFilling(), saleFilling,
SaleFilled() saleFilled
], ],
SaleCancelled.new(), saleCancelled,
proc(m: Machine, s: State): bool = proc(m: Machine, s: State): bool =
SalesAgent(m).requestState.value == RequestState.Cancelled SalesAgent(m).requestState.value == RequestState.Cancelled
), ),
Transition.new( Transition.new(
@[ @[
SaleUnknown.new(), saleUnknown,
SaleDownloading.new(), saleDownloading,
SaleProving.new(), saleProving,
SaleFilling.new(), saleFilling,
SaleFilled.new() saleFilled
], ],
SaleFailed.new(), saleFailed,
proc(m: Machine, s: State): bool = proc(m: Machine, s: State): bool =
let agent = SalesAgent(m) let agent = SalesAgent(m)
agent.requestState.value == RequestState.Failed or agent.requestState.value == RequestState.Failed or
@ -51,22 +61,22 @@ proc newSalesAgent*(sales: Sales,
), ),
Transition.new( Transition.new(
@[ @[
SaleUnknown.new(), saleUnknown,
SaleDownloading.new(), saleDownloading,
SaleFilling.new(), saleFilling,
SaleProving.new() saleProving
], ],
SaleFilled.new(), saleFilled,
proc(m: Machine, s: State): bool = proc(m: Machine, s: State): bool =
SalesAgent(m).slotState.value == SlotState.Filled SalesAgent(m).slotState.value == SlotState.Filled
), ),
Transition.new( Transition.new(
@[ @[
SaleUnknown.new(), saleUnknown,
SaleDownloading.new(), saleDownloading,
SaleFilling.new(), saleFilling,
SaleFilled.new(), saleFilled,
SaleProving.new() saleProving
], ],
SaleFinished.new(), SaleFinished.new(),
proc(m: Machine, s: State): bool = proc(m: Machine, s: State): bool =
@ -76,24 +86,24 @@ proc newSalesAgent*(sales: Sales,
), ),
Transition.new( Transition.new(
AnyState.new(), AnyState.new(),
SaleErrored.new(), saleErrored,
proc(m: Machine, s: State): bool = proc(m: Machine, s: State): bool =
SalesAgent(m).errored.value SalesAgent(m).errored.value
), ),
Transition.new( Transition.new(
SaleDownloading.new(), saleDownloading,
SaleProving.new(), saleProving,
proc(m: Machine, s: State): bool = proc(m: Machine, s: State): bool =
SalesAgent(m).downloaded.value SalesAgent(m).downloaded.value
), ),
Transition.new( Transition.new(
SaleProving.new(), saleProving,
SaleFilling.new(), saleFilling,
proc(m: Machine, s: State): bool = proc(m: Machine, s: State): bool =
SalesAgent(m).proof.value.len > 0 # TODO: proof validity check? SalesAgent(m).proof.value.len > 0 # TODO: proof validity check?
), ),
Transition.new( Transition.new(
SaleFilled.new(), saleFilled,
SaleFinished.new(), SaleFinished.new(),
proc(m: Machine, s: State): bool = proc(m: Machine, s: State): bool =
let agent = SalesAgent(m) let agent = SalesAgent(m)
@ -102,8 +112,8 @@ proc newSalesAgent*(sales: Sales,
host == agent.me host == agent.me
), ),
Transition.new( Transition.new(
SaleFilled.new(), saleFilled,
SaleErrored.new(), saleErrored,
proc(m: Machine, s: State): bool = proc(m: Machine, s: State): bool =
let agent = SalesAgent(m) let agent = SalesAgent(m)
without host =? agent.slotHost.value: without host =? agent.slotHost.value:
@ -115,8 +125,8 @@ proc newSalesAgent*(sales: Sales,
else: return false else: return false
), ),
Transition.new( Transition.new(
SaleUnknown.new(), saleUnknown,
SaleErrored.new(), saleErrored,
proc(m: Machine, s: State): bool = proc(m: Machine, s: State): bool =
let agent = SalesAgent(m) let agent = SalesAgent(m)
if agent.restoredFromChain and agent.slotState.value == SlotState.Free: if agent.restoredFromChain and agent.slotState.value == SlotState.Free:

View File

@ -60,7 +60,7 @@ proc checkTransitions(machine: Machine) =
if transition.trigger(machine, machine.state) and if transition.trigger(machine, machine.state) and
machine.state != transition.nextState and # avoid transitioning to self machine.state != transition.nextState and # avoid transitioning to self
(machine.state == nil or (machine.state == nil or
machine.state in transition.prevStates or machine.state in transition.prevStates or # state instance, multiple
transition.prevStates.any(proc (s: State): bool = s of AnyState)): transition.prevStates.any(proc (s: State): bool = s of AnyState)):
machine.schedule(Event.transition(machine.state, transition.nextState)) machine.schedule(Event.transition(machine.state, transition.nextState))

View File

@ -206,3 +206,32 @@ suite "async state machines":
check machine.state of State4 check machine.state of State4
check checked check checked
#3->5 transition was checked but not run because state had already moved to 4 #3->5 transition was checked but not run because state had already moved to 4
test "allows source transition to include multiple states":
machine = MyMachine.new(@[
Transition.new(
@[
state3,
state4
],
state5,
proc(m: Machine, s: State): bool = true
)]
)
machine.start(state3)
check eventually runs == [0, 0, 1, 0, 1]
machine.schedule(Event.transition(state5, state4))
check eventually runs == [0, 0, 1, 1, 2]
check machine.state of State5
test "does not allow transitioning to the state it's already on":
machine = MyMachine.new(@[
Transition.new(
AnyState.new(),
state4,
proc(m: Machine, s: State): bool = true
)]
)
machine.start(state4)
check eventually runs == [0, 0, 0, 0, 0]
check machine.state.isNil