001: /*
002: * This file is part of the WfMOpen project.
003: * Copyright (C) 2001-2003 Danet GmbH (www.danet.de), GS-AN.
004: * All rights reserved.
005: *
006: * This program is free software; you can redistribute it and/or modify
007: * it under the terms of the GNU General Public License as published by
008: * the Free Software Foundation; either version 2 of the License, or
009: * (at your option) any later version.
010: *
011: * This program is distributed in the hope that it will be useful,
012: * but WITHOUT ANY WARRANTY; without even the implied warranty of
013: * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
014: * GNU General Public License for more details.
015: *
016: * You should have received a copy of the GNU General Public License
017: * along with this program; if not, write to the Free Software
018: * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
019: *
020: * $Id: Transition.java,v 1.4 2007/03/27 21:59:43 mlipp Exp $
021: *
022: * $Log: Transition.java,v $
023: * Revision 1.4 2007/03/27 21:59:43 mlipp
024: * Fixed lots of checkstyle warnings.
025: *
026: * Revision 1.3 2006/09/29 12:32:07 drmlipp
027: * Consistently using WfMOpen as projct name now.
028: *
029: * Revision 1.2 2004/09/10 11:53:15 drmlipp
030: * Made tests undividually runnable.
031: *
032: * Revision 1.1.1.2 2003/12/19 13:01:43 drmlipp
033: * Updated to 1.1rc1
034: *
035: * Revision 1.21 2003/10/21 21:00:45 lipp
036: * Moved EJBClientTest to new junit sub-package.
037: *
038: * Revision 1.20 2003/10/08 12:39:40 huaiyang
039: * make test weblogic compatible.
040: *
041: * Revision 1.19 2003/09/19 15:01:34 schlue
042: * Initial deadline test added (not working yet).
043: *
044: * Revision 1.18 2003/09/19 13:12:29 lipp
045: * Adapted to closed.completed having a substate.
046: *
047: * Revision 1.17 2003/06/29 18:41:19 lipp
048: * Minor fixes.
049: *
050: * Revision 1.16 2003/06/27 09:44:03 lipp
051: * Fixed copyright/license information.
052: *
053: * Revision 1.15 2003/06/03 14:50:12 schlue
054: * Test case for AND split with OTHERWISE condition added.
055: *
056: * Revision 1.14 2003/06/03 11:58:27 schlue
057: * PR56 fixed.
058: *
059: * Revision 1.13 2003/06/02 13:27:16 lipp
060: * Fixed PR35 (user error).
061: *
062: * Revision 1.12 2003/05/31 18:30:32 lipp
063: * Fixed test case.
064: *
065: * Revision 1.11 2003/05/16 14:13:12 schlue
066: * Cascade completed (still not running as intended)
067: *
068: * Revision 1.10 2003/05/16 10:45:55 schlue
069: * Loop test updated (still not running correctly)
070: *
071: * Revision 1.9 2003/05/15 11:23:42 schlue
072: * Added initial cascade test (still incomplete).
073: *
074: * Revision 1.8 2003/05/15 07:36:01 schlue
075: * Added first loop test.
076: *
077: * Revision 1.7 2003/05/14 12:02:26 schlue
078: * Import of process descriptions changed due to modified import behaviour.
079: *
080: * Revision 1.6 2003/05/08 10:50:28 schlue
081: * Initial subflow tests added.
082: *
083: * Revision 1.5 2003/05/05 14:39:50 lipp
084: * Moved code for removing process automatically to event handling.
085: *
086: * Revision 1.4 2003/04/17 14:13:28 schlue
087: * More complex transition test added.
088: *
089: * Revision 1.3 2003/04/16 19:58:49 lipp
090: * Adapted to jdk 1.4
091: *
092: * Revision 1.2 2003/04/16 14:06:50 schlue
093: * Transition path test added.
094: *
095: * Revision 1.1 2003/04/16 09:43:32 schlue
096: * Test cases for transition added.
097: *
098: *
099: */
100: package process;
101:
102: import java.io.BufferedReader;
103: import java.io.InputStream;
104: import java.io.InputStreamReader;
105:
106: import java.util.Iterator;
107: import java.util.List;
108:
109: import java.rmi.RemoteException;
110:
111: import de.danet.an.util.junit.EJBClientTest;
112:
113: import de.danet.an.workflow.omgcore.ProcessData;
114: import de.danet.an.workflow.omgcore.WfProcess;
115: import de.danet.an.workflow.omgcore.WfRequester;
116:
117: import de.danet.an.workflow.api.Activity;
118: import de.danet.an.workflow.api.DefaultRequester;
119: import de.danet.an.workflow.api.ImportException;
120: import de.danet.an.workflow.api.InvalidKeyException;
121: import de.danet.an.workflow.api.PrioritizedMessage;
122: import de.danet.an.workflow.api.ProcessDefinitionDirectory;
123: import de.danet.an.workflow.api.ProcessDirectory;
124: import de.danet.an.workflow.api.ProcessMgr;
125: import de.danet.an.workflow.api.WorkflowService;
126: import de.danet.an.workflow.api.WorkflowServiceFactory;
127:
128: import junit.framework.Test;
129: import junit.framework.TestResult;
130: import junit.framework.TestSuite;
131:
132: /**
133: * Test subject area of "transition" of processes.
134: * This includes conditions, complex split and join transition conditions,
135: * return values, etc.
136: * After completion, all previously created processes and process definitions
137: * are removed.
138: * @author <a href="mailto:schlueter@danet.de">Holger Schlueter</a>
139: * @version 1.0
140: */
141: public class Transition extends WfMOpenTestCase {
142: /**
143: * Access to process definition directory (singleton)
144: */
145: private ProcessDefinitionDirectory defDir = null;
146:
147: /**
148: * Access to process directory (singleton)
149: */
150: private ProcessDirectory procDir = null;
151:
152: /**
153: * Access to default requester (singleton)
154: */
155: private WfRequester requester = null;
156:
157: /**
158: * Constructor of this TestCase
159: * @param name a <code>String</code> value
160: */
161: public Transition(String name) {
162: super (name);
163: }
164:
165: /**
166: * Construct this test suite.
167: * @return a <code>Test</code> value
168: */
169: public static Test suite() {
170: TestSuite suite = new TestSuite();
171: suite.addTest(new Transition("testRun"));
172: suite.addTest(new Transition("testPath"));
173: suite.addTest(new Transition("testLoop"));
174: suite.addTest(new Transition("testCascade"));
175: suite.addTest(new Transition("testScrabble"));
176: suite.addTest(new Transition("testAndSplitOtherwise"));
177: return suite;
178: }
179:
180: /**
181: * Runs the tests with an appropriate login context.
182: *
183: * @param testResult a <code>TestResult</code> value
184: */
185: public void run(final TestResult testResult) {
186: EJBClientTest.run(new Runnable() {
187: public void run() {
188: Transition.super .run(testResult);
189: }
190: }, plc, testResult);
191: }
192:
193: /**
194: * Test creating a process, passing through and (automatically) removing.
195: * @exception Exception if an error occurs
196: */
197: public void testRun() throws Exception {
198: List msgList = importProcessDefinition("/process/minimal.xml");
199: ProcessMgr mgr = defDir.processMgr("SystemTest", "stopOnStart");
200: WfProcess proc = mgr.createProcess(requester);
201: String procKey = proc.key();
202: proc.start();
203: assertTrue(stateReached(proc, "open.running.running",
204: "open.not_running.suspended.suspended"));
205: Activity act = (Activity) proc.steps().toArray()[0];
206: act.resume();
207: assertTrue(stateReached(proc, "closed.completed",
208: "closed.completed"));
209: // Assure that process has to be removed manually
210: assertTrue(mgr.processByKey(procKey) != null);
211: procDir.removeProcess(proc);
212: boolean processRemoved = false;
213: try {
214: mgr.processByKey(procKey);
215: } catch (InvalidKeyException exc) {
216: processRemoved = true;
217: }
218: assertTrue(processRemoved);
219:
220: mgr = defDir.processMgr("SystemTest", "stopOnFinish");
221: proc = mgr.createProcess(requester);
222: procKey = proc.key();
223: proc.start();
224: assertTrue(stateReached(proc, "open.running.running",
225: "open.not_running.suspended.suspended"));
226: act = (Activity) proc.steps().toArray()[0];
227: act.resume();
228: assertTrue(stateReached(proc, "closed.completed",
229: "closed.completed"));
230: // Assure that process has to be removed manually
231: assertTrue(mgr.processByKey(procKey) != null);
232: procDir.removeProcess(proc);
233: processRemoved = false;
234: try {
235: mgr.processByKey(procKey);
236: } catch (InvalidKeyException exc) {
237: processRemoved = true;
238: }
239: assertTrue(processRemoved);
240:
241: mgr = defDir.processMgr("SystemTest", "completeNoRemoval");
242: proc = mgr.createProcess(requester);
243: procKey = proc.key();
244: proc.start();
245: assertTrue(stateReached(proc, "closed.completed",
246: "closed.completed"));
247: // Assure that process has to be removed manually
248: assertTrue(mgr.processByKey(procKey) != null);
249: procDir.removeProcess(proc);
250: processRemoved = false;
251: try {
252: mgr.processByKey(procKey);
253: } catch (InvalidKeyException exc) {
254: processRemoved = true;
255: }
256: assertTrue(processRemoved);
257:
258: mgr = defDir.processMgr("SystemTest", "completeRemoval");
259: proc = mgr.createProcess(requester);
260: procKey = proc.key();
261: proc.start();
262: // Assure that process has been removed automatically
263: processRemoved = false;
264: int maxRetries = 5;
265: boolean test = true;
266: while (test) {
267: if (maxRetries-- > 0) {
268: try {
269: mgr.processByKey(procKey);
270: Thread.sleep(1000);
271: } catch (InvalidKeyException exc) {
272: processRemoved = true;
273: test = false;
274: }
275: } else {
276: test = false;
277: }
278: }
279: assertTrue(processRemoved);
280: // Imported process definitions will be removed automatically by import
281: // within next test case!
282: }
283:
284: /**
285: * Test the transition path when executing processes.
286: * @exception Exception if an error occurs
287: */
288: public void testPath() throws Exception {
289: List msgList = importProcessDefinition("/process/transition1.xml");
290: ProcessMgr mgr = defDir.processMgr("SystemTest", "simplePath");
291: WfProcess proc = mgr.createProcess(requester);
292: proc.start();
293: // Wait for completion
294: assertTrue(stateReached(proc, "closed.completed",
295: "closed.completed"));
296: ProcessData data = proc.processContext();
297: assertTrue(((String) data.get("TransitionPath"))
298: .equals("PATH:act1:act2:act3"));
299: procDir.removeProcess(proc);
300:
301: mgr = defDir.processMgr("SystemTest", "block_2_in_2_out");
302: proc = mgr.createProcess(requester);
303: proc.start();
304: // Wait for completion
305: assertTrue("Process not completed in time", stateReached(proc,
306: "closed.completed", "closed.completed"));
307: data = proc.processContext();
308: assertTrue(((String) data.get("ConfirmA3")).equals("OK"));
309: assertTrue(((String) data.get("ConfirmA4")).equals("OK"));
310: procDir.removeProcess(proc);
311: defDir.removeProcessDefinition("SystemTest", "simplePath");
312: defDir
313: .removeProcessDefinition("SystemTest",
314: "block_2_in_2_out");
315: }
316:
317: /**
318: * Test conditional looping within a process.
319: * @exception Exception if an error occurs
320: */
321: public void testLoop() throws Exception {
322: StringBuffer processDefinition = new StringBuffer();
323: // Read correct process definition
324: InputStream is = getClass().getResourceAsStream(
325: "/process/loopNoStart.xml");
326: BufferedReader in = new BufferedReader(new InputStreamReader(
327: is, "ISO-8859-1"));
328: String line = null;
329: while ((line = in.readLine()) != null) {
330: processDefinition.append(line + "\n");
331: }
332: try {
333: List msg = defDir
334: .importProcessDefinitions(processDefinition
335: .toString());
336: assertTrue(msg.size() == 1);
337: assertTrue(((PrioritizedMessage) msg.get(0)).priority()
338: .equals(PrioritizedMessage.Priority.WARN));
339: assertTrue(((PrioritizedMessage) msg.get(0))
340: .unmappedMessage()
341: .equals("ImportMessages#procdef.transition.noentry"));
342: } catch (ImportException exc) {
343: Iterator msg = exc.messages().iterator();
344: while (msg.hasNext()) {
345: System.out.println(((PrioritizedMessage) msg.next())
346: .unmappedMessage());
347: }
348: }
349:
350: List msgList = importProcessDefinition("/process/loop.xml");
351: assertTrue(msgList.size() == 0);
352: ProcessMgr mgr = defDir
353: .processMgr("SystemTest", "loop_3_times");
354: WfProcess proc = mgr.createProcess(requester);
355: proc.start();
356: // Wait for completion
357: assertTrue(stateReached(proc, "closed.completed"));
358: ProcessData data = proc.processContext();
359: assertTrue(((Long) data.get("Counter")).intValue() == 3);
360: procDir.removeProcess(proc);
361: defDir.removeProcessDefinition("SystemTest", "loop_3_times");
362: }
363:
364: /**
365: * Test conditions by use of a cascading process.
366: * @exception Exception if an error occurs
367: */
368: public void testCascade() throws Exception {
369: // Uses XPDL imported by testLoop
370: ProcessMgr mgr = defDir.processMgr("SystemTest", "cascade");
371: WfProcess proc = mgr.createProcess(requester);
372: proc.start();
373: // Wait for completion
374: assertTrue(stateReached(proc, "closed.completed"));
375: ProcessData data = proc.processContext();
376: assertTrue(((Boolean) data.get("completed"))
377: .equals(Boolean.TRUE));
378: procDir.removeProcess(proc);
379: defDir.removeProcessDefinition("SystemTest", "cascade");
380: }
381:
382: /**
383: * Test conditions by use of a cascading process.
384: * @exception Exception if an error occurs
385: */
386: public void testScrabble() throws Exception {
387: // Uses XPDL imported by testLoop
388: ProcessMgr mgr = defDir.processMgr("SystemTest", "scrabble");
389: WfProcess proc = mgr.createProcess(requester);
390: proc.start();
391: // Wait for completion
392: assertTrue(stateReached(proc, "closed.completed"));
393: ProcessData data = proc.processContext();
394: assertTrue(((String) data.get("compound")).equals("DANET"));
395: procDir.removeProcess(proc);
396: defDir.removeProcessDefinition("SystemTest", "cascade");
397: }
398:
399: /**
400: * Test correct handling of OTHERWISE case within an AND split.
401: * @exception Exception if an error occurs
402: */
403: public void testAndSplitOtherwise() throws Exception {
404: // Uses XPDL imported by testLoop
405: ProcessMgr mgr = defDir.processMgr("SystemTest",
406: "andOtherwiseTest");
407: WfProcess proc = mgr.createProcess(requester);
408: proc.start();
409: // Wait for completion
410: assertTrue(stateReached(proc, "closed.completed"));
411: ProcessData data = proc.processContext();
412: assertTrue(((Boolean) data.get("Success")).equals(Boolean.TRUE));
413: assertTrue(((Boolean) data.get("Error")).equals(Boolean.FALSE));
414: procDir.removeProcess(proc);
415: defDir
416: .removeProcessDefinition("SystemTest",
417: "andOtherwiseTest");
418: }
419:
420: /**
421: * Initialisation.
422: * The <code>setUp</code> method defines the way a state change is
423: * realized. Override this method to change this way.
424: * @exception Exception if an error occurs
425: */
426: protected void setUp() throws Exception {
427: super .setUp();
428: WorkflowService wfs = WorkflowServiceFactory.newInstance()
429: .newWorkflowService();
430: try {
431: defDir = wfs.processDefinitionDirectory();
432: } catch (RemoteException exc) {
433: System.err
434: .println("Process definition directory not accessible: "
435: + exc.getMessage());
436: System.exit(-1);
437: }
438:
439: procDir = wfs.processDirectory();
440: requester = new DefaultRequester(wfs);
441: }
442:
443: private List importProcessDefinition(String name) throws Exception {
444: StringBuffer processDefinition = new StringBuffer();
445: List msgList = null;
446: InputStream is = getClass().getResourceAsStream(name);
447: BufferedReader in = new BufferedReader(new InputStreamReader(
448: is, "ISO-8859-1"));
449: String line = null;
450: while ((line = in.readLine()) != null) {
451: processDefinition.append(line + "\n");
452: }
453: try {
454: msgList = defDir.importProcessDefinitions(processDefinition
455: .toString());
456: } catch (ImportException exc) {
457: msgList = exc.messages();
458: Iterator msg = msgList.iterator();
459: while (msg.hasNext()) {
460: System.out.println(((PrioritizedMessage) msg.next())
461: .message());
462: }
463: }
464: return msgList;
465: }
466:
467: private boolean stateReached(WfProcess proc, String procState)
468: throws Exception {
469: boolean test = true;
470: boolean stateReached = false;
471: int maxRetries = 100;
472: while (test) {
473: if (maxRetries-- > 0) {
474: if (proc.state().startsWith(procState)) {
475: stateReached = true;
476: test = false;
477: } else {
478: Thread.sleep(1000);
479: }
480: } else {
481: test = false;
482: }
483: }
484: return stateReached;
485: }
486:
487: private boolean stateReached(WfProcess proc, String procState,
488: String actState) throws Exception {
489: Activity act = (Activity) proc.steps().toArray()[0];
490: boolean test = true;
491: boolean stateReached = false;
492: int maxRetries = 10;
493: while (test) {
494: if (maxRetries-- > 0) {
495: if (proc.state().startsWith(procState)
496: && act.state().startsWith(actState)) {
497: stateReached = true;
498: test = false;
499: } else {
500: Thread.sleep(1000);
501: }
502: } else {
503: test = false;
504: }
505: }
506: return stateReached;
507: }
508: }
|