001: /*
002: * Copyright 2005-2007 The Kuali Foundation.
003: *
004: *
005: * Licensed under the Educational Community License, Version 1.0 (the "License");
006: * you may not use this file except in compliance with the License.
007: * You may obtain a copy of the License at
008: *
009: * http://www.opensource.org/licenses/ecl1.php
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: */
017: package edu.iu.uis.eden.engine;
018:
019: import java.util.Arrays;
020: import java.util.Collection;
021: import java.util.HashSet;
022: import java.util.Iterator;
023: import java.util.List;
024: import java.util.Set;
025:
026: import org.junit.Test;
027: import org.kuali.workflow.test.WorkflowTestCase;
028:
029: import edu.iu.uis.eden.EdenConstants;
030: import edu.iu.uis.eden.KEWServiceLocator;
031: import edu.iu.uis.eden.actionrequests.ActionRequestValue;
032: import edu.iu.uis.eden.clientapp.WorkflowDocument;
033: import edu.iu.uis.eden.clientapp.vo.NetworkIdVO;
034: import edu.iu.uis.eden.engine.node.RouteNodeInstance;
035:
036: public class ParallelRoutingTest extends WorkflowTestCase {
037:
038: private static final String DOCUMENT_TYPE_NAME = "ParallelDocType";
039: private static final String PARALLEL_EMPTY_DOCUMENT_TYPE_NAME = "ParallelEmptyDocType";
040: private static final String ACKNOWLEDGE_1_NODE = "Acknowledge1";
041: private static final String WORKFLOW_DOCUMENT_2_NODE = "WorkflowDocument2";
042: private static final String WORKFLOW_DOCUMENT_3_NODE = "WorkflowDocument3";
043: private static final String JOIN_NODE = "Join";
044: private static final String WORKFLOW_DOCUMENT_FINAL_NODE = "WorkflowDocumentFinal";
045:
046: protected void loadTestData() throws Exception {
047: loadXmlFile("EngineConfig.xml");
048: }
049:
050: @Test
051: public void testParallelRoute() throws Exception {
052: WorkflowDocument document = new WorkflowDocument(
053: new NetworkIdVO("ewestfal"), DOCUMENT_TYPE_NAME);
054: document.saveRoutingData();
055: assertTrue("Document should be initiated", document
056: .stateIsInitiated());
057: assertEquals("Should be no action requests.", 0, document
058: .getActionRequests().length);
059: assertEquals("Invalid route level.", new Integer(0), document
060: .getRouteHeader().getDocRouteLevel());
061: Collection nodeInstances = KEWServiceLocator
062: .getRouteNodeService().getActiveNodeInstances(
063: document.getRouteHeaderId());
064: assertEquals("Wrong number of active nodes.", 1, nodeInstances
065: .size());
066: document.routeDocument("Routing for parallel");
067:
068: // should have generated a request to "bmcgough"
069: document = new WorkflowDocument(new NetworkIdVO("bmcgough"),
070: document.getRouteHeaderId());
071: assertTrue("Document should be enroute", document
072: .stateIsEnroute());
073: List actionRequests = KEWServiceLocator
074: .getActionRequestService().findPendingByDoc(
075: document.getRouteHeaderId());
076: assertEquals("Incorrect pending action requests.", 1,
077: actionRequests.size());
078: ActionRequestValue bRequest = (ActionRequestValue) actionRequests
079: .get(0);
080: assertNotNull("Should have been routed through node instance.",
081: bRequest.getNodeInstance());
082: assertTrue(document.isApprovalRequested());
083:
084: document.approve("Approving test");
085:
086: // document should split at this point and generate an ack to temay and approves to rkirkend and pmckown
087: document = new WorkflowDocument(new NetworkIdVO("rkirkend"),
088: document.getRouteHeaderId());
089: assertTrue("Document should be enroute", document
090: .stateIsEnroute());
091: actionRequests = KEWServiceLocator.getActionRequestService()
092: .findPendingByDoc(document.getRouteHeaderId());
093: assertEquals("Incorrect pending action requests.", 3,
094: actionRequests.size());
095: boolean isToTemay = false;
096: boolean isToPmckown = false;
097: boolean isToRkirkend = false;
098: for (Iterator iterator = actionRequests.iterator(); iterator
099: .hasNext();) {
100: ActionRequestValue actionRequest = (ActionRequestValue) iterator
101: .next();
102: if (actionRequest.getWorkflowUser()
103: .getAuthenticationUserId().getAuthenticationId()
104: .equals("temay")) {
105: isToTemay = true;
106: assertEquals("Request should be activated.",
107: EdenConstants.ACTION_REQUEST_ACTIVATED,
108: actionRequest.getStatus());
109: assertEquals("Wrong action requested.",
110: EdenConstants.ACTION_REQUEST_ACKNOWLEDGE_REQ,
111: actionRequest.getActionRequested());
112: assertNotNull(
113: "Should have been routed through node instance.",
114: actionRequest.getNodeInstance());
115: assertEquals("Invalid node.", ACKNOWLEDGE_1_NODE,
116: actionRequest.getNodeInstance().getRouteNode()
117: .getRouteNodeName());
118: }
119: if (actionRequest.getWorkflowUser()
120: .getAuthenticationUserId().getAuthenticationId()
121: .equals("rkirkend")) {
122: isToRkirkend = true;
123: assertEquals("Request should be activated.",
124: EdenConstants.ACTION_REQUEST_ACTIVATED,
125: actionRequest.getStatus());
126: assertEquals("Wrong action requested.",
127: EdenConstants.ACTION_REQUEST_APPROVE_REQ,
128: actionRequest.getActionRequested());
129: assertNotNull(
130: "Should have been routed through node instance.",
131: actionRequest.getNodeInstance());
132: assertEquals("Invalid node.", WORKFLOW_DOCUMENT_2_NODE,
133: actionRequest.getNodeInstance().getRouteNode()
134: .getRouteNodeName());
135: }
136: if (actionRequest.getWorkflowUser()
137: .getAuthenticationUserId().getAuthenticationId()
138: .equals("pmckown")) {
139: isToPmckown = true;
140: assertEquals("Request should be activated.",
141: EdenConstants.ACTION_REQUEST_ACTIVATED,
142: actionRequest.getStatus());
143: assertEquals("Wrong action requested.",
144: EdenConstants.ACTION_REQUEST_APPROVE_REQ,
145: actionRequest.getActionRequested());
146: assertNotNull(
147: "Should have been routed through node instance.",
148: actionRequest.getNodeInstance());
149: assertEquals("Invalid node.", WORKFLOW_DOCUMENT_3_NODE,
150: actionRequest.getNodeInstance().getRouteNode()
151: .getRouteNodeName());
152: }
153: }
154: assertTrue("No request to temay.", isToTemay);
155: assertTrue("No request to pmckown.", isToPmckown);
156: assertTrue("No request to rkirkend.", isToRkirkend);
157:
158: // check that we are at both nodes, one in each branch
159: String[] nodeNames = document.getNodeNames();
160: assertEquals("Wrong number of node names.", 2, nodeNames.length);
161: boolean isNode2 = false;
162: boolean isNode3 = false;
163: for (int index = 0; index < nodeNames.length; index++) {
164: String name = nodeNames[index];
165: if (name.equals(WORKFLOW_DOCUMENT_2_NODE)) {
166: isNode2 = true;
167: }
168: if (name.equals(WORKFLOW_DOCUMENT_3_NODE)) {
169: isNode3 = true;
170: }
171: }
172: assertTrue("Not at node2.", isNode2);
173: assertTrue("Not at node3.", isNode3);
174: nodeInstances = KEWServiceLocator.getRouteNodeService()
175: .getActiveNodeInstances(document.getRouteHeaderId());
176: assertEquals("Wrong number of active nodes.", 2, nodeInstances
177: .size());
178: Iterator iterator = nodeInstances.iterator();
179: RouteNodeInstance instance1 = (RouteNodeInstance) iterator
180: .next();
181: RouteNodeInstance instance2 = (RouteNodeInstance) iterator
182: .next();
183: assertNotNull("Node should be in branch.", instance1
184: .getBranch());
185: assertNotNull("Node should be in branch.", instance2
186: .getBranch());
187: assertTrue("Branches should be different.", !instance1
188: .getBranch().getBranchId().equals(
189: instance2.getBranch().getBranchId()));
190:
191: document = new WorkflowDocument(new NetworkIdVO("rkirkend"),
192: document.getRouteHeaderId());
193: assertTrue("Should have request.", document
194: .isApprovalRequested());
195: document.approve("Git-r-dun");
196:
197: nodeInstances = KEWServiceLocator.getRouteNodeService()
198: .getActiveNodeInstances(document.getRouteHeaderId());
199: assertEquals("Wrong number of active nodes.", 2, nodeInstances
200: .size());
201: boolean isAtJoin = false;
202: boolean isAtWD3 = false;
203: for (Iterator iter = nodeInstances.iterator(); iter.hasNext();) {
204: RouteNodeInstance nodeInstance = (RouteNodeInstance) iter
205: .next();
206: if (nodeInstance.getRouteNode().getRouteNodeName().equals(
207: JOIN_NODE)) {
208: assertEquals("Join branch should be split branch.",
209: instance1.getBranch().getParentBranch()
210: .getBranchId(), nodeInstance
211: .getBranch().getBranchId());
212: isAtJoin = true;
213: }
214: if (nodeInstance.getRouteNode().getRouteNodeName().equals(
215: WORKFLOW_DOCUMENT_3_NODE)) {
216: isAtWD3 = true;
217: }
218: }
219: assertTrue("Not at join", isAtJoin);
220: assertTrue("Not at WD3", isAtWD3);
221:
222: document = new WorkflowDocument(new NetworkIdVO("pmckown"),
223: document.getRouteHeaderId());
224: assertTrue("Should have request.", document
225: .isApprovalRequested());
226: document.approve("Do it.");
227:
228: nodeInstances = KEWServiceLocator.getRouteNodeService()
229: .getActiveNodeInstances(document.getRouteHeaderId());
230: assertEquals("Wrong number of active nodes.", 1, nodeInstances
231: .size());
232: boolean isAtWDF = false;
233: for (Iterator iter = nodeInstances.iterator(); iter.hasNext();) {
234: RouteNodeInstance nodeInstance = (RouteNodeInstance) iter
235: .next();
236: if (nodeInstance.getRouteNode().getRouteNodeName().equals(
237: WORKFLOW_DOCUMENT_FINAL_NODE)) {
238: isAtWDF = true;
239: }
240: }
241: assertTrue("Not at WDF", isAtWDF);
242:
243: document = new WorkflowDocument(new NetworkIdVO("xqi"),
244: document.getRouteHeaderId());
245: assertTrue("Should still be enroute.", document
246: .stateIsEnroute());
247: assertTrue("Should have request.", document
248: .isApprovalRequested());
249: document.approve("I'm the last approver");
250:
251: assertTrue("Document should be processed.", document
252: .stateIsProcessed());
253: nodeInstances = KEWServiceLocator.getRouteNodeService()
254: .getActiveNodeInstances(document.getRouteHeaderId());
255: //commented out because the final RouteNodeInstance is now not active when the doc goes final
256: // assertEquals("Wrong number of active nodes.", 1, nodeInstances.size());
257: // isAtWDF = false;
258: // for (Iterator iter = nodeInstances.iterator(); iter.hasNext();) {
259: // RouteNodeInstance nodeInstance = (RouteNodeInstance) iter.next();
260: // if (nodeInstance.getRouteNode().getRouteNodeName().equals(WORKFLOW_DOCUMENT_FINAL_NODE)) {
261: // isAtWDF = true;
262: // }
263: // }
264: // assertTrue("Not at WDF", isAtWDF);
265:
266: document = new WorkflowDocument(new NetworkIdVO("temay"),
267: document.getRouteHeaderId());
268: assertTrue("Should have request.", document
269: .isAcknowledgeRequested());
270: document.acknowledge("");
271: assertTrue(document.stateIsFinal());
272: }
273:
274: /**
275: * Tests that the document route past the join properly when there are parallel branches that don't generate requests.
276: * This was coded in response to a bug found while testing with ERA in order to track it down and fix it.
277: */
278: @Test
279: public void testEmptyParallelBranches() throws Exception {
280:
281: WorkflowDocument document = new WorkflowDocument(
282: new NetworkIdVO("ewestfal"),
283: PARALLEL_EMPTY_DOCUMENT_TYPE_NAME);
284: document.saveRoutingData();
285: assertTrue("Document should be initiated", document
286: .stateIsInitiated());
287: assertEquals("Should be no action requests.", 0, document
288: .getActionRequests().length);
289: assertEquals("Invalid route level.", new Integer(0), document
290: .getRouteHeader().getDocRouteLevel());
291: Collection nodeInstances = KEWServiceLocator
292: .getRouteNodeService().getActiveNodeInstances(
293: document.getRouteHeaderId());
294: assertEquals("Wrong number of active nodes.", 1, nodeInstances
295: .size());
296: document.routeDocument("");
297:
298: // should have generated a request to "bmcgough"
299: document = new WorkflowDocument(new NetworkIdVO("bmcgough"),
300: document.getRouteHeaderId());
301: assertTrue("Document should be enroute", document
302: .stateIsEnroute());
303: List actionRequests = KEWServiceLocator
304: .getActionRequestService().findPendingByDoc(
305: document.getRouteHeaderId());
306: assertEquals("Incorrect pending action requests.", 1,
307: actionRequests.size());
308: ActionRequestValue bRequest = (ActionRequestValue) actionRequests
309: .get(0);
310: assertNotNull("Should have been routed through node instance.",
311: bRequest.getNodeInstance());
312: assertTrue(document.isApprovalRequested());
313:
314: document.approve("");
315:
316: // now the document should have split, passed through nodes in each branch which didn't generate requests,
317: // and then passed the join node and generated requests at WorkflowDocumentFinal
318: document = new WorkflowDocument(new NetworkIdVO("xqi"),
319: document.getRouteHeaderId());
320: assertTrue("Document should be enroute", document
321: .stateIsEnroute());
322: assertTrue(document.isApprovalRequested());
323:
324: }
325:
326: /**
327: * This runs the test with the adhoc approvers branch second instead of first
328: */
329: /*
330: public void testEmptyParallelBranchesSwitched() throws Exception {
331:
332: WorkflowDocument document = new WorkflowDocument(new NetworkIdVO("ewestfal"), PARALLEL_EMPTY_DOCUMENT_TYPE_2_NAME);
333: document.saveRoutingData();
334: assertTrue("Document should be initiated", document.stateIsInitiated());
335: assertEquals("Should be no action requests.", 0, document.getActionRequests().length);
336: assertEquals("Invalid route level.", new Integer(0), document.getRouteHeader().getDocRouteLevel());
337: Collection nodeInstances = SpringServiceLocator.getRouteNodeService().getActiveNodeInstances(document.getRouteHeaderId());
338: assertEquals("Wrong number of active nodes.", 1, nodeInstances.size());
339: document.routeDocument("");
340:
341: // should have generated a request to "bmcgough"
342: document = new WorkflowDocument(new NetworkIdVO("bmcgough"), document.getRouteHeaderId());
343: assertTrue("Document should be enroute", document.stateIsEnroute());
344: List actionRequests = TestUtilities.getActionRequestService().findPendingByDoc(document.getRouteHeaderId());
345: assertEquals("Incorrect pending action requests.", 1, actionRequests.size());
346: ActionRequestValue bRequest = (ActionRequestValue)actionRequests.get(0);
347: assertNotNull("Should have been routed through node instance.", bRequest.getNodeInstance());
348: assertTrue(document.isApprovalRequested());
349:
350: document.approve("");
351:
352: // now the document should have split, passed through nodes in each branch which didn't generate requests,
353: // and then passed the join node and generated requests at WorkflowDocumentFinal
354: document = new WorkflowDocument(new NetworkIdVO("xqi"), document.getRouteHeaderId());
355: assertTrue("Document should be enroute", document.stateIsEnroute());
356: assertTrue(document.isApprovalRequested());
357:
358: }*/
359:
360: @Test
361: public void testAdhocApproversJoinScenario() throws Exception {
362: WorkflowDocument document = new WorkflowDocument(
363: new NetworkIdVO("ewestfal"), "AdHocApproversDocType");
364: document.routeDocument("");
365:
366: // should send an approve to bmcgough
367: document = new WorkflowDocument(new NetworkIdVO("bmcgough"),
368: document.getRouteHeaderId());
369: assertTrue("Bmcgough should have approve request.", document
370: .isApprovalRequested());
371: document.approve("");
372:
373: // at this point the document should pass the split, and end up at the WorkflowDocument2 node and the AdHocApproversJoin node
374: // after bypassing the AdHocJoinPoint
375: Set nodeNames = new HashSet(Arrays.asList(document
376: .getNodeNames()));
377: assertEquals("There should be two node names.", 2, nodeNames
378: .size());
379: assertTrue("Should be at WorkflowDocument2 node.", nodeNames
380: .contains("WorkflowDocument2"));
381: assertTrue("Should be at WorkflowDocument2 node.", nodeNames
382: .contains("AdHocApproversJoin"));
383:
384: // pmckown has the request at the adhoc approvers node, if we approve as him then the document should _not_ transition out
385: // of it's current nodes
386: document = new WorkflowDocument(new NetworkIdVO("pmckown"),
387: document.getRouteHeaderId());
388: assertTrue("Pmckown should have approve request.", document
389: .isApprovalRequested());
390: document.approve("");
391:
392: // the document should still be at the same nodes
393: nodeNames = new HashSet(Arrays.asList(document.getNodeNames()));
394: assertEquals("There should be two node names.", 2, nodeNames
395: .size());
396: assertTrue("Should be at WorkflowDocument2 node.", nodeNames
397: .contains("WorkflowDocument2"));
398: assertTrue("Should be at WorkflowDocument2 node.", nodeNames
399: .contains("AdHocApproversJoin"));
400:
401: // at WorkflowDocument2, rkirkend is the approver, if we approve as him we should end up at the WorkflowDocumentFinal node
402: document = new WorkflowDocument(new NetworkIdVO("rkirkend"),
403: document.getRouteHeaderId());
404: assertTrue("Rkirkend should have approve request.", document
405: .isApprovalRequested());
406: document.approve("");
407:
408: // the document should now be at WorkflowDocumentFinal with a request to xqi
409: nodeNames = new HashSet(Arrays.asList(document.getNodeNames()));
410: assertEquals("There should be one node name.", 1, nodeNames
411: .size());
412: assertTrue("Should be at WorkflowDocumentFinal node.",
413: nodeNames.contains("WorkflowDocumentFinal"));
414:
415: document = new WorkflowDocument(new NetworkIdVO("xqi"),
416: document.getRouteHeaderId());
417: assertTrue("Document should still be enroute.", document
418: .stateIsEnroute());
419: document.approve("");
420: assertTrue("Document should now be final.", document
421: .stateIsFinal());
422:
423: }
424:
425: }
|