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: Deadline.java,v 1.3 2007/03/27 21:59:43 mlipp Exp $
021: *
022: * $Log: Deadline.java,v $
023: * Revision 1.3 2007/03/27 21:59:43 mlipp
024: * Fixed lots of checkstyle warnings.
025: *
026: * Revision 1.2 2006/09/29 12:32:07 drmlipp
027: * Consistently using WfMOpen as projct name now.
028: *
029: * Revision 1.1.1.1 2003/12/19 13:01:43 drmlipp
030: * Updated to 1.1rc1
031: *
032: * Revision 1.11 2003/12/02 15:59:28 lipp
033: * Fixed timing problem.
034: *
035: * Revision 1.10 2003/11/04 08:37:32 schlue
036: * Deadline tests for block activities and subflows added.
037: *
038: * Revision 1.9 2003/10/21 21:00:45 lipp
039: * Moved EJBClientTest to new junit sub-package.
040: *
041: * Revision 1.8 2003/10/08 12:39:40 huaiyang
042: * make test weblogic compatible.
043: *
044: * Revision 1.7 2003/09/26 14:41:37 schlue
045: * New test cases for deadline added.
046: *
047: * Revision 1.6 2003/09/25 14:58:27 schlue
048: * Deadline tests fixed.
049: *
050: * Revision 1.5 2003/09/25 14:37:47 schlue
051: * Deadline tests fixed.
052: *
053: * Revision 1.4 2003/09/25 13:57:28 lipp
054: * Fixed.
055: *
056: * Revision 1.3 2003/09/25 13:41:42 schlue
057: * Deadline tests added.
058: *
059: * Revision 1.2 2003/09/19 15:05:00 schlue
060: * Call to stateReached fixed.
061: *
062: * Revision 1.1 2003/09/19 15:01:34 schlue
063: * Initial deadline test added (not working yet).
064: *
065: *
066: *
067: */
068: package process;
069:
070: import java.io.BufferedReader;
071: import java.io.InputStream;
072: import java.io.InputStreamReader;
073: import java.rmi.RemoteException;
074: import java.util.Date;
075: import java.util.Iterator;
076:
077: import junit.framework.Test;
078: import junit.framework.TestSuite;
079: import de.danet.an.util.junit.EJBClientTest;
080: import de.danet.an.workflow.api.Activity;
081: import de.danet.an.workflow.api.DefaultRequester;
082: import de.danet.an.workflow.api.ImportException;
083: import de.danet.an.workflow.api.PrioritizedMessage;
084: import de.danet.an.workflow.api.ProcessDefinitionDirectory;
085: import de.danet.an.workflow.api.ProcessDirectory;
086: import de.danet.an.workflow.api.ProcessMgr;
087: import de.danet.an.workflow.api.WorkflowService;
088: import de.danet.an.workflow.api.WorkflowServiceFactory;
089: import de.danet.an.workflow.omgcore.WfProcess;
090: import de.danet.an.workflow.omgcore.WfRequester;
091: import de.danet.an.workflow.omgcore.ProcessData;
092:
093: /**
094: * Test of Deadlines within workflow processes.
095: * After completion, all previously created processes and process definitions
096: * are removed.
097: * @author <a href="mailto:schlueter@danet.de">Holger Schlueter</a>
098: * @version 1.0
099: */
100: public class Deadline extends WfMOpenTestCase {
101: /**
102: * Access to process definition directory (singleton)
103: */
104: private ProcessDefinitionDirectory defDir = null;
105:
106: /**
107: * Access to process directory (singleton)
108: */
109: private ProcessDirectory procDir = null;
110:
111: /**
112: * Access to default requester (singleton)
113: */
114: private WfRequester requester = null;
115:
116: /**
117: * Constructor of this TestCase
118: * @param name a <code>String</code> value
119: */
120: public Deadline(String name) {
121: super (name);
122: }
123:
124: /**
125: * Construct this test suite.
126: * @return a <code>Test</code> value
127: */
128: public static Test suite() {
129: TestSuite suite = new TestSuite();
130: suite.addTest(new Deadline("timeoutSynchr"));
131: suite.addTest(new Deadline("timeoutASynchr"));
132: suite.addTest(new Deadline("timeoutLoop"));
133: suite.addTest(new Deadline("timeoutSuspend"));
134: suite.addTest(new Deadline("timeoutBlock"));
135: suite.addTest(new Deadline("timeoutSubflow"));
136: return new EJBClientTest(plc, suite);
137: }
138:
139: /**
140: * Test synchronous deadline execution. Explicit named exception are
141: * tested as well as default exception if no match is found.
142: * @exception Exception if an error occurs
143: */
144: public void timeoutSynchr() throws Exception {
145: ProcessMgr mgr = defDir.processMgr("SystemTest",
146: "timeoutSynchr");
147: WfProcess proc = mgr.createProcess(requester);
148: String procKey = proc.key();
149: proc.start();
150: assertTrue(stateReached(proc, "closed.completed"));
151: ProcessData data = proc.processContext();
152: String path = (String) data.get("TransitionPath");
153: assertTrue(path, path.equals("PATH:act1:act2:to"));
154: procDir.removeProcess(proc);
155:
156: mgr = defDir.processMgr("SystemTest", "timeoutSynchrDefault");
157: proc = mgr.createProcess(requester);
158: procKey = proc.key();
159: proc.start();
160: assertTrue(stateReached(proc, "closed.completed"));
161: data = proc.processContext();
162: path = (String) data.get("TransitionPath");
163: assertTrue(path, path.equals("PATH:act1:act2:def"));
164: procDir.removeProcess(proc);
165: }
166:
167: /**
168: * Test asynchronous deadline execution.
169: * @exception Exception if an error occurs
170: */
171: public void timeoutASynchr() throws Exception {
172: ProcessMgr mgr = defDir.processMgr("SystemTest",
173: "timeoutASynchr");
174: WfProcess proc = mgr.createProcess(requester);
175: String procKey = proc.key();
176: proc.start();
177: assertTrue(stateReached(proc, "closed.completed"));
178: ProcessData data = proc.processContext();
179: String path = (String) data.get("TransitionPath");
180: assertTrue(path, path.equals("PATH:act1:to1:to2:to3"));
181: procDir.removeProcess(proc);
182: }
183:
184: /**
185: * Test deadline execution in combination with loops.
186: * @exception Exception if an error occurs
187: */
188: public void timeoutLoop() throws Exception {
189: ProcessMgr mgr = defDir.processMgr("SystemTest", "timeoutLoop");
190: WfProcess proc = mgr.createProcess(requester);
191: String procKey = proc.key();
192: proc.start();
193: assertTrue(stateReached(proc, "closed.completed"));
194: ProcessData data = proc.processContext();
195: String path = (String) data.get("TransitionPath");
196: Long incr = (Long) data.get("increment");
197: assertTrue("I: " + incr + "; " + path, path
198: .equals("PATH:start:loop:to:loop:to:loop:end"));
199: procDir.removeProcess(proc);
200: }
201:
202: /**
203: * Test deadline execution in combination with suspension of
204: * activities and/or the process.
205: * @exception Exception if an error occurs
206: */
207: public void timeoutSuspend() throws Exception {
208: ProcessMgr mgr = defDir.processMgr("SystemTest",
209: "suspendStartMan");
210: WfProcess proc = mgr.createProcess(requester);
211: String procKey = proc.key();
212: proc.start();
213: assertTrue(stateReached(proc, "closed.completed"));
214: ProcessData data = proc.processContext();
215: String path = (String) data.get("TransitionPath");
216: assertTrue(path, path.equals("PATH:start:t1:t2:end"));
217: procDir.removeProcess(proc);
218:
219: mgr = defDir.processMgr("SystemTest", "suspendEndMan");
220: proc = mgr.createProcess(requester);
221: procKey = proc.key();
222: proc.start();
223: assertTrue(stateReached(proc, "closed.completed"));
224: data = proc.processContext();
225: path = (String) data.get("TransitionPath");
226: assertTrue(path, path.equals("PATH:start:a1:t1:a2:t2:end"));
227: procDir.removeProcess(proc);
228:
229: // One test case with two variants:
230: // 1. activity is suspended: (deadline is triggered after resume)
231: mgr = defDir.processMgr("SystemTest", "suspendAbsolute");
232: proc = mgr.createProcess(requester);
233: procKey = proc.key();
234: proc.start();
235: Activity act = null;
236: Iterator i = proc.steps().iterator();
237: while (i.hasNext()) {
238: act = (Activity) i.next();
239: if (act.name().equals("A1")) {
240: break;
241: }
242: }
243: assertTrue(act.state(), stateReached(act, "open.running"));
244: Thread.sleep(1000); // allow some time to invoke first tool
245: act.suspend();
246: data = proc.processContext();
247: path = (String) data.get("TransitionPath");
248: assertTrue(path, path.equals("PATH:start:a1"));
249: assertTrue(act.state(), stateReached(act,
250: "open.not_running.suspended"));
251: Thread.sleep(15000);
252: Date timestampRes = new Date();
253: act.resume();
254: assertTrue(act.state(), stateReached(act,
255: "closed.completed.abandoned"));
256: assertTrue(stateReached(proc, "closed.completed"));
257: data = proc.processContext();
258: path = (String) data.get("TransitionPath");
259: Date timestampTo = (Date) data.get("timestamp_to");
260: assertTrue(path, path.equals("PATH:start:a1:t1:end"));
261: assertTrue(timestampTo + ":" + timestampRes, timestampTo
262: .after(timestampRes));
263: procDir.removeProcess(proc);
264:
265: // 2. whole process is suspended: (deadline is triggered before resume
266: // but cannot be started until process is resumed)
267: proc = mgr.createProcess(requester);
268: procKey = proc.key();
269: proc.start();
270: act = null;
271: i = proc.steps().iterator();
272: while (i.hasNext()) {
273: act = (Activity) i.next();
274: if (act.name().equals("A1")) {
275: break;
276: }
277: }
278: assertTrue(act.state(), stateReached(act, "open.running"));
279: Thread.sleep(1000); // allow some time to invoke first tool
280: proc.suspend();
281: data = proc.processContext();
282: path = (String) data.get("TransitionPath");
283: assertTrue(path, path.equals("PATH:start:a1"));
284: assertTrue(act.state(), stateReached(act,
285: "closed.completed.abandoned"));
286: Thread.sleep(10000);
287: act = null;
288: i = proc.steps().iterator();
289: while (i.hasNext()) {
290: act = (Activity) i.next();
291: if (act.name().equals("TIMEOUT1")) {
292: break;
293: }
294: }
295: assertTrue(act.state(), stateReached(act,
296: "open.not_running.not_started"));
297: timestampRes = new Date();
298: proc.resume();
299: assertTrue(act.state(), stateReached(act, "closed.completed"));
300: assertTrue(act.state(), !proc.state().equals(
301: "closed.completed.abandoned"));
302: assertTrue(stateReached(proc, "closed.completed"));
303: data = proc.processContext();
304: path = (String) data.get("TransitionPath");
305: timestampTo = (Date) data.get("timestamp_to");
306: assertTrue(path, path.equals("PATH:start:a1:t1:end"));
307: assertTrue(timestampTo + ":" + timestampRes, !timestampTo
308: .before(timestampRes));
309: procDir.removeProcess(proc);
310: }
311:
312: /**
313: * Test deadline execution within block activity.
314: * @exception Exception if an error occurs
315: */
316: public void timeoutBlock() throws Exception {
317: ProcessMgr mgr = defDir
318: .processMgr("SystemTest", "timeoutBlock");
319: WfProcess proc = mgr.createProcess(requester);
320: String procKey = proc.key();
321: proc.start();
322: assertTrue(stateReached(proc, "closed.completed"));
323: ProcessData data = proc.processContext();
324: String path = (String) data.get("TransitionPath");
325: assertTrue(path, path.equals("PATH:start:a1:t1:a3:a2:t0:end"));
326: procDir.removeProcess(proc);
327: }
328:
329: /**
330: * Test deadline execution within subflows.
331: * @exception Exception if an error occurs
332: */
333: public void timeoutSubflow() throws Exception {
334: ProcessMgr mgr = defDir.processMgr("SystemTest",
335: "timeoutSubflow");
336: WfProcess proc = mgr.createProcess(requester);
337: String procKey = proc.key();
338: proc.start();
339: assertTrue(stateReached(proc, "closed.completed"));
340: ProcessData data = proc.processContext();
341: String path = (String) data.get("TransitionPath");
342: assertTrue(path, path.equals("PATH:start:a1:t1:a3:a2:t0:end"));
343: procDir.removeProcess(proc);
344: }
345:
346: /**
347: * Initialisation.
348: * The <code>setUp</code> method defines the way a state change is
349: * realized. Override this method to change this way.
350: * @exception Exception if an error occurs
351: */
352: protected void setUp() throws Exception {
353: super .setUp();
354: WorkflowService wfs = WorkflowServiceFactory.newInstance()
355: .newWorkflowService();
356: try {
357: defDir = wfs.processDefinitionDirectory();
358: } catch (RemoteException exc) {
359: System.err
360: .println("Process definition directory not accessible: "
361: + exc.getMessage());
362: System.exit(-1);
363: }
364:
365: procDir = wfs.processDirectory();
366: requester = new DefaultRequester(wfs);
367: importProcessDefinition("/process/deadline.xml");
368: }
369:
370: private void importProcessDefinition(String name) throws Exception {
371: StringBuffer processDefinition = new StringBuffer();
372: InputStream is = getClass().getResourceAsStream(name);
373: BufferedReader in = new BufferedReader(new InputStreamReader(
374: is, "ISO-8859-1"));
375: String line = null;
376: while ((line = in.readLine()) != null) {
377: processDefinition.append(line + "\n");
378: }
379: try {
380: defDir.importProcessDefinitions(processDefinition
381: .toString());
382: } catch (ImportException exc) {
383: Iterator msg = exc.messages().iterator();
384: while (msg.hasNext()) {
385: System.out.println(((PrioritizedMessage) msg.next())
386: .message());
387: }
388: }
389: }
390:
391: private boolean stateReached(WfProcess proc, String procState)
392: throws Exception {
393: boolean test = true;
394: boolean stateReached = false;
395: int maxRetries = 100;
396: while (test) {
397: if (maxRetries-- > 0) {
398: if (proc.state().startsWith(procState)) {
399: stateReached = true;
400: test = false;
401: } else {
402: Thread.sleep(500);
403: }
404: } else {
405: test = false;
406: }
407: }
408: return stateReached;
409: }
410:
411: private boolean stateReached(Activity act, String actState)
412: throws Exception {
413: boolean test = true;
414: boolean stateReached = false;
415: int maxRetries = 100;
416: while (test) {
417: if (maxRetries-- > 0) {
418: if (act.state().startsWith(actState)) {
419: stateReached = true;
420: test = false;
421: } else {
422: Thread.sleep(500);
423: }
424: } else {
425: test = false;
426: }
427: }
428: return stateReached;
429: }
430: }
|