001/*
002 * Licensed to the Apache Software Foundation (ASF) under one or more
003 * contributor license agreements.  See the NOTICE file distributed with
004 * this work for additional information regarding copyright ownership.
005 * The ASF licenses this file to You under the Apache License, Version 2.0
006 * (the "License"); you may not use this file except in compliance with
007 * the License.  You may obtain a copy of the License at
008 *
009 *     http://www.apache.org/licenses/LICENSE-2.0
010 *
011 * Unless required by applicable law or agreed to in writing, software
012 * distributed under the License is distributed on an "AS IS" BASIS,
013 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
014 * See the License for the specific language governing permissions and
015 * limitations under the License.
016 */
017package org.apache.commons.scxml2.model;
018
019import java.util.Iterator;
020import java.util.Set;
021
022import org.apache.commons.scxml2.SCXMLExecutor;
023import org.apache.commons.scxml2.SCXMLTestHelper;
024import org.apache.commons.scxml2.TriggerEvent;
025import org.junit.Assert;
026import org.junit.Test;
027/**
028 * Unit tests {@link org.apache.commons.scxml2.SCXMLExecutor}.
029 */
030public class StatelessModelTest {
031
032    /**
033     * Test the stateless model, simultaneous executions, JEXL expressions
034     */    
035    @Test
036    public void testStatelessModelSimultaneousJexl() throws Exception {
037        // parse once, use many times
038        SCXML scxml = SCXMLTestHelper.parse("org/apache/commons/scxml2/env/jexl/stateless-01.xml");
039        SCXMLExecutor exec01 = SCXMLTestHelper.getExecutor(scxml);
040        exec01.go();
041        SCXMLExecutor exec02 = SCXMLTestHelper.getExecutor(scxml);
042        exec02.go();
043        Assert.assertFalse(exec01 == exec02);
044        runSimultaneousTest(exec01, exec02);
045    }
046
047    /**
048     * Test the stateless model, sequential executions, JEXL expressions
049     */    
050    @Test
051    public void testStatelessModelSequentialJexl() throws Exception {
052        // rinse and repeat
053        SCXML scxml = SCXMLTestHelper.parse("org/apache/commons/scxml2/env/jexl/stateless-01.xml");
054        for (int i = 0; i < 3; i++) {
055            SCXMLExecutor exec01 = SCXMLTestHelper.getExecutor(scxml);
056            exec01.go();
057            runSequentialTest(exec01);
058        }
059    }
060
061    /**
062     * Test sharing a single SCXML object between two executors
063     */    
064    @Test
065    public void testStatelessModelParallelSharedSCXML() throws Exception {
066        SCXML scxml01par = SCXMLTestHelper.parse("org/apache/commons/scxml2/model/stateless-parallel-01.xml");
067        SCXMLExecutor exec01 = SCXMLTestHelper.getExecutor(scxml01par);
068        exec01.go();
069        SCXMLExecutor exec02 = SCXMLTestHelper.getExecutor(scxml01par);
070        exec02.go();
071        Assert.assertFalse(exec01 == exec02);
072
073        Set<EnterableState> currentStates = exec01.getStatus().getStates();
074        checkParallelStates(currentStates, "state1.init", "state2.init", "exec01");
075
076        currentStates = exec02.getStatus().getStates();
077        checkParallelStates(currentStates, "state1.init", "state2.init", "exec02");
078
079        currentStates = fireEvent("state1.event", exec01);
080        checkParallelStates(currentStates, "state1.final", "state2.init", "exec01");
081
082        currentStates = fireEvent("state2.event", exec02);
083        checkParallelStates(currentStates, "state1.init", "state2.final", "exec02");
084
085        currentStates = fireEvent("state2.event", exec01);
086        checkParallelStates(currentStates, "next", null, "exec01");
087
088        currentStates = fireEvent("state1.event", exec02);
089        checkParallelStates(currentStates, "next", null, "exec02");
090    }
091
092    /**
093     * TODO: Test sharing two SCXML objects between one executor (not recommended)
094     *
095    @Test
096    public void testStatelessModelParallelSwapSCXML() throws Exception {
097        SCXML scxml01par = SCXMLTestHelper.parse("org/apache/commons/scxml2/model/stateless-parallel-01.xml");
098        SCXML scxml02par = SCXMLTestHelper.parse("org/apache/commons/scxml2/model/stateless-parallel-01.xml");
099        SCXMLExecutor exec01 = SCXMLTestHelper.getExecutor(scxml01par);
100        exec01.go();
101        Assert.assertTrue(scxml01par != scxml02par);
102
103        Set<EnterableState> currentStates = exec01.getStatus().getStates();
104        checkParallelStates(currentStates, "state1.init", "state2.init", "exec01");
105
106        currentStates = fireEvent("state1.event", exec01);
107        checkParallelStates(currentStates, "state1.final", "state2.init", "exec01");
108        exec01.setStateMachine(scxml02par);
109        exec01.addListener(scxml02par, new SimpleSCXMLListener());
110        currentStates = fireEvent("state2.event", exec01);
111        checkParallelStates(currentStates, "next", null, "exec01");
112    }
113     */
114
115    private void checkParallelStates(Set<EnterableState> currentStates,
116            String s1, String s2, String label) {
117        Iterator<EnterableState> i = currentStates.iterator();
118        Assert.assertTrue("Not enough states", i.hasNext());
119        String cs1 = i.next().getId();
120        String cs2;
121        if (s2 != null) {
122            Assert.assertTrue("Not enough states, found one state: " + cs1, i.hasNext());
123            cs2 = i.next().getId();
124            Assert.assertFalse("Too many states", i.hasNext());
125            if (s2.equals(cs2)) {
126                cs2 = null;
127            } else if (s1.equals(cs2)) {
128                cs2 = null;
129            } else {
130                Assert.fail(label + " in unexpected state " + cs2);
131            }
132        } else {
133            Assert.assertFalse("Too many states", i.hasNext());
134        }
135        if (s1 != null && s1.equals(cs1)) {
136            return;
137        }
138        if (s2 != null && s2.equals(cs1)) {
139            return;
140        }
141        Assert.fail(label + " in unexpected state " + cs1);
142    }
143
144    private void runSimultaneousTest(SCXMLExecutor exec01, SCXMLExecutor exec02) throws Exception {
145        //// Interleaved
146        // exec01
147        Set<EnterableState> currentStates = exec01.getStatus().getStates();
148        Assert.assertEquals(1, currentStates.size());
149        Assert.assertEquals("ten", currentStates.iterator().next().getId());
150        currentStates = fireEvent("done.state.ten", exec01);
151        Assert.assertEquals(1, currentStates.size());
152        Assert.assertEquals("twenty", currentStates.iterator().next().getId());
153        // exec02
154        currentStates = exec02.getStatus().getStates();
155        Assert.assertEquals(1, currentStates.size());
156        Assert.assertEquals("ten", currentStates.iterator().next().getId());
157        // exec01
158        currentStates = fireEvent("done.state.twenty", exec01);
159        Assert.assertEquals(1, currentStates.size());
160        Assert.assertEquals("thirty", currentStates.iterator().next().getId());
161        // exec02
162        currentStates = fireEvent("done.state.ten", exec02);
163        Assert.assertEquals(1, currentStates.size());
164        Assert.assertEquals("twenty", currentStates.iterator().next().getId());
165        currentStates = fireEvent("done.state.twenty", exec02);
166        Assert.assertEquals(1, currentStates.size());
167        Assert.assertEquals("thirty", currentStates.iterator().next().getId());
168    }
169
170    private void runSequentialTest(SCXMLExecutor exec) throws Exception {
171        Set<EnterableState> currentStates = exec.getStatus().getStates();
172        Assert.assertEquals(1, currentStates.size());
173        Assert.assertEquals("ten", (currentStates.iterator().
174            next()).getId());
175        currentStates = fireEvent("done.state.ten", exec);
176        Assert.assertEquals(1, currentStates.size());
177        Assert.assertEquals("twenty", (currentStates.iterator().
178            next()).getId());
179        currentStates = fireEvent("done.state.twenty", exec);
180        Assert.assertEquals(1, currentStates.size());
181        Assert.assertEquals("thirty", (currentStates.iterator().
182            next()).getId());
183    }
184
185    private Set<EnterableState> fireEvent(String name, SCXMLExecutor exec) throws Exception {
186        TriggerEvent[] evts = {new TriggerEvent(name, TriggerEvent.SIGNAL_EVENT, null)};
187        exec.triggerEvents(evts);
188        return exec.getStatus().getStates();
189    }
190}
191