From a9f636f81b70f67779e1e65b2198e62b459997bc Mon Sep 17 00:00:00 2001 From: Michael Hoffer Date: Thu, 23 Feb 2023 17:33:41 +0100 Subject: [PATCH] toggle-state-and-count test added, nestedFSM test fixed (actually switches region mode) --- config/common.properties | 4 +- subprojects/executor/build.gradle | 3 + .../eu/mihosoft/vsm/executor/FSMExecutor.java | 3 +- .../java/eu/mihosoft/vsm/model/FSMTest.java | 248 +++++++++++++++++- 4 files changed, 250 insertions(+), 8 deletions(-) diff --git a/config/common.properties b/config/common.properties index 037f110..7ccc77b 100644 --- a/config/common.properties +++ b/config/common.properties @@ -1,6 +1,8 @@ #vmf.version = 0.3-SNAPSHOT vmf.version = 0.2.8.6 -publication.version = 0.4.0 +publication.version = 0.4.1 asyncutils.version = 0.1.1 + +tinylog.version = 2.5.0 diff --git a/subprojects/executor/build.gradle b/subprojects/executor/build.gradle index 67908de..ae924ac 100644 --- a/subprojects/executor/build.gradle +++ b/subprojects/executor/build.gradle @@ -47,6 +47,9 @@ dependencies { implementation "eu.mihosoft.asyncutils:asyncutils:${rootProject.commonProps.get("asyncutils.version")}" + implementation "org.tinylog:tinylog-api:${rootProject.commonProps.get("tinylog.version")}" + implementation "org.tinylog:tinylog-impl:${rootProject.commonProps.get("tinylog.version")}" + implementation project(":subprojects:fsm") } diff --git a/subprojects/executor/src/main/java/eu/mihosoft/vsm/executor/FSMExecutor.java b/subprojects/executor/src/main/java/eu/mihosoft/vsm/executor/FSMExecutor.java index 95e5dc3..c57c73e 100644 --- a/subprojects/executor/src/main/java/eu/mihosoft/vsm/executor/FSMExecutor.java +++ b/subprojects/executor/src/main/java/eu/mihosoft/vsm/executor/FSMExecutor.java @@ -768,7 +768,6 @@ private void performStateTransition(Event evt, State oldState, State newState, T // create a new execute for child fsm if it doesn't exist yet if (childFSM.getExecutor() == null) { newState.getOwningFSM().getExecutor().newChild(childFSM); - //getCaller().getExecutor().newChild(childFSM); } eu.mihosoft.vsm.model.FSMExecutor executor = childFSM.getExecutor(); executor.reset(); @@ -1084,7 +1083,7 @@ public CompletableFuture stopAsync() { private void log(String msg) { if(getCaller().isVerbose()) { - System.out.println(msg); + org.tinylog.Logger.info(msg); } } diff --git a/subprojects/executor/src/test/java/eu/mihosoft/vsm/model/FSMTest.java b/subprojects/executor/src/test/java/eu/mihosoft/vsm/model/FSMTest.java index c909aed..3704c9d 100644 --- a/subprojects/executor/src/test/java/eu/mihosoft/vsm/model/FSMTest.java +++ b/subprojects/executor/src/test/java/eu/mihosoft/vsm/model/FSMTest.java @@ -25,6 +25,7 @@ */ package eu.mihosoft.vsm.model; +import static java.lang.Thread.currentThread; import static org.hamcrest.MatcherAssert.assertThat; import static org.hamcrest.Matchers.*; @@ -154,7 +155,7 @@ public void testATMFSM() throws InterruptedException { fsm.vmf().reflect().propertyByName("currentState").orElseThrow().addChangeListener(change -> { var oldV = (State) change.propertyChange().orElseThrow().oldValue(); var newV = (State) change.propertyChange().orElseThrow().newValue(); - System.out.println(Thread.currentThread() + " > transitioned from " + + System.out.println(currentThread() + " > transitioned from " + (oldV == null ? "" : oldV.getName()) + " to " + (newV == null ? "" : newV.getName())); @@ -603,7 +604,7 @@ private static FSM createNestedWithOrthogonal(List enterExitListOrig, bo } catch (InterruptedException interruptedException) { System.out.println("interrupt do-action-in-state-c"); enterExitList.add("interrupt do-action-in-state-c"); - Thread.currentThread().interrupt(); + currentThread().interrupt(); } finally { System.out.println("exit do-action-in-state-c"); enterExitList.add("exit do-action-in-state-c"); @@ -1535,7 +1536,7 @@ public void testChildrenDoneEvent() throws InterruptedException { System.out.println("!!! cfsm: exit"); } catch (InterruptedException interruptedException) { System.out.println("!!! cfsm: interrupted"); - Thread.currentThread().interrupt(); + currentThread().interrupt(); childFSMStateWasInterrupted.set(true); } }) @@ -1552,7 +1553,7 @@ public void testChildrenDoneEvent() throws InterruptedException { System.out.println("!!! s2: exit"); } catch (InterruptedException interruptedException) { System.out.println("!!! s2: interrupt"); - Thread.currentThread().interrupt(); + currentThread().interrupt(); s2WasInterrupted.set(true); } }) @@ -2421,7 +2422,7 @@ public void nestedFSM() throws InterruptedException, ExecutionException { : AsyncFSMExecutor.ExecutionMode.PARALLEL_REGIONS; System.out.println("> running executor with " + mode.name() + ", n-child-fsms: " + numberOFChildren); - var executor = FSMExecutors.newAsyncExecutor(fsm, AsyncFSMExecutor.ExecutionMode.PARALLEL_REGIONS); + var executor = FSMExecutors.newAsyncExecutor(fsm, mode); executor.startAsync(); @@ -3154,4 +3155,241 @@ public void exitVsFinalTest() { // +--------------------------------------------+ } + + @Test(timeout = 5_000) + public void simpleToggleStateAndCountTest() { + + // +---------------+ +----------------+ +-----+ + // | A | | B | | C | + // | <-------------+ +------------> | + // | do: wait(100);| state-done/ | do: wait(100); | state-done | | + // | count++; | count(); + + // create storage + var storage = Storage.newInstance(); + int n = 10; + storage.storeValue("n", n); + + // create the states of the fsm + + var I = State.newBuilder() + .withName("I") + .withOnEntryActions((s, e) -> { + var msg = "entered state " + s.getName(); + System.out.println(msg); + list.add(msg); + storage.storeValue("count", 0); + }) + .withOnExitActions((s, e) -> { + var msg = "exited state " + s.getName(); + System.out.println(msg); + list.add(msg); + }) + .build(); + + var A = State.newBuilder() + .withName("A") + .withOnEntryActions((s, e) -> { + var msg = "entered state " + s.getName(); + System.out.println(msg); + list.add(msg); + }) + .withDoAction((s, e) -> { + var msg = "do action in state " + s.getName(); + System.out.println(msg); + list.add(msg); + try { + Thread.sleep(100); + storage.updateValue("count", (id, count) -> (int)count + 1); + } catch (InterruptedException ex) { + currentThread().interrupt(); + } + }) + .withOnExitActions((s, e) -> { + var msg = "exited state " + s.getName(); + System.out.println(msg); + list.add(msg); + }) + .build(); + + var B = State.newBuilder() + .withName("B") + .withOnEntryActions((s, e) -> { + var msg = "entered state " + s.getName(); + System.out.println(msg); + list.add(msg); + }) + .withDoAction((s, e) -> { + var msg = "do action in state " + s.getName(); + System.out.println(msg); + list.add(msg); + try { + Thread.sleep(100); + } catch (InterruptedException ex) { + currentThread().interrupt(); + } + }) + .withOnExitActions((s, e) -> { + var msg = "exited state " + s.getName(); + System.out.println(msg); + list.add(msg); + }) + .build(); + + var C = State.newBuilder() + .withName("C") + .withOnEntryActions((s, e) -> { + var msg = "entered state " + s.getName(); + System.out.println(msg); + list.add(msg); + }) + .withOnExitActions((s, e) -> { + var msg = "exited state " + s.getName(); + System.out.println(msg); + list.add(msg); + }) + .build(); + + // create the fsm + var root = FSM.newBuilder() + .withName("root") + .withInitialState(I) + .withOwnedState(I,A, B, C) + .withFinalState(C) + .withTransitions( + Transition.newBuilder() + .withTrigger(FSMExecutor.FSMEvents.STATE_DONE.getName()) + .withSource(I) + .withTarget(A) + .build(), + Transition.newBuilder() + .withTrigger(FSMExecutor.FSMEvents.STATE_DONE.getName()) + .withSource(A) + .withTarget(B) + .build(), + Transition.newBuilder() + .withTrigger(FSMExecutor.FSMEvents.STATE_DONE.getName()) + .withSource(C) + .withTarget(A) + .build(), + Transition.newBuilder() + .withTrigger(FSMExecutor.FSMEvents.STATE_DONE.getName()) + .withSource(B) + .withTarget(A) + .withGuard((s, e) -> (int)storage.getValue("count").get() < (int)storage.getValue("n").get()) + .build(), + Transition.newBuilder() + .withTrigger(FSMExecutor.FSMEvents.STATE_DONE.getName()) + .withSource(B) + .withTarget(C) + .build() + ) + .withVerbose(true) + .build(); + + // create the executor + var executor = FSMExecutors.newAsyncExecutor(root, MODE); + storage.addListener(executor); + executor.startAndWait(); + + Assert.assertEquals(n, storage.getValue("count").get()); + + // assert the list + Assert.assertEquals(List.of( + "entered state I", + "exited state I", + + // #1 + "entered state A", + "do action in state A", + "exited state A", + "entered state B", + "do action in state B", + "exited state B", + + // #2 + "entered state A", + "do action in state A", + "exited state A", + "entered state B", + "do action in state B", + "exited state B", + + // #3 + "entered state A", + "do action in state A", + "exited state A", + "entered state B", + "do action in state B", + "exited state B", + + // #4 + "entered state A", + "do action in state A", + "exited state A", + "entered state B", + "do action in state B", + "exited state B", + + // #5 + "entered state A", + "do action in state A", + "exited state A", + "entered state B", + "do action in state B", + "exited state B", + + // #6 + "entered state A", + "do action in state A", + "exited state A", + "entered state B", + "do action in state B", + "exited state B", + + // #7 + "entered state A", + "do action in state A", + "exited state A", + "entered state B", + "do action in state B", + "exited state B", + + // #8 + "entered state A", + "do action in state A", + "exited state A", + "entered state B", + "do action in state B", + "exited state B", + + // #9 + "entered state A", + "do action in state A", + "exited state A", + "entered state B", + "do action in state B", + "exited state B", + + // #10 + "entered state A", + "do action in state A", + "exited state A", + "entered state B", + "do action in state B", + "exited state B", + + "entered state C", + "exited state C" + ), list); + + + } }