View Javadoc
1   /**
2    * Copyright 2005-2014 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.actions;
17  
18  import mocks.MockEmailNotificationService;
19  import org.apache.cxf.common.util.StringUtils;
20  import org.junit.Ignore;
21  import org.junit.Test;
22  import org.kuali.rice.core.api.delegation.DelegationType;
23  import org.kuali.rice.kew.actionrequest.ActionRequestValue;
24  import org.kuali.rice.kew.actionrequest.service.ActionRequestService;
25  import org.kuali.rice.kew.api.KewApiConstants;
26  import org.kuali.rice.kew.api.WorkflowDocument;
27  import org.kuali.rice.kew.api.WorkflowDocumentFactory;
28  import org.kuali.rice.kew.api.action.InvalidActionTakenException;
29  import org.kuali.rice.kew.api.document.DocumentContentUpdate;
30  import org.kuali.rice.kew.api.document.PropertyDefinition;
31  import org.kuali.rice.kew.api.document.attribute.WorkflowAttributeDefinition;
32  import org.kuali.rice.kew.engine.node.RouteNodeInstance;
33  import org.kuali.rice.kew.engine.node.service.RouteNodeService;
34  import org.kuali.rice.kew.framework.postprocessor.DocumentRouteStatusChange;
35  import org.kuali.rice.kew.framework.postprocessor.ProcessDocReport;
36  import org.kuali.rice.kew.postprocessor.DefaultPostProcessor;
37  import org.kuali.rice.kew.rule.GenericWorkflowAttribute;
38  import org.kuali.rice.kew.service.KEWServiceLocator;
39  import org.kuali.rice.kew.test.KEWTestCase;
40  import org.kuali.rice.kew.test.TestUtilities;
41  import org.kuali.rice.kim.api.services.KimApiServiceLocator;
42  import org.kuali.rice.test.BaselineTestCase.BaselineMode;
43  import org.kuali.rice.test.BaselineTestCase.Mode;
44  
45  import java.util.Collection;
46  import java.util.HashMap;
47  import java.util.Iterator;
48  import java.util.List;
49  import java.util.Map;
50  
51  import static org.junit.Assert.*;
52  
53  @BaselineMode(Mode.CLEAR_DB)
54  public class BlanketApproveTest extends KEWTestCase {
55  
56      public static String TEST_USER_EWESTFAL = "ewestfal";
57      public static String TEST_USER_USER1 = "user1";
58      public static String TEST_USER_USER2 = "user2";
59      public static String TEST_USER_TEMAY = "temay";
60      public static String TEST_USER_JHOPF = "jhopf";
61      public static String TEST_USER_JITRUE = "jitrue";
62      public static String TEST_USER_JTHOMAS = "jthomas";
63      public static String TEST_USER_BMCGOUGH = "bmcgough";
64      public static String TEST_USER_RKIRKEND = "rkirkend";
65      public static String TEST_USER_PMCKOWN = "pmckown";
66      public static String TEST_USER_XQI = "xqi";
67      
68  	@Override
69      protected void loadTestData() throws Exception {
70          loadXmlFile("ActionsConfig.xml");
71      }
72      
73      /**
74       * When a user is not in the blanket approver workgroup an exception should be thrown and 
75       * it should have a good message.
76       * 
77       * @throws Exception
78       */
79      @Test public void testBlanketApproverNotInBlanketApproverWorkgroup() throws Exception  {
80      	WorkflowDocument document = WorkflowDocumentFactory.createDocument(getPrincipalIdForName(TEST_USER_USER1), SequentialSetup.DOCUMENT_TYPE_NAME);
81      	try {
82      		document.blanketApprove("");
83      		fail("InvalidActionTakenException should have been thrown");
84      	} catch (InvalidActionTakenException iate) {
85      		assertEquals("Exception on message is incorrent", "User is not authorized to BlanketApprove document", iate.getMessage());
86      	}
87          
88      }
89      
90      /**
91       * When a user is in the blanket approve workgroup but the user is not the initiator an exception
92       * should be thrown.
93       */
94      @Test public void testBlanketApproverNotInitiator() throws Exception  {
95          WorkflowDocument document = WorkflowDocumentFactory.createDocument(getPrincipalIdForName(TEST_USER_USER1), SequentialSetup.DOCUMENT_TYPE_NAME);
96          WorkflowDocument newDocument = WorkflowDocumentFactory.loadDocument(getPrincipalIdForName(TEST_USER_EWESTFAL), document.getDocumentId());
97          try {
98              newDocument.blanketApprove("");
99              fail("Exception should have been thrown when non-initiator user attempts blanket approve on default blanket approve policy document");
100         } catch (Exception e) {
101             e.printStackTrace();
102         }
103     }
104     
105     @SuppressWarnings("deprecation")
106 	@Test public void testBlanketApproveSequential() throws Exception {
107         WorkflowDocument document = WorkflowDocumentFactory.createDocument(getPrincipalIdForName(TEST_USER_EWESTFAL), SequentialSetup.DOCUMENT_TYPE_NAME);
108         document.blanketApprove("");
109         document = WorkflowDocumentFactory.loadDocument(getPrincipalIdForName(TEST_USER_EWESTFAL), document.getDocumentId());
110         assertTrue("Document should be processed.", document.isProcessed());
111         Collection nodeInstances = getRouteNodeService().getActiveNodeInstances(document.getDocumentId());
112         // once the document is processed there are no active nodes
113         assertEquals("Wrong number of active nodes.", 0, nodeInstances.size());
114         nodeInstances = getRouteNodeService().getTerminalNodeInstances(document.getDocumentId());
115         assertEquals("Wrong number of active nodes.", 1, nodeInstances.size());
116         RouteNodeInstance ackNodeInstance = (RouteNodeInstance)nodeInstances.iterator().next();
117         assertEquals("At wrong node.", SequentialSetup.ACKNOWLEDGE_2_NODE, ackNodeInstance.getRouteNode().getRouteNodeName());
118         assertTrue("Node should be complete.", ackNodeInstance.isComplete());
119         List actionRequests = KEWServiceLocator.getActionRequestService().findPendingByDoc(document.getDocumentId());
120         assertEquals("Wrong number of pending action requests.", 5, actionRequests.size());
121         boolean isNotification1 = false;
122         boolean isNotification2 = false;
123         boolean isNotification3 = false;
124         boolean isAck1 = false;
125         boolean isAck2 = false;
126         for (Iterator iterator = actionRequests.iterator(); iterator.hasNext();) {
127             ActionRequestValue actionRequest = (ActionRequestValue) iterator.next();
128             assertEquals("Should only be acknowledges.", KewApiConstants.ACTION_REQUEST_ACKNOWLEDGE_REQ, actionRequest.getActionRequested());
129             RouteNodeInstance nodeInstance = actionRequest.getNodeInstance();
130             assertNotNull(nodeInstance);
131             String nodeName = nodeInstance.getRouteNode().getRouteNodeName();
132             if (actionRequest.getPrincipalId().equals(getPrincipalIdForName(TEST_USER_BMCGOUGH))) {
133                 isNotification1 = true;
134                 assertEquals(SequentialSetup.WORKFLOW_DOCUMENT_NODE, nodeName);
135                 assertEquals(KewApiConstants.MACHINE_GENERATED_RESPONSIBILITY_ID, actionRequest.getResponsibilityId());
136             } else if (actionRequest.getPrincipalId().equals(getPrincipalIdForName(TEST_USER_RKIRKEND))) {
137                 isNotification2 = true;
138                 assertEquals(SequentialSetup.WORKFLOW_DOCUMENT_NODE, nodeName);
139                 assertEquals(KewApiConstants.MACHINE_GENERATED_RESPONSIBILITY_ID, actionRequest.getResponsibilityId());
140             } else if (actionRequest.getPrincipalId().equals(getPrincipalIdForName(TEST_USER_PMCKOWN))) {
141                 isNotification3 = true;
142                 assertEquals(SequentialSetup.WORKFLOW_DOCUMENT_2_NODE, nodeName);
143                 assertEquals(KewApiConstants.MACHINE_GENERATED_RESPONSIBILITY_ID, actionRequest.getResponsibilityId());
144             } else if (actionRequest.getPrincipalId().equals(getPrincipalIdForName(TEST_USER_TEMAY))) {
145                 isAck1 = true;
146                 assertEquals(SequentialSetup.ACKNOWLEDGE_1_NODE, nodeName);
147                 assertFalse(KewApiConstants.MACHINE_GENERATED_RESPONSIBILITY_ID.equals(actionRequest.getResponsibilityId()));
148             } else if (actionRequest.getPrincipalId().equals(getPrincipalIdForName(TEST_USER_JHOPF))) {
149                 isAck2 = true;
150                 assertEquals(SequentialSetup.ACKNOWLEDGE_2_NODE, nodeName);
151                 assertFalse(KewApiConstants.MACHINE_GENERATED_RESPONSIBILITY_ID.equals(actionRequest.getResponsibilityId()));
152             }
153         }
154         assertTrue(isNotification1);
155         assertTrue(isNotification2);
156         assertTrue(isNotification3);
157         assertTrue(isAck1);
158         assertTrue(isAck2);
159         document = WorkflowDocumentFactory.loadDocument(getPrincipalIdForName(TEST_USER_BMCGOUGH), document.getDocumentId());
160         assertTrue(document.isProcessed());
161         assertTrue(document.isAcknowledgeRequested());
162         assertEquals("bmcgough should not have been sent an approve email", 0, getMockEmailService().immediateReminderEmailsSent(TEST_USER_BMCGOUGH, document.getDocumentId(), KewApiConstants.ACTION_REQUEST_APPROVE_REQ));
163         assertEquals("bmcgough should not have been sent an ack email", 1, getMockEmailService().immediateReminderEmailsSent(TEST_USER_BMCGOUGH, document.getDocumentId(), KewApiConstants.ACTION_REQUEST_ACKNOWLEDGE_REQ));
164         document.acknowledge("");
165 
166         document = WorkflowDocumentFactory.loadDocument(getPrincipalIdForName(TEST_USER_RKIRKEND), document.getDocumentId());
167         assertTrue(document.isProcessed());
168         assertTrue(document.isAcknowledgeRequested());
169         assertEquals("rkirkend should not have been sent an approve email", 0, getMockEmailService().immediateReminderEmailsSent("rkirkend", document.getDocumentId(), KewApiConstants.ACTION_REQUEST_APPROVE_REQ));
170         assertEquals("rkirkend should not have been sent an ack email", 1, getMockEmailService().immediateReminderEmailsSent("rkirkend", document.getDocumentId(), KewApiConstants.ACTION_REQUEST_ACKNOWLEDGE_REQ));
171         document.acknowledge("");
172         
173         document = WorkflowDocumentFactory.loadDocument(getPrincipalIdForName(TEST_USER_PMCKOWN), document.getDocumentId());
174         assertTrue(document.isProcessed());
175         assertTrue(document.isAcknowledgeRequested());
176         assertEquals("pmckown should not have been sent an approve email", 0, getMockEmailService().immediateReminderEmailsSent("pmckown", document.getDocumentId(), KewApiConstants.ACTION_REQUEST_APPROVE_REQ));
177         assertEquals("pmckown should not have been sent an ack email", 1, getMockEmailService().immediateReminderEmailsSent("pmckown", document.getDocumentId(), KewApiConstants.ACTION_REQUEST_ACKNOWLEDGE_REQ));
178         document.acknowledge("");
179         
180         document = WorkflowDocumentFactory.loadDocument(getPrincipalIdForName(TEST_USER_TEMAY), document.getDocumentId());
181         assertTrue(document.isProcessed());
182         assertTrue(document.isAcknowledgeRequested());
183         assertEquals("rkirkend should have been sent an temay", 1, getMockEmailService().immediateReminderEmailsSent(TEST_USER_TEMAY, document.getDocumentId(), KewApiConstants.ACTION_REQUEST_ACKNOWLEDGE_REQ));
184         document.acknowledge("");
185         
186         document = WorkflowDocumentFactory.loadDocument(getPrincipalIdForName(TEST_USER_JHOPF), document.getDocumentId());
187         assertTrue(document.isProcessed());
188         assertTrue(document.isAcknowledgeRequested());
189         assertEquals("rkirkend should have been sent an jhopf", 1, getMockEmailService().immediateReminderEmailsSent(TEST_USER_JHOPF, document.getDocumentId(), KewApiConstants.ACTION_REQUEST_ACKNOWLEDGE_REQ));
190         document.acknowledge("");
191         
192         document = WorkflowDocumentFactory.loadDocument(getPrincipalIdForName(TEST_USER_EWESTFAL), document.getDocumentId());
193         assertTrue(document.isFinal());
194         
195         document = WorkflowDocumentFactory.createDocument(getPrincipalIdForName(TEST_USER_EWESTFAL), SequentialSetup.DOCUMENT_TYPE_NAME);
196         document.blanketApprove("", SequentialSetup.WORKFLOW_DOCUMENT_2_NODE);
197         assertTrue("Document should be enroute.", document.isEnroute());
198         nodeInstances = getRouteNodeService().getActiveNodeInstances(document.getDocumentId());
199         assertEquals("Should be one active node.", 1, nodeInstances.size());
200         RouteNodeInstance doc2Instance = (RouteNodeInstance)nodeInstances.iterator().next();
201         assertEquals("At wrong node.", SequentialSetup.WORKFLOW_DOCUMENT_2_NODE, doc2Instance.getRouteNode().getRouteNodeName());
202         
203     }
204     
205     @Test public void testBlanketApproveSequentialErrors() throws Exception {
206         // blanket approve to invalid node
207         WorkflowDocument document = WorkflowDocumentFactory.createDocument(getPrincipalIdForName(TEST_USER_EWESTFAL), SequentialSetup.DOCUMENT_TYPE_NAME);
208         try {
209             document.blanketApprove("", "TotallyInvalidNode");
210             fail("Should have thrown exception");
211         } catch (Exception e) {}
212         
213         // blanket approve backwards
214         document = WorkflowDocumentFactory.createDocument(getPrincipalIdForName(TEST_USER_EWESTFAL), SequentialSetup.DOCUMENT_TYPE_NAME);
215         document.blanketApprove("", SequentialSetup.WORKFLOW_DOCUMENT_2_NODE);
216         try {
217             document.blanketApprove("", SequentialSetup.WORKFLOW_DOCUMENT_NODE);
218             fail("Should have thrown exception");
219         } catch (Exception e) {}
220         
221         // blanket approve to current node
222         document = WorkflowDocumentFactory.createDocument(getPrincipalIdForName(TEST_USER_EWESTFAL), SequentialSetup.DOCUMENT_TYPE_NAME);
223         document.route("");
224         try {
225             document.blanketApprove("", SequentialSetup.WORKFLOW_DOCUMENT_NODE);
226             fail("Should have thrown exception");
227         } catch (Exception e) {}
228         
229         // blanket approve as user not in the blanket approve workgroup
230         document = WorkflowDocumentFactory.createDocument(getPrincipalIdForName(TEST_USER_USER1), SequentialSetup.DOCUMENT_TYPE_NAME);
231         try {
232             document.blanketApprove("");
233             fail("Shouldn't be able to blanket approve if not in blanket approve workgroup");
234         } catch (Exception e) {}
235     }
236     
237     @Test public void testBlanketApproveParallel() throws Exception {
238         WorkflowDocument document = WorkflowDocumentFactory.createDocument(getPrincipalIdForName(TEST_USER_EWESTFAL), ParallelSetup.DOCUMENT_TYPE_NAME);
239         document.blanketApprove("");        
240         document = WorkflowDocumentFactory.loadDocument(getPrincipalIdForName(TEST_USER_EWESTFAL), document.getDocumentId());
241         assertTrue("Document should be processed.", document.isProcessed());
242         Collection nodeInstances = getRouteNodeService().getActiveNodeInstances(document.getDocumentId());
243         // once the document has gone processed there are no active nodes
244         assertEquals("Wrong number of active nodes.", 0, nodeInstances.size());
245         nodeInstances = getRouteNodeService().getTerminalNodeInstances(document.getDocumentId());
246         assertEquals("Wrong number of terminal nodes.", 1, nodeInstances.size());
247         RouteNodeInstance ackNodeInstance = (RouteNodeInstance)nodeInstances.iterator().next();
248         assertEquals("At wrong node.", SequentialSetup.ACKNOWLEDGE_2_NODE, ackNodeInstance.getRouteNode().getRouteNodeName());
249         assertTrue("Node should be complete.", ackNodeInstance.isComplete());
250         List actionRequests = KEWServiceLocator.getActionRequestService().findPendingByDoc(document.getDocumentId());
251         assertEquals("Wrong number of pending action requests.", 10, actionRequests.size());
252 
253     }
254 
255     /**
256      * Test the blanket approval of a document chained by the post processor
257      *
258      * @throws Exception
259      */
260     @Ignore
261     @Test
262     public void testChainedBlanketApproval() throws Exception {
263         // Generate child document
264         WorkflowDocument childDocument = WorkflowDocumentFactory.createDocument(getPrincipalIdForName(TEST_USER_EWESTFAL), ChainedChildSetup.DOCUMENT_TYPE_NAME);
265         WorkflowAttributeDefinition.Builder childDocAttribute = WorkflowAttributeDefinition.Builder.create(ChainedParentSetup.CHILD_DOC_ATTRIBUTE);
266         PropertyDefinition docIdProperty = PropertyDefinition.create(
267                 ChainedParentSetup.DOC_ID_PROPERTY, childDocument.getDocumentId());
268         childDocAttribute.addPropertyDefinition(docIdProperty);
269 
270         // Generate a parent document, apply child attribute
271         WorkflowDocument parentDocument = WorkflowDocumentFactory.createDocument(getPrincipalIdForName(TEST_USER_EWESTFAL), ChainedParentSetup.DOCUMENT_TYPE_NAME);
272         //parentDocument.addAttributeDefinition(childDocAttribute.build());
273         //parentDocument.saveDocumentData();
274 
275         // Issue with attribute definition save
276         String fullContent = parentDocument.getDocumentContent().getFullContent();
277         String newContent = "<documentContent><attributeContent><documentId>" + childDocument.getDocumentId() + "</documentId></attributeContent></documentContent>";
278         DocumentContentUpdate.Builder documentContentUpdateBuilder = DocumentContentUpdate.Builder.create();
279         documentContentUpdateBuilder.setAttributeContent(newContent);
280         parentDocument.updateDocumentContent(documentContentUpdateBuilder.build());
281         parentDocument.saveDocumentData();
282 
283         parentDocument.blanketApprove("");
284         parentDocument = WorkflowDocumentFactory.loadDocument(getPrincipalIdForName(TEST_USER_EWESTFAL), parentDocument.getDocumentId());
285         assertTrue("Parent Document should be processed.", parentDocument.isProcessed());
286 
287         childDocument = WorkflowDocumentFactory.loadDocument(getPrincipalIdForName(TEST_USER_EWESTFAL), childDocument.getDocumentId());
288         assertTrue("Child Document should be processed.", childDocument.isProcessed());
289 
290     }
291     
292     @Test public void testBlanketApproveIntoBranch() throws Exception {
293         WorkflowDocument document = WorkflowDocumentFactory.createDocument(getPrincipalIdForName(TEST_USER_EWESTFAL), ParallelSetup.DOCUMENT_TYPE_NAME);
294         document.blanketApprove("", ParallelSetup.WORKFLOW_DOCUMENT_2_B1_NODE);
295         List actionRequests = KEWServiceLocator.getActionRequestService().findPendingByDoc(document.getDocumentId());
296         assertEquals("Wrong number of pending action requests.", 5, actionRequests.size());
297         
298         // document should now be at the node we blanket approved to and the join node
299         Collection activeNodes = getRouteNodeService().getActiveNodeInstances(document.getDocumentId());
300         assertEquals("Wrong number of active nodes.", 3, activeNodes.size());
301         boolean isAtWD2B1 = false;
302         boolean isAtJoin = false;
303         boolean isAtWD3B2 = false;
304         boolean isAtWD4B3 = false;
305         for (Iterator iterator = activeNodes.iterator(); iterator.hasNext();) {
306             RouteNodeInstance nodeInstance = (RouteNodeInstance) iterator.next();
307             isAtWD2B1 = isAtWD2B1 || nodeInstance.getName().equals(ParallelSetup.WORKFLOW_DOCUMENT_2_B1_NODE);
308             isAtWD3B2 = isAtWD3B2 || nodeInstance.getName().equals(ParallelSetup.WORKFLOW_DOCUMENT_3_B2_NODE);
309             isAtWD4B3 = isAtWD4B3 || nodeInstance.getName().equals(ParallelSetup.WORKFLOW_DOCUMENT_4_B3_NODE);
310             isAtJoin = isAtJoin || nodeInstance.getName().equals(ParallelSetup.JOIN_NODE);
311         }
312         assertTrue("Should be at blanket approved node.", isAtWD2B1);
313         assertTrue("Should be at blanket approved node WD3B2.", isAtWD3B2);
314         assertTrue("Should be at blanket approved node WD4B3.", isAtWD4B3);        
315         assertFalse("Should be at join node.", isAtJoin);
316         
317         document.blanketApprove("");
318         document = WorkflowDocumentFactory.loadDocument(getPrincipalIdForName(TEST_USER_EWESTFAL), document.getDocumentId());
319         assertTrue("Document should be processed.", document.isProcessed());
320         actionRequests = KEWServiceLocator.getActionRequestService().findPendingByDoc(document.getDocumentId());
321         
322         assertEquals("Wrong number of pending action requests.", 10, actionRequests.size());
323     }
324     
325     @Test public void testBlanketApproveToMultipleNodes() throws Exception {
326         
327         WorkflowDocument document = WorkflowDocumentFactory.createDocument(getPrincipalIdForName(TEST_USER_EWESTFAL), ParallelSetup.DOCUMENT_TYPE_NAME);
328         document.blanketApprove("", new String[] { ParallelSetup.WORKFLOW_DOCUMENT_2_B1_NODE, ParallelSetup.WORKFLOW_DOCUMENT_3_B2_NODE });
329         List actionRequests = KEWServiceLocator.getActionRequestService().findPendingByDoc(document.getDocumentId());
330         assertEquals("Wrong number of pending action requests.", 5, actionRequests.size());
331         
332         // document should now be at both nodes we blanket approved to and the join node
333         Collection activeNodes = getRouteNodeService().getActiveNodeInstances(document.getDocumentId());
334         assertEquals("Wrong number of active nodes.", 3, activeNodes.size());
335         boolean isAtWD2B1 = false;
336         boolean isAtWD3B2 = false;
337         boolean isAtJoin = false;
338         boolean isAtWD4B3 = false;
339         for (Iterator iterator = activeNodes.iterator(); iterator.hasNext();) {
340             RouteNodeInstance nodeInstance = (RouteNodeInstance) iterator.next();
341             isAtWD2B1 = isAtWD2B1 || nodeInstance.getName().equals(ParallelSetup.WORKFLOW_DOCUMENT_2_B1_NODE);
342             isAtWD3B2 = isAtWD3B2 || nodeInstance.getName().equals(ParallelSetup.WORKFLOW_DOCUMENT_3_B2_NODE);
343             isAtWD4B3 = isAtWD4B3 || nodeInstance.getName().equals(ParallelSetup.WORKFLOW_DOCUMENT_4_B3_NODE);
344             isAtJoin = isAtJoin || nodeInstance.getName().equals(ParallelSetup.JOIN_NODE);
345         }
346         assertTrue("Should be at blanket approved node WD2B1.", isAtWD2B1);
347         assertTrue("Should be at blanket approved node WD3B2.", isAtWD3B2);
348         assertTrue("Should be at blanket approved node WD4B3.  https://jira.kuali.org/browse/KULRICE-8481 - "
349                 + "BlanketApproveTest.testBlanketApproveToMultipleNodes fails in CI with Should be at blanket approved node WD4B3.", isAtWD4B3);
350         assertFalse("Should not be at join node.", isAtJoin);
351         
352         document.blanketApprove("");
353         document = WorkflowDocumentFactory.loadDocument(getPrincipalIdForName(TEST_USER_EWESTFAL), document.getDocumentId());
354         assertTrue("Document should be processed.", document.isProcessed());
355         actionRequests = KEWServiceLocator.getActionRequestService().findPendingByDoc(document.getDocumentId());
356         assertEquals("Wrong number of pending action requests.", 10, actionRequests.size());
357     }
358     
359     @Test public void testBlanketApproveToJoin() throws Exception {
360         WorkflowDocument document = WorkflowDocumentFactory.createDocument(getPrincipalIdForName(TEST_USER_EWESTFAL), ParallelSetup.DOCUMENT_TYPE_NAME);
361         document.blanketApprove("", ParallelSetup.JOIN_NODE);
362         assertTrue("Document should still be enroute.", document.isEnroute());
363 
364         // document should now be at the workflow document final node
365         Collection activeNodes = getRouteNodeService().getActiveNodeInstances(document.getDocumentId());
366         assertEquals("Wrong number of active nodes.", 1, activeNodes.size());
367         RouteNodeInstance nodeInstance = (RouteNodeInstance)activeNodes.iterator().next();
368         assertEquals("Document at wrong node.", ParallelSetup.WORKFLOW_DOCUMENT_FINAL_NODE, nodeInstance.getName());
369         
370         document = WorkflowDocumentFactory.loadDocument(getPrincipalIdForName(TEST_USER_XQI), document.getDocumentId());
371         assertTrue("Should have approve request.", document.isApprovalRequested());
372         document.blanketApprove("", ParallelSetup.ACKNOWLEDGE_1_NODE);
373         
374         activeNodes = getRouteNodeService().getActiveNodeInstances(document.getDocumentId());
375 
376         assertEquals("Wrong number of active nodes.", 0, activeNodes.size());
377         Collection terminalNodes = getRouteNodeService().getTerminalNodeInstances(document.getDocumentId());
378         assertEquals("Wrong number of terminal nodes.", 1, terminalNodes.size());
379         nodeInstance = (RouteNodeInstance)terminalNodes.iterator().next();
380         assertEquals("Document at wrong node.", ParallelSetup.ACKNOWLEDGE_2_NODE, nodeInstance.getName());
381         assertTrue("Final node not complete.", nodeInstance.isComplete());
382     }
383     
384     @Test public void testBlanketApproveToAcknowledge() throws Exception {
385         
386         WorkflowDocument document = WorkflowDocumentFactory.createDocument(getPrincipalIdForName(TEST_USER_EWESTFAL), ParallelSetup.DOCUMENT_TYPE_NAME);
387         document.blanketApprove("", ParallelSetup.ACKNOWLEDGE_1_NODE);
388         assertTrue("Document should be processed.", document.isProcessed());
389 
390         // document should now be terminal
391         Collection activeNodes = getRouteNodeService().getActiveNodeInstances(document.getDocumentId());
392         assertEquals("Wrong number of active nodes.", 0, activeNodes.size());
393         Collection terminalNodes = getRouteNodeService().getTerminalNodeInstances(document.getDocumentId());
394         assertEquals("Wrong number of terminal nodes.", 1, terminalNodes.size());
395         RouteNodeInstance nodeInstance = (RouteNodeInstance)terminalNodes.iterator().next();
396         assertEquals("Document at wrong node.", ParallelSetup.ACKNOWLEDGE_2_NODE, nodeInstance.getName());
397         assertTrue("Final node not complete.", nodeInstance.isComplete());
398     }
399     
400     @Test public void testBlanketApproveToMultipleNodesErrors() throws Exception {
401         
402         WorkflowDocument document = WorkflowDocumentFactory.createDocument(getPrincipalIdForName(TEST_USER_EWESTFAL), ParallelSetup.DOCUMENT_TYPE_NAME);
403         try {
404             document.blanketApprove("", new String[] { ParallelSetup.WORKFLOW_DOCUMENT_2_B1_NODE, ParallelSetup.ACKNOWLEDGE_1_NODE });    
405             fail("document should have thrown exception");
406         } catch (Exception e) {
407             // Shouldn't be able to blanket approve past the join in conjunction with blanket approve within a branch
408         	TestUtilities.getExceptionThreader().join();
409         	document = WorkflowDocumentFactory.loadDocument(getPrincipalIdForName(TEST_USER_EWESTFAL), document.getDocumentId());
410             assertTrue("Document should be in exception routing.", document.isException());            
411         }
412     }
413     
414     /**
415      * Tests that the notifications are generated properly on a blanket approve.  Works against the "NotificationTest" document type.
416      */
417     @Test public void testBlanketApproveNotification() throws Exception {
418         WorkflowDocument document = WorkflowDocumentFactory.createDocument(getPrincipalIdForName(TEST_USER_EWESTFAL), NotifySetup.DOCUMENT_TYPE_NAME);
419         document.blanketApprove("");
420         ActionRequestService arService = KEWServiceLocator.getActionRequestService(); 
421         List actionRequests = arService.getRootRequests(arService.findPendingByDoc(document.getDocumentId()));
422         assertEquals("Should be 5 pending acknowledgements and 1 pending fyi", 6, actionRequests.size());
423         boolean foundJhopfNotification = false;
424         boolean foundRkirkendNotification = false;
425         boolean foundJitrueNotification = false;
426         boolean foundBmcgoughNotification = false;
427         boolean foundXqiAck = false;
428         boolean foundJthomasFYI = false;
429         for (Iterator iterator = actionRequests.iterator(); iterator.hasNext();) {
430             ActionRequestValue actionRequest = (ActionRequestValue) iterator.next();
431             RouteNodeInstance nodeInstance = actionRequest.getNodeInstance();
432             String netId = (actionRequest.getPrincipalId() == null ? null : getPrincipalNameForId(actionRequest.getPrincipalId()));
433             if (TEST_USER_JHOPF.equals(netId)) {
434                 foundJhopfNotification = true;
435                 assertTrue("Action request should be an acknowledge.", actionRequest.isAcknowledgeRequest());
436                 assertEquals(NotifySetup.NOTIFY_FIRST_NODE, nodeInstance.getName());
437             } else if ("rkirkend".equals(netId)) {
438                 foundRkirkendNotification = true;
439                 assertTrue("Action request should be an acknowledge.", actionRequest.isAcknowledgeRequest());
440                 assertEquals(NotifySetup.NOTIFY_LEFT_NODE, nodeInstance.getName());
441                 assertEquals("Rkirkend should have three delegate acks.", 3, actionRequest.getChildrenRequests().size());
442                 assertTrue("Should be primary delegation.", actionRequest.isPrimaryDelegator());
443                 boolean foundTemayDelegate = false;
444                 boolean foundNonSITWGDelegate = false;
445                 boolean foundPmckownDelegate = false;
446                 for (Iterator iterator2 = actionRequest.getChildrenRequests().iterator(); iterator2.hasNext();) {
447                     ActionRequestValue childRequest = (ActionRequestValue) iterator2.next();
448                     assertTrue("Child request should be an acknowledge.", actionRequest.isAcknowledgeRequest());
449                     String childId = (childRequest.isGroupRequest() ? childRequest.getGroup().getName(): getPrincipalNameForId(childRequest.getPrincipalId()));
450                     if (TEST_USER_TEMAY.equals(childId)) {
451                         foundTemayDelegate = true;
452                         assertEquals("Should be primary delegation.", DelegationType.PRIMARY, childRequest.getDelegationType());
453                     } else if ("pmckown".equals(childId)) {
454                         foundPmckownDelegate = true;
455                         assertEquals("Should be secondary delegation.", DelegationType.SECONDARY, childRequest.getDelegationType());
456                     } else if ("NonSIT".equals(childId)) {
457                         foundNonSITWGDelegate = true;
458                         assertEquals("Should be primary delegation.", DelegationType.PRIMARY, childRequest.getDelegationType());
459                     }
460                 }
461                 assertTrue("Could not locate delegate request for temay.", foundTemayDelegate);
462                 assertTrue("Could not locate delegate request for NonSIT Group.", foundNonSITWGDelegate);
463                 assertTrue("Could not locate delegate request for pmckown.", foundPmckownDelegate);
464             } else if (TEST_USER_BMCGOUGH.equals(netId)) {
465                 foundBmcgoughNotification = true;
466                 assertTrue("Action request should be an acknowledge.", actionRequest.isAcknowledgeRequest());
467                 assertEquals(NotifySetup.NOTIFY_FINAL_NODE, nodeInstance.getName());
468                 
469             } else if ("xqi".equals(netId)) {
470                 foundXqiAck = true;
471                 assertTrue("Action request should be an acknowledge.", actionRequest.isAcknowledgeRequest());
472                 assertEquals(NotifySetup.NOTIFY_FINAL_NODE, nodeInstance.getName());
473                 
474             } else if (TEST_USER_JTHOMAS.equals(netId)) {
475                 foundJthomasFYI = true;
476                 assertTrue("Action request should be an FYI.", actionRequest.isFYIRequest());
477                 assertEquals(NotifySetup.NOTIFY_FINAL_NODE, nodeInstance.getName());
478             } else if (actionRequest.isRoleRequest()) {
479                List topLevelRequests = arService.getTopLevelRequests(actionRequest);
480                assertEquals(1, topLevelRequests.size());
481                actionRequest = (ActionRequestValue)topLevelRequests.get(0);
482                // this tests the notofication of the role to jitrue with delegates
483                assertEquals("Should be to jitrue.", TEST_USER_JITRUE, getPrincipalNameForId(actionRequest.getPrincipalId()));
484                foundJitrueNotification = true;
485                List delegateRoleRequests = arService.getDelegateRequests(actionRequest);
486                assertEquals("Should be 1 delegate role requests", 1, delegateRoleRequests.size());
487                ActionRequestValue delegateRoleRequest = (ActionRequestValue)delegateRoleRequests.get(0);
488                assertEquals("Should be NotifyDelegate role", "NotifyDelegate", delegateRoleRequest.getRoleName());
489                assertEquals("Should be secondary delegation", DelegationType.SECONDARY, delegateRoleRequest.getDelegationType());
490                List delegateRequests = arService.getTopLevelRequests(delegateRoleRequest);
491                assertEquals("Should be 2 delegate requests", 2, delegateRequests.size());
492                boolean foundNatjohnsDelegate = false;
493                boolean foundShenlDelegate = false;
494                for (Iterator iterator2 = delegateRequests.iterator(); iterator2.hasNext();) {
495                    ActionRequestValue delegateRequest = (ActionRequestValue) iterator2.next();
496                    String delNetId = getPrincipalNameForId(delegateRequest.getPrincipalId());
497                    if ("natjohns".equals(delNetId)) {
498                        foundNatjohnsDelegate = true;
499                    } else if ("shenl".equals(delNetId)) {
500                        foundShenlDelegate = true;
501                    }
502                }
503                assertTrue("Could not locate natjohns role delegate request.", foundNatjohnsDelegate);
504                assertTrue("Could not locate shenl role delegate request.", foundShenlDelegate);
505             }
506         }
507         assertTrue("Could not locate notification for jhopf.", foundJhopfNotification);
508         assertTrue("Could not locate notification for rkirkend.", foundRkirkendNotification);
509         assertTrue("Could not locate notification for bmcgough.", foundBmcgoughNotification);
510         assertTrue("Could not locate acknowledgment for xqi.", foundXqiAck);
511         assertTrue("Could not locate FYI for jthomas.", foundJthomasFYI);
512         assertTrue("Could not locate notification for jitrue.", foundJitrueNotification);
513     }
514     
515     /**
516      * Tests that we can blanket approve past mandatory route nodes.
517      * Addresses issue http://fms.dfa.cornell.edu:8080/browse/KULWF-461
518      */
519     @Test public void testBlanketApprovePastMandatoryNode() throws Exception {
520         WorkflowDocument document = WorkflowDocumentFactory.createDocument(getPrincipalIdForName(TEST_USER_EWESTFAL), "BlanketApproveMandatoryNodeTest");
521         document.blanketApprove("");
522         assertTrue("Document should be processed.", document.isProcessed());
523     }
524     
525     /**
526      * Tests the behavior of blanket approve through a role node and then through a node with a Workgroup including
527      * the individual(s) in the role.  Verifies that the Action List contains the proper entries in this case.
528      */
529     @Test public void testBlanketApproveThroughRoleAndWorkgroup() throws Exception {
530     	String jitruePrincipalId = getPrincipalIdForName(TEST_USER_JITRUE);
531     	WorkflowDocument document = WorkflowDocumentFactory.createDocument(getPrincipalIdForName(TEST_USER_USER1), "BlanketApproveThroughRoleAndWorkgroupTest");
532     	document.saveDocument("");
533     	assertTrue(document.isSaved());
534     	TestUtilities.assertNotInActionList(jitruePrincipalId, document.getDocumentId());
535 
536     	document.blanketApprove("");
537     	
538     	// document should now be processed
539     	document = WorkflowDocumentFactory.loadDocument(jitruePrincipalId, document.getDocumentId());
540     	assertTrue(document.isProcessed());
541     	assertTrue(document.isAcknowledgeRequested());
542     	
543     	// there should be 3 root acknowledge requests, one to the WorkflowAdmin workgroup, one to jitrue in the Notify role and one to jitrue in the Notify2 role
544     	List actionRequests = KEWServiceLocator.getActionRequestService().findPendingRootRequestsByDocId(document.getDocumentId());
545     	assertEquals("There should be 3 root requests.", 3, actionRequests.size());
546     	
547     	// now check that the document is in jitrue's action list
548     	TestUtilities.assertInActionList(jitruePrincipalId, document.getDocumentId());
549     	
550     	// acknowledge as a member of the workgroup who is not jitrue
551     	document = WorkflowDocumentFactory.loadDocument(getPrincipalIdForName(TEST_USER_EWESTFAL), document.getDocumentId());
552     	assertTrue(document.isAcknowledgeRequested());
553     	document.acknowledge("");
554     	
555     	// document should still be processed
556     	document = WorkflowDocumentFactory.loadDocument(jitruePrincipalId, document.getDocumentId());
557     	assertTrue(document.isProcessed());
558     	assertTrue(document.isAcknowledgeRequested());
559     	
560     	// there should now be 2 root acknowledge requests, one to jitrue in the Notify role and one to jitrue in the Notify2 role
561     	actionRequests = KEWServiceLocator.getActionRequestService().findPendingRootRequestsByDocId(document.getDocumentId());
562     	assertEquals("There should be 2 root requests.", 2, actionRequests.size());
563     	
564     	// jitrue should still have this in his action list
565     	TestUtilities.assertInActionList(jitruePrincipalId, document.getDocumentId());
566     	document.acknowledge("");
567     	
568     	// document should now be final
569     	assertTrue(document.isFinal());
570     }
571     
572     private RouteNodeService getRouteNodeService() {
573         return KEWServiceLocator.getRouteNodeService();
574     }
575     
576     private class SequentialSetup {
577 
578         public static final String DOCUMENT_TYPE_NAME = "BlanketApproveSequentialTest";
579         public static final String ADHOC_NODE = "AdHoc";
580         public static final String WORKFLOW_DOCUMENT_NODE = "WorkflowDocument";
581         public static final String WORKFLOW_DOCUMENT_2_NODE = "WorkflowDocument2";
582         public static final String ACKNOWLEDGE_1_NODE = "Acknowledge1";
583         public static final String ACKNOWLEDGE_2_NODE = "Acknowledge2";
584         
585     }
586 
587     private class ChainedParentSetup {
588         public static final String DOCUMENT_TYPE_NAME = "ChainedBlanketApproveTestParent";
589         public static final String CHILD_DOC_ATTRIBUTE = "ChildDocumentAttribute";
590         public static final String DOC_ID_PROPERTY = "documentId";
591         public static final String ADHOC_NODE = "AdHoc";
592         public static final String WORKFLOW_DOCUMENT_NODE = "WorkflowDocument";
593         public static final String WORKFLOW_DOCUMENT_2_NODE = "WorkflowDocument2";
594         public static final String ACKNOWLEDGE_1_NODE = "Acknowledge1";
595         public static final String ACKNOWLEDGE_2_NODE = "Acknowledge2";
596     }
597 
598     private class ChainedChildSetup {
599         public static final String DOCUMENT_TYPE_NAME = "ChainedBlanketApproveTestChild";
600         public static final String ADHOC_NODE = "AdHoc";
601         public static final String WORKFLOW_DOCUMENT_NODE = "WorkflowDocument";
602         public static final String WORKFLOW_DOCUMENT_2_NODE = "WorkflowDocument2";
603         public static final String ACKNOWLEDGE_1_NODE = "Acknowledge1";
604         public static final String ACKNOWLEDGE_2_NODE = "Acknowledge2";
605     }
606     
607     private class ParallelSetup {
608 
609         public static final String DOCUMENT_TYPE_NAME = "BlanketApproveParallelTest";
610         public static final String ADHOC_NODE = "AdHoc";
611         public static final String WORKFLOW_DOCUMENT_NODE = "WorkflowDocument";
612         public static final String WORKFLOW_DOCUMENT_2_B1_NODE = "WorkflowDocument2-B1";
613         public static final String WORKFLOW_DOCUMENT_2_B2_NODE = "WorkflowDocument2-B2";
614         public static final String WORKFLOW_DOCUMENT_3_B1_NODE = "WorkflowDocument3-B1";
615         public static final String WORKFLOW_DOCUMENT_3_B2_NODE = "WorkflowDocument3-B2";
616         public static final String WORKFLOW_DOCUMENT_4_B3_NODE = "WorkflowDocument4-B3";
617         public static final String ACKNOWLEDGE_1_NODE = "Acknowledge1";
618         public static final String ACKNOWLEDGE_2_NODE = "Acknowledge2";
619         public static final String JOIN_NODE = "Join";
620         public static final String SPLIT_NODE = "Split";
621         public static final String WORKFLOW_DOCUMENT_FINAL_NODE = "WorkflowDocumentFinal";
622         
623     }
624     
625     /*private class CycleSetup {
626 
627         public static final String DOCUMENT_TYPE_NAME = "BlanketApproveCycleTest";
628         public static final String ADHOC_NODE = "AdHoc";
629         public static final String WORKFLOW_DOCUMENT_NODE = "WorkflowDocument";
630         public static final String WORKFLOW_DOCUMENT_2_NODE = "WorkflowDocument2";
631         public static final String WORKFLOW_DOCUMENT_FINAL_NODE = "WorkflowDocumentFinal";
632         public static final String JOIN_NODE = "Join";
633         public static final String CUSTOM_CYCLE_SPLIT_NODE = "CustomCycleSplit";
634         
635     }*/
636 
637     /**
638      * Verifying Blanket approve on a chained document works properly
639      *
640      *
641      */
642     public static class ChainedApprovalPostProcessor extends DefaultPostProcessor {
643 
644         public ProcessDocReport doRouteStatusChange(DocumentRouteStatusChange statusChangeEvent) throws Exception {
645 
646             if (KewApiConstants.ROUTE_HEADER_PROCESSED_CD.equals(statusChangeEvent.getNewRouteStatus())) {
647                 // Using KimApiServiceLocator to avoid issues with static class and getPrincipalIdFromName
648                 String principalId = KimApiServiceLocator
649                         .getIdentityService().getPrincipalByPrincipalName(TEST_USER_EWESTFAL).getPrincipalId();
650                 WorkflowDocument parentDocument = WorkflowDocumentFactory.loadDocument(principalId, statusChangeEvent.getDocumentId());
651                 List<WorkflowAttributeDefinition> attributeDefinitions = parentDocument.getAttributeDefinitions();
652 
653                 // Workaround to get document id  for chained blanket approve test
654                 String documentContent = parentDocument.getDocumentContent().getFullContent();
655                 String documentId = StringUtils.split(documentContent, "\\<(\\/)?documentId\\>")[1];
656                 WorkflowDocument childDocument = WorkflowDocumentFactory.loadDocument(principalId, documentId);
657                 childDocument.blanketApprove("");
658 
659                 // Standard approach (attribute definition not coming across)
660                 for(WorkflowAttributeDefinition attributeDefinition: parentDocument.getAttributeDefinitions()) {
661                     if(ChainedParentSetup.CHILD_DOC_ATTRIBUTE.equals(attributeDefinition.getAttributeName())) {
662                         String childDocumentId = attributeDefinition.getPropertyDefinitionsAsMap().get(ChainedParentSetup.DOC_ID_PROPERTY);
663                         WorkflowDocument childDocumentItem = WorkflowDocumentFactory.loadDocument(principalId, childDocumentId);
664                         childDocumentItem.blanketApprove("");
665                     }
666                 }
667             }
668 
669             return new ProcessDocReport(true);
670         }
671 
672     }
673 
674     public class ChainedApprovalWorkflowAttribute extends GenericWorkflowAttribute {
675 
676         public ChainedApprovalWorkflowAttribute() {
677 
678         }
679 
680         Map<String, String> propertiesMap = new HashMap<String, String>();
681 
682         @Override
683         public Map<String, String> getProperties() {
684             return propertiesMap;
685         }
686     }
687 
688 
689     public static class NotifySetup {
690 
691         public static final String DOCUMENT_TYPE_NAME = "NotificationTest";
692         public static final String ADHOC_NODE = "AdHoc";
693         public static final String NOTIFY_FIRST_NODE = "NotifyFirst";
694         public static final String NOTIFY_LEFT_NODE = "NotifyLeftBranch";
695         public static final String NOTIFY_RIGHT_NODE = "NotifyRightBranch";
696         public static final String NOTIFY_FINAL_NODE = "NotifyFinal";
697         public static final String SPLIT_NODE = "Split";
698         public static final String JOIN_NODE = "Join";
699         
700     }
701 
702     private MockEmailNotificationService getMockEmailService() {
703         return (MockEmailNotificationService)KEWServiceLocator.getActionListEmailService();
704     }
705     
706 }