1   /*
2    * Licensed to the Apache Software Foundation (ASF) under one or more
3    * contributor license agreements.  See the NOTICE file distributed with
4    * this work for additional information regarding copyright ownership.
5    * The ASF licenses this file to You under the Apache License, Version 2.0
6    * (the "License"); you may not use this file except in compliance with
7    * the License.  You may obtain a copy of the License at
8    *
9    *     http://www.apache.org/licenses/LICENSE-2.0
10   *
11   * Unless required by applicable law or agreed to in writing, software
12   * distributed under the License is distributed on an "AS IS" BASIS,
13   * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14   * See the License for the specific language governing permissions and
15   * limitations under the License.
16   */
17  package org.apache.commons.scxml.model;
18  
19  import java.net.URL;
20  import java.util.Iterator;
21  import java.util.Set;
22  
23  import junit.framework.Test;
24  import junit.framework.TestCase;
25  import junit.framework.TestSuite;
26  import junit.textui.TestRunner;
27  
28  import org.apache.commons.scxml.SCXMLExecutor;
29  import org.apache.commons.scxml.SCXMLTestHelper;
30  import org.apache.commons.scxml.TriggerEvent;
31  import org.apache.commons.scxml.env.jsp.ELContext;
32  import org.apache.commons.scxml.env.jsp.ELEvaluator;
33  /***
34   * Unit tests {@link org.apache.commons.scxml.SCXMLExecutor}.
35   */
36  public class StatelessModelTest extends TestCase {
37      /***
38       * Construct a new instance of SCXMLExecutorTest with
39       * the specified name
40       */
41      public StatelessModelTest(String name) {
42          super(name);
43      }
44  
45      public static Test suite() {
46          TestSuite suite = new TestSuite(StatelessModelTest.class);
47          suite.setName("SCXML Executor Tests");
48          return suite;
49      }
50  
51      // Test data
52      private URL stateless01jexl, stateless01jsp, stateless01par;
53      private SCXML scxml01jexl, scxml01jsp, scxml01par, scxml02par;
54      private SCXMLExecutor exec01, exec02;
55  
56      /***
57       * Set up instance variables required by this test case.
58       */
59      public void setUp() {
60          stateless01jexl = this.getClass().getClassLoader().
61              getResource("org/apache/commons/scxml/env/jexl/stateless-01.xml");
62          stateless01jsp = this.getClass().getClassLoader().
63              getResource("org/apache/commons/scxml/env/jsp/stateless-01.xml");
64          stateless01par = this.getClass().getClassLoader().
65              getResource("org/apache/commons/scxml/model/stateless-parallel-01.xml");
66          scxml01jexl = SCXMLTestHelper.digest(stateless01jexl);
67          scxml01jsp = SCXMLTestHelper.digest(stateless01jsp);
68          scxml01par = SCXMLTestHelper.digest(stateless01par);
69          scxml02par = SCXMLTestHelper.digest(stateless01par);
70      }
71  
72      /***
73       * Tear down instance variables required by this test case.
74       */
75      public void tearDown() {
76          stateless01jexl = null;
77      }
78  
79      /***
80       * Test the stateless model, simultaneous executions, JEXL expressions
81       */
82      public void testStatelessModelSimultaneousJexl() {
83      	// parse once, use many times
84          exec01 = SCXMLTestHelper.getExecutor(scxml01jexl);
85          assertNotNull(exec01);
86          exec02 = SCXMLTestHelper.getExecutor(scxml01jexl);
87          assertNotNull(exec02);
88          assertFalse(exec01 == exec02);
89          runSimultaneousTest();
90      }
91  
92      /***
93       * Test the stateless model, sequential executions, JEXL expressions
94       */
95      public void testStatelessModelSequentialJexl() {
96          // rinse and repeat
97          for (int i = 0; i < 3; i++) {
98              exec01 = SCXMLTestHelper.getExecutor(scxml01jexl);
99              assertNotNull(exec01);
100             runSequentialTest();
101         }
102     }
103 
104     /***
105      * Test the stateless model, simultaneous executions, EL expressions
106      */
107     public void testStatelessModelSimultaneousEl() {
108     	// parse once, use many times
109         exec01 = SCXMLTestHelper.getExecutor(scxml01jsp,
110             new ELContext(), new ELEvaluator());
111         assertNotNull(exec01);
112         exec02 = SCXMLTestHelper.getExecutor(scxml01jsp,
113             new ELContext(), new ELEvaluator());
114         assertNotNull(exec02);
115         assertFalse(exec01 == exec02);
116         runSimultaneousTest();
117     }
118 
119     /***
120      * Test the stateless model, sequential executions, EL expressions
121      */
122     public void testStatelessModelSequentialEl() {
123         // rinse and repeat
124         for (int i = 0; i < 3; i++) {
125             exec01 = SCXMLTestHelper.getExecutor(scxml01jsp,
126                 new ELContext(), new ELEvaluator());
127             assertNotNull(exec01);
128             runSequentialTest();
129         }
130     }
131 
132     /***
133      * Test sharing a single SCXML object between two executors
134      */
135     public void testStatelessModelParallelSharedSCXML() {
136         exec01 = SCXMLTestHelper.getExecutor(scxml01par);
137         assertNotNull(exec01);
138         exec02 = SCXMLTestHelper.getExecutor(scxml01par);
139         assertNotNull(exec02);
140         assertFalse(exec01 == exec02);
141 
142         Set currentStates = exec01.getCurrentStatus().getStates();
143         checkParallelStates(currentStates, "state1.init", "state2.init", "exec01");
144 
145         currentStates = exec02.getCurrentStatus().getStates();
146         checkParallelStates(currentStates, "state1.init", "state2.init", "exec02");
147 
148         currentStates = fireEvent("state1.event", exec01);
149         checkParallelStates(currentStates, "state1.final", "state2.init", "exec01");
150 
151         currentStates = fireEvent("state2.event", exec02);
152         checkParallelStates(currentStates, "state1.init", "state2.final", "exec02");
153 
154         currentStates = fireEvent("state2.event", exec01);
155         checkParallelStates(currentStates, "next", null, "exec01");
156 
157         currentStates = fireEvent("state1.event", exec02);
158         checkParallelStates(currentStates, "next", null, "exec02");
159     }
160 
161     /***
162      * Test sharing two SCXML objects between one executor (not recommended)
163      */
164     public void testStatelessModelParallelSwapSCXML() {
165         exec01 = SCXMLTestHelper.getExecutor(scxml01par);
166         assertNotNull(exec01);
167         assertTrue(scxml01par != scxml02par);
168 
169         Set currentStates = exec01.getCurrentStatus().getStates();
170         checkParallelStates(currentStates, "state1.init", "state2.init", "exec01");
171 
172         currentStates = fireEvent("state1.event", exec01);
173         checkParallelStates(currentStates, "state1.final", "state2.init", "exec01");
174         exec01.setStateMachine(scxml02par);
175 
176         currentStates = fireEvent("state2.event", exec01);
177         checkParallelStates(currentStates, "next", null, "exec01");
178     }
179 
180     private void checkParallelStates(Set currentStates, String s1, String s2,
181             String label) {
182         Iterator i = currentStates.iterator();
183         assertTrue("Not enough states", i.hasNext());
184         String cs1 = ((State) i.next()).getId();
185         String cs2 = null;
186         if (s2 != null) {
187             assertTrue("Not enough states, found one state: " + cs1, i.hasNext());
188             cs2 = ((State) i.next()).getId();
189             assertFalse("Too many states", i.hasNext());
190             if (s2.equals(cs2)) {
191                 cs2 = null;
192             } else if (s1.equals(cs2)) {
193                 cs2 = null;
194             } else {
195                 fail(label + " in unexpected state " + cs2);
196             }
197         } else {
198             assertFalse("Too many states", i.hasNext());
199         }
200         if (s1 != null && s1.equals(cs1)) {
201             return;
202         }
203         if (s2 != null && s2.equals(cs1)) {
204             return;
205         }
206         fail(label + " in unexpected state " + cs1);
207     }
208 
209     private void runSimultaneousTest() {
210         try {
211             //// Interleaved
212             // exec01
213             Set currentStates = exec01.getCurrentStatus().getStates();
214             assertEquals(1, currentStates.size());
215             assertEquals("ten", ((State)currentStates.iterator().
216                 next()).getId());
217             currentStates = fireEvent("ten.done", exec01);
218             assertEquals(1, currentStates.size());
219             assertEquals("twenty", ((State)currentStates.iterator().
220                 next()).getId());
221             // exec02
222             currentStates = exec02.getCurrentStatus().getStates();
223             assertEquals(1, currentStates.size());
224             assertEquals("ten", ((State)currentStates.iterator().
225                 next()).getId());
226             // exec01
227             currentStates = fireEvent("twenty.done", exec01);
228             assertEquals(1, currentStates.size());
229             assertEquals("thirty", ((State)currentStates.iterator().
230                 next()).getId());
231             // exec02
232             currentStates = fireEvent("ten.done", exec02);
233             assertEquals(1, currentStates.size());
234             assertEquals("twenty", ((State)currentStates.iterator().
235                 next()).getId());
236             currentStates = fireEvent("twenty.done", exec02);
237             assertEquals(1, currentStates.size());
238             assertEquals("thirty", ((State)currentStates.iterator().
239                 next()).getId());
240         } catch (Exception e) {
241             fail(e.getMessage());
242         }
243     }
244 
245     private void runSequentialTest() {
246         try {
247             Set currentStates = exec01.getCurrentStatus().getStates();
248             assertEquals(1, currentStates.size());
249             assertEquals("ten", ((State)currentStates.iterator().
250                 next()).getId());
251             currentStates = fireEvent("ten.done", exec01);
252             assertEquals(1, currentStates.size());
253             assertEquals("twenty", ((State)currentStates.iterator().
254                 next()).getId());
255             currentStates = fireEvent("twenty.done", exec01);
256             assertEquals(1, currentStates.size());
257             assertEquals("thirty", ((State)currentStates.iterator().
258                 next()).getId());
259         } catch (Exception e) {
260             fail(e.getMessage());
261         }    	
262     }
263 
264     private Set fireEvent(String name, SCXMLExecutor exec) {
265         TriggerEvent[] evts = {new TriggerEvent(name,
266                 TriggerEvent.SIGNAL_EVENT, null)};
267         try {
268             exec.triggerEvents(evts);
269         } catch (Exception e) {
270             fail(e.getMessage());
271         }
272         return exec.getCurrentStatus().getStates();
273     }
274 
275     public static void main(String args[]) {
276         TestRunner.run(suite());
277     }
278 }
279