View Javadoc

1   /**
2    * Copyright 2005-2013 The Kuali Foundation
3    *
4    * Licensed under the Educational Community License, Version 2.0 (the "License");
5    * you may not use this file except in compliance with the License.
6    * You may obtain a copy of the License at
7    *
8    * http://www.opensource.org/licenses/ecl2.php
9    *
10   * Unless required by applicable law or agreed to in writing, software
11   * distributed under the License is distributed on an "AS IS" BASIS,
12   * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13   * See the License for the specific language governing permissions and
14   * limitations under the License.
15   */
16  package org.kuali.rice.kew.engine;
17  
18  
19  import static org.junit.Assert.assertEquals;
20  import static org.junit.Assert.assertNotNull;
21  import static org.junit.Assert.assertTrue;
22  
23  import java.util.Collection;
24  import java.util.Iterator;
25  import java.util.List;
26  import java.util.Set;
27  
28  import org.junit.Test;
29  import org.kuali.rice.kew.actionrequest.ActionRequestValue;
30  import org.kuali.rice.kew.api.WorkflowDocument;
31  import org.kuali.rice.kew.api.WorkflowDocumentFactory;
32  import org.kuali.rice.kew.api.action.ActionRequestStatus;
33  import org.kuali.rice.kew.engine.node.RouteNodeInstance;
34  import org.kuali.rice.kew.service.KEWServiceLocator;
35  import org.kuali.rice.kew.test.KEWTestCase;
36  import org.kuali.rice.kew.api.KewApiConstants;
37  
38  public class ParallelRoutingTest extends KEWTestCase {
39      
40      private static final String DOCUMENT_TYPE_NAME = "ParallelDocType";
41      private static final String PARALLEL_EMPTY_DOCUMENT_TYPE_NAME = "ParallelEmptyDocType";
42      private static final String PARALLEL_EMPTY_DOCUMENT_TYPE_2_NAME = "ParallelEmptyDocType2";
43      private static final String ACKNOWLEDGE_1_NODE = "Acknowledge1";
44      private static final String WORKFLOW_DOCUMENT_2_NODE = "WorkflowDocument2";
45      private static final String WORKFLOW_DOCUMENT_3_NODE = "WorkflowDocument3";
46      private static final String JOIN_NODE = "Join";
47      private static final String WORKFLOW_DOCUMENT_FINAL_NODE = "WorkflowDocumentFinal";
48  	
49      protected void loadTestData() throws Exception {
50          loadXmlFile("EngineConfig.xml");
51      }
52  
53      @Test public void testParallelRoute() throws Exception {
54          WorkflowDocument document = WorkflowDocumentFactory.createDocument(getPrincipalIdForName("ewestfal"), DOCUMENT_TYPE_NAME);
55          document.saveDocumentData();
56          assertTrue("Document should be initiated", document.isInitiated());
57          assertEquals("Should be no action requests.", 0, document.getRootActionRequests().size());
58          Collection nodeInstances = KEWServiceLocator.getRouteNodeService().getActiveNodeInstances(document.getDocumentId());
59          assertEquals("Wrong number of active nodes.", 1, nodeInstances.size());
60          document.route("Routing for parallel");
61          
62          // should have generated a request to "bmcgough"
63          document = WorkflowDocumentFactory.loadDocument(getPrincipalIdForName("bmcgough"), document.getDocumentId());
64          assertTrue("Document should be enroute", document.isEnroute());
65          List actionRequests = KEWServiceLocator.getActionRequestService().findPendingByDoc(document.getDocumentId());
66          assertEquals("Incorrect pending action requests.", 1, actionRequests.size());
67          ActionRequestValue bRequest = (ActionRequestValue)actionRequests.get(0);
68          assertNotNull("Should have been routed through node instance.", bRequest.getNodeInstance());
69          assertTrue(document.isApprovalRequested());
70          
71          document.approve("Approving test");
72          
73          // document should split at this point and generate an ack to temay and approves to rkirkend and pmckown
74          document = WorkflowDocumentFactory.loadDocument(getPrincipalIdForName("rkirkend"), document.getDocumentId());
75          assertTrue("Document should be enroute", document.isEnroute());
76          actionRequests = KEWServiceLocator.getActionRequestService().findPendingByDoc(document.getDocumentId());
77          assertEquals("Incorrect pending action requests.", 3, actionRequests.size());
78          boolean isToTemay = false;
79          boolean isToPmckown = false;
80          boolean isToRkirkend = false;
81          for (Iterator iterator = actionRequests.iterator(); iterator.hasNext();) {
82              ActionRequestValue actionRequest = (ActionRequestValue) iterator.next();
83              if (actionRequest.getPrincipalId().equals(getPrincipalIdForName("temay"))) {
84                  isToTemay = true;
85                  assertEquals("Request should be activated.", ActionRequestStatus.ACTIVATED.getCode(), actionRequest.getStatus());
86                  assertEquals("Wrong action requested.", KewApiConstants.ACTION_REQUEST_ACKNOWLEDGE_REQ, actionRequest.getActionRequested());
87                  assertNotNull("Should have been routed through node instance.", actionRequest.getNodeInstance());
88                  assertEquals("Invalid node.", ACKNOWLEDGE_1_NODE, actionRequest.getNodeInstance().getRouteNode().getRouteNodeName());
89              }
90              if (actionRequest.getPrincipalId().equals(getPrincipalIdForName("rkirkend"))) {
91                  isToRkirkend = true;
92                  assertEquals("Request should be activated.", ActionRequestStatus.ACTIVATED.getCode(), actionRequest.getStatus());
93                  assertEquals("Wrong action requested.", KewApiConstants.ACTION_REQUEST_APPROVE_REQ, actionRequest.getActionRequested());
94                  assertNotNull("Should have been routed through node instance.", actionRequest.getNodeInstance());
95                  assertEquals("Invalid node.", WORKFLOW_DOCUMENT_2_NODE, actionRequest.getNodeInstance().getRouteNode().getRouteNodeName());
96              }
97              if (actionRequest.getPrincipalId().equals(getPrincipalIdForName("pmckown"))) {
98                  isToPmckown = true;
99                  assertEquals("Request should be activated.", ActionRequestStatus.ACTIVATED.getCode(), actionRequest.getStatus());
100                 assertEquals("Wrong action requested.", KewApiConstants.ACTION_REQUEST_APPROVE_REQ, actionRequest.getActionRequested());
101                 assertNotNull("Should have been routed through node instance.", actionRequest.getNodeInstance());
102                 assertEquals("Invalid node.", WORKFLOW_DOCUMENT_3_NODE, actionRequest.getNodeInstance().getRouteNode().getRouteNodeName());
103             }
104         }
105         assertTrue("No request to temay.", isToTemay);
106         assertTrue("No request to pmckown.", isToPmckown);
107         assertTrue("No request to rkirkend.", isToRkirkend);
108         
109         // check that we are at both nodes, one in each branch
110         Set<String> nodeNames = document.getNodeNames();
111         assertEquals("Wrong number of node names.", 2, nodeNames.size() );
112         boolean isNode2 = false;
113         boolean isNode3 = false;
114         for (String name : nodeNames) {
115             if (name.equals(WORKFLOW_DOCUMENT_2_NODE)) {
116                 isNode2 = true;
117             }
118             if (name.equals(WORKFLOW_DOCUMENT_3_NODE)) {
119                 isNode3 = true;
120             }
121         }
122         assertTrue("Not at node2.", isNode2);
123         assertTrue("Not at node3.", isNode3);
124         nodeInstances = KEWServiceLocator.getRouteNodeService().getActiveNodeInstances(document.getDocumentId());
125         assertEquals("Wrong number of active nodes.", 2, nodeInstances.size());
126         Iterator iterator = nodeInstances.iterator();
127         RouteNodeInstance instance1 = (RouteNodeInstance)iterator.next();
128         RouteNodeInstance instance2 = (RouteNodeInstance)iterator.next();
129         assertNotNull("Node should be in branch.", instance1.getBranch());
130         assertNotNull("Node should be in branch.", instance2.getBranch());
131         assertTrue("Branches should be different.", !instance1.getBranch().getBranchId().equals(instance2.getBranch().getBranchId()));
132         
133         document = WorkflowDocumentFactory.loadDocument(getPrincipalIdForName("rkirkend"), document.getDocumentId());
134         assertTrue("Should have request.", document.isApprovalRequested());
135         document.approve("Git-r-dun");
136         
137         nodeInstances = KEWServiceLocator.getRouteNodeService().getActiveNodeInstances(document.getDocumentId());
138         assertEquals("Wrong number of active nodes.", 2, nodeInstances.size());
139         boolean isAtJoin = false;
140         boolean isAtWD3 = false;
141         for (Iterator iter = nodeInstances.iterator(); iter.hasNext();) {
142             RouteNodeInstance nodeInstance = (RouteNodeInstance) iter.next();
143             if (nodeInstance.getRouteNode().getRouteNodeName().equals(JOIN_NODE)) {
144                 assertEquals("Join branch should be split branch.", instance1.getBranch().getParentBranch().getBranchId(), nodeInstance.getBranch().getBranchId());
145                 isAtJoin = true;
146             }
147             if (nodeInstance.getRouteNode().getRouteNodeName().equals(WORKFLOW_DOCUMENT_3_NODE)) {
148                 isAtWD3 = true;
149             }
150         }
151         assertTrue("Not at join", isAtJoin);
152         assertTrue("Not at WD3", isAtWD3);
153         
154         document = WorkflowDocumentFactory.loadDocument(getPrincipalIdForName("pmckown"), document.getDocumentId());
155         assertTrue("Should have request.", document.isApprovalRequested());
156         document.approve("Do it.");
157         
158         nodeInstances = KEWServiceLocator.getRouteNodeService().getActiveNodeInstances(document.getDocumentId());
159         assertEquals("Wrong number of active nodes.", 1, nodeInstances.size());
160         boolean isAtWDF = false;
161         for (Iterator iter = nodeInstances.iterator(); iter.hasNext();) {
162             RouteNodeInstance nodeInstance = (RouteNodeInstance) iter.next();
163             if (nodeInstance.getRouteNode().getRouteNodeName().equals(WORKFLOW_DOCUMENT_FINAL_NODE)) {
164                 isAtWDF = true;
165             }
166         }
167         assertTrue("Not at WDF", isAtWDF);
168         
169         document = WorkflowDocumentFactory.loadDocument(getPrincipalIdForName("xqi"), document.getDocumentId());
170         assertTrue("Should still be enroute.", document.isEnroute());
171         assertTrue("Should have request.", document.isApprovalRequested());
172         document.approve("I'm the last approver");
173         
174         assertTrue("Document should be processed.", document.isProcessed());
175         nodeInstances = KEWServiceLocator.getRouteNodeService().getActiveNodeInstances(document.getDocumentId());
176         //commented out because the final RouteNodeInstance is now not active when the doc goes final
177 //        assertEquals("Wrong number of active nodes.", 1, nodeInstances.size());
178 //        isAtWDF = false;
179 //        for (Iterator iter = nodeInstances.iterator(); iter.hasNext();) {
180 //            RouteNodeInstance nodeInstance = (RouteNodeInstance) iter.next();
181 //            if (nodeInstance.getRouteNode().getRouteNodeName().equals(WORKFLOW_DOCUMENT_FINAL_NODE)) {
182 //                isAtWDF = true;
183 //            }
184 //        }
185 //        assertTrue("Not at WDF", isAtWDF);
186         
187         document = WorkflowDocumentFactory.loadDocument(getPrincipalIdForName("temay"), document.getDocumentId());
188         assertTrue("Should have request.", document.isAcknowledgeRequested());
189         document.acknowledge("");
190         assertTrue(document.isFinal());
191     }
192     
193     /**
194      * Tests that the document route past the join properly when there are parallel branches that don't generate requests.
195      * This was coded in response to a bug found while testing with ERA in order to track it down and fix it.
196      */
197     @Test public void testEmptyParallelBranches() throws Exception {
198         
199         WorkflowDocument document = WorkflowDocumentFactory.createDocument(getPrincipalIdForName("ewestfal"), PARALLEL_EMPTY_DOCUMENT_TYPE_NAME);
200         document.saveDocumentData();
201         assertTrue("Document should be initiated", document.isInitiated());
202         assertEquals("Should be no action requests.", 0, document.getRootActionRequests().size());
203         Collection<? extends Object> nodeInstances = KEWServiceLocator.getRouteNodeService().getActiveNodeInstances(document.getDocumentId());
204         assertEquals("Wrong number of active nodes.", 1, nodeInstances.size());
205         document.route("");
206         
207         // should have generated a request to "bmcgough"
208         document = WorkflowDocumentFactory.loadDocument(getPrincipalIdForName("bmcgough"), document.getDocumentId());
209         assertTrue("Document should be enroute", document.isEnroute());
210         List actionRequests = KEWServiceLocator.getActionRequestService().findPendingByDoc(document.getDocumentId());
211         assertEquals("Incorrect pending action requests.", 1, actionRequests.size());
212         ActionRequestValue bRequest = (ActionRequestValue)actionRequests.get(0);
213         assertNotNull("Should have been routed through node instance.", bRequest.getNodeInstance());
214         assertTrue(document.isApprovalRequested());
215         
216         document.approve("");
217         
218         // now the document should have split, passed through nodes in each branch which didn't generate requests,
219         // and then passed the join node and generated requests at WorkflowDocumentFinal
220         document = WorkflowDocumentFactory.loadDocument(getPrincipalIdForName("xqi"), document.getDocumentId());
221         assertTrue("Document should be enroute", document.isEnroute());
222         assertTrue(document.isApprovalRequested());
223         
224     }
225     
226     /**
227      * This runs the test with the adhoc approvers branch second instead of first
228      *//*
229     public void testEmptyParallelBranchesSwitched() throws Exception {
230         
231         WorkflowDocument document = WorkflowDocumentFactory.createDocument(new NetworkIdVO("ewestfal"), PARALLEL_EMPTY_DOCUMENT_TYPE_2_NAME);
232         document.saveDocumentData();
233         assertTrue("Document should be initiated", document.isInitiated());
234         assertEquals("Should be no action requests.", 0, document.getActionRequests().length);
235         assertEquals("Invalid route level.", new Integer(0), document.getRouteHeader().getDocRouteLevel());
236         Collection nodeInstances = SpringServiceLocator.getRouteNodeService().getActiveNodeInstances(document.getDocumentId());
237         assertEquals("Wrong number of active nodes.", 1, nodeInstances.size());
238         document.route("");
239         
240         // should have generated a request to "bmcgough"
241         document = WorkflowDocumentFactory.loadDocument(new NetworkIdVO("bmcgough"), document.getDocumentId());
242         assertTrue("Document should be enroute", document.isEnroute());
243         List actionRequests = TestUtilities.getActionRequestService().findPendingByDoc(document.getDocumentId());
244         assertEquals("Incorrect pending action requests.", 1, actionRequests.size());
245         ActionRequestValue bRequest = (ActionRequestValue)actionRequests.get(0);
246         assertNotNull("Should have been routed through node instance.", bRequest.getRouteNodeInstance());
247         assertTrue(document.isApprovalRequested());
248         
249         document.approve("");
250         
251         // now the document should have split, passed through nodes in each branch which didn't generate requests,
252         // and then passed the join node and generated requests at WorkflowDocumentFinal
253         document = WorkflowDocumentFactory.loadDocument(new NetworkIdVO("xqi"), document.getDocumentId());
254         assertTrue("Document should be enroute", document.isEnroute());
255         assertTrue(document.isApprovalRequested());
256         
257     }*/
258     
259     @Test public void testAdhocApproversJoinScenario() throws Exception {
260         WorkflowDocument document = WorkflowDocumentFactory.createDocument(getPrincipalIdForName("ewestfal"), "AdHocApproversDocType");
261         document.route("");
262         
263         // should send an approve to bmcgough
264         document = WorkflowDocumentFactory.loadDocument(getPrincipalIdForName("bmcgough"), document.getDocumentId());
265         assertTrue("Bmcgough should have approve request.", document.isApprovalRequested());
266         document.approve("");
267         
268         // at this point the document should pass the split, and end up at the WorkflowDocument2 node and the AdHocApproversJoin node
269         // after bypassing the AdHocJoinPoint
270         Set<String> nodeNames = document.getNodeNames();
271         assertEquals("There should be two node names.", 2, nodeNames.size());
272         assertTrue("Should be at WorkflowDocument2 node.", nodeNames.contains("WorkflowDocument2"));
273         assertTrue("Should be at WorkflowDocument2 node.", nodeNames.contains("AdHocApproversJoin"));
274         
275         // pmckown has the request at the adhoc approvers node, if we approve as him then the document should _not_ transition out
276         // of it's current nodes
277         document = WorkflowDocumentFactory.loadDocument(getPrincipalIdForName("pmckown"), document.getDocumentId());
278         assertTrue("Pmckown should have approve request.", document.isApprovalRequested());
279         document.approve("");
280         
281         // the document should still be at the same nodes
282         nodeNames = document.getNodeNames();
283         assertEquals("There should be two node names.", 2, nodeNames.size());
284         assertTrue("Should be at WorkflowDocument2 node.", nodeNames.contains("WorkflowDocument2"));
285         assertTrue("Should be at WorkflowDocument2 node.", nodeNames.contains("AdHocApproversJoin"));
286     
287         // at WorkflowDocument2, rkirkend is the approver, if we approve as him we should end up at the WorkflowDocumentFinal node
288         document = WorkflowDocumentFactory.loadDocument(getPrincipalIdForName("rkirkend"), document.getDocumentId());
289         assertTrue("Rkirkend should have approve request.", document.isApprovalRequested());
290         document.approve("");
291         
292         // the document should now be at WorkflowDocumentFinal with a request to xqi
293         nodeNames = document.getNodeNames();
294         assertEquals("There should be one node name.", 1, nodeNames.size());
295         assertTrue("Should be at WorkflowDocumentFinal node.", nodeNames.contains("WorkflowDocumentFinal"));
296         
297         document = WorkflowDocumentFactory.loadDocument(getPrincipalIdForName("xqi"), document.getDocumentId());
298         assertTrue("Document should still be enroute.", document.isEnroute());
299         document.approve("");
300         assertTrue("Document should now be final.", document.isFinal());
301         
302     }
303     
304 }