View Javadoc
1   /**
2    * Copyright 2005-2011 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 org.junit.Test;
19  import org.kuali.rice.kew.api.KewApiServiceLocator;
20  import org.kuali.rice.kew.api.WorkflowDocument;
21  import org.kuali.rice.kew.api.WorkflowDocumentFactory;
22  import org.kuali.rice.kew.api.action.ActionRequest;
23  import org.kuali.rice.kew.api.action.ActionRequestType;
24  import org.kuali.rice.kew.api.action.AdHocRevoke;
25  import org.kuali.rice.kew.api.action.InvalidActionTakenException;
26  import org.kuali.rice.kew.api.exception.WorkflowException;
27  import org.kuali.rice.kew.service.KEWServiceLocator;
28  import org.kuali.rice.kew.test.KEWTestCase;
29  import org.kuali.rice.kew.test.TestUtilities;
30  import org.kuali.rice.kew.api.KewApiConstants;
31  import org.kuali.rice.kim.api.KimConstants;
32  
33  import java.util.Collection;
34  import java.util.List;
35  
36  import static org.junit.Assert.*;
37  
38  public class RevokeAdHocActionTest extends KEWTestCase {
39  
40  	private static final String ADH0C_DOC = "AdhocRouteTest";
41  	private String docId;
42  
43      protected void loadTestData() throws Exception {
44          loadXmlFile("ActionsConfig.xml");
45      }
46  
47      /**
48       * Tests revoking by action request id.
49       */
50      @Test public void testRevokeByActionRequestId() throws Exception {
51      	WorkflowDocument doc = WorkflowDocumentFactory.createDocument(getPrincipalIdForName("rkirkend"), ADH0C_DOC);
52      	docId = doc.getDocumentId();
53      	doc.adHocToPrincipal(ActionRequestType.APPROVE, "AdHoc", "annotation1", getPrincipalIdForName("dewey"), "respDesc1", false);
54  
55      	// check the action requests
56      	TestUtilities.assertNumberOfPendingRequests(docId, 1);
57      	TestUtilities.assertUserHasPendingRequest(docId, "dewey");
58  
59      	// now revoke by a bad action request id, we should recieve a WorkflowException
60      	try {
61      		doc.revokeAdHocRequestById("123456789", "");
62      		fail("Revoking by a bad action request id should have thrown an exception!");
63      	} catch (InvalidActionTakenException e) {}
64  
65      	// revoke by the real action request id
66      	List<ActionRequest> actionRequestVOs = KewApiServiceLocator.getWorkflowDocumentService().getRootActionRequests(docId);
67      	assertEquals(1, actionRequestVOs.size());
68      	String actionRequestId = actionRequestVOs.get(0).getId();
69      	doc.revokeAdHocRequestById(actionRequestId, "");
70  
71      	// there should now be no pending requests
72      	TestUtilities.assertNumberOfPendingRequests(docId, 0);
73  
74      	// route the document, this doc type is configured to route to user1
75      	doc.route("");
76      	doc = getDocument("user1");
77      	assertTrue(doc.isApprovalRequested());
78  
79      	// now attempt to revoke this non-adhoc request by id, it should throw an error
80      	actionRequestVOs = KewApiServiceLocator.getWorkflowDocumentService().getRootActionRequests(docId);
81      	for (int index = 0; index < actionRequestVOs.size(); index++) {
82      		if (actionRequestVOs.get(index).isPending()) {
83      			try {
84      				doc.revokeAdHocRequestById(actionRequestVOs.get(index).getId().toString(), "");
85      				fail("Attempted to revoke by an invalid action request id, should have thrown an error!");
86      			} catch (InvalidActionTakenException e) {}
87      		}
88      	}
89  
90      }
91  
92      /**
93       * Tests revoking by user and workgroup.
94       */
95      @Test public void testRevokeByUserAndGroup() throws Exception {
96      	// ad hoc the document to dewey (twice) and the workgroup WorkflowAdmin
97      	WorkflowDocument doc =WorkflowDocumentFactory.createDocument(getPrincipalIdForName("rkirkend"), ADH0C_DOC);
98      	docId = doc.getDocumentId();
99      	String principalId = getPrincipalIdForName("dewey");
100     	doc.adHocToPrincipal(ActionRequestType.APPROVE, "AdHoc", "annotationDewey1", principalId, "respDesc1", false);
101     	doc.adHocToPrincipal(ActionRequestType.APPROVE, "AdHoc", "annotationDewey2", principalId, "respDesc1", false);
102     	String groupId = getGroupIdForName(KimConstants.KIM_GROUP_WORKFLOW_NAMESPACE_CODE, "WorkflowAdmin");
103     	doc.adHocToGroup(ActionRequestType.APPROVE, "AdHoc", "Annotation WorkflowAdmin",  groupId, "respDesc2", true);
104 
105     	TestUtilities.assertNumberOfPendingRequests(docId, 3);
106     	TestUtilities.assertUserHasPendingRequest(docId, "dewey");
107     	TestUtilities.assertUserHasPendingRequest(docId, "quickstart");
108 
109     	// route the document, this should activate the ad hoc requests
110     	doc.route("");
111     	assertTrue(doc.isEnroute());
112     	TestUtilities.assertAtNodeNew(doc, "AdHoc");
113     	TestUtilities.assertNumberOfPendingRequests(docId, 3);
114 
115     	String testGroupId = getGroupIdForName(KimConstants.KIM_GROUP_WORKFLOW_NAMESPACE_CODE, "TestWorkgroup");
116     	// try revoking by a user and workgroup without adhoc requests, it should effectively be a no-op
117     	AdHocRevoke revoke = AdHocRevoke.createRevokeFromPrincipal(getPrincipalIdForName("ewestfal"));
118     	doc.revokeAdHocRequests(revoke, "This should be a no-op");
119     	revoke = AdHocRevoke.createRevokeFromGroup(testGroupId);
120     	doc.revokeAdHocRequests(revoke, "This should be a no-op");
121     	doc = getDocument("rkirkend");
122     	TestUtilities.assertNumberOfPendingRequests(docId, 3);
123     	TestUtilities.assertUserHasPendingRequest(docId, "dewey");
124     	TestUtilities.assertUserHasPendingRequest(docId, "quickstart");
125 
126     	// now revoke each request in turn, after the second one is invoked the document should transition to it's next route level
127     	// and route to user1
128     	revoke = AdHocRevoke.createRevokeFromPrincipal(getPrincipalIdForName("dewey"));
129     	doc.revokeAdHocRequests(revoke, "revokeUser");
130     	TestUtilities.assertNumberOfPendingRequests(docId, 1);
131     	doc = getDocument("dewey");
132     	assertFalse("dewey should no longer have an approve request.", doc.isApprovalRequested());
133     	revoke = AdHocRevoke.createRevokeFromGroup(groupId);
134     	doc.revokeAdHocRequests(revoke, "revokeWorkgroup");
135 
136     	// the doc should now transition to the next node
137     	doc = getDocument("user1");
138     	TestUtilities.assertAtNodeNew(doc, "One");
139     	assertTrue("user1 should have an approve request.", doc.isApprovalRequested());
140     	doc.approve("");
141 
142     	// doc should now be final
143     	assertTrue("doc should be final", doc.isFinal());
144     }
145 
146     /**
147      * Tests revoking by node name.
148      */
149     @Test public void testRevokeByNodeName() throws Exception {
150     	// ad hoc requests at the AdHoc node and then revoke the entire node
151     	WorkflowDocument doc = WorkflowDocumentFactory.createDocument(getPrincipalIdForName("rkirkend"), ADH0C_DOC);
152     	docId = doc.getDocumentId();
153     	doc.adHocToPrincipal(ActionRequestType.APPROVE, "AdHoc", "annotationDewey1", getPrincipalIdForName("dewey"), "respDesc1", false);
154     	String groupId = getGroupIdForName(KimConstants.KIM_GROUP_WORKFLOW_NAMESPACE_CODE, "WorkflowAdmin");
155     	doc.adHocToGroup(ActionRequestType.APPROVE, "AdHoc", "Annotation WorkflowAdmin", groupId, "respDesc2", true);
156     	TestUtilities.assertNumberOfPendingRequests(docId, 2);
157 
158     	// now revoke the node
159     	doc.revokeAdHocRequests(AdHocRevoke.createRevokeAtNode("AdHoc"), "");
160     	TestUtilities.assertNumberOfPendingRequests(docId, 0);
161     	// send an Acknowledge to the AdHoc node prior to routing
162     	doc.adHocToPrincipal(ActionRequestType.ACKNOWLEDGE, "AdHoc", "annotationEwestfal1", getPrincipalIdForName("ewestfal"), "respDesc1", false);
163 
164     	// route the document
165     	doc = getDocument("rkirkend");
166     	doc.route("");
167     	TestUtilities.assertAtNodeNew(doc, "One");
168 
169     	// ewestfal should have an acknowledge request
170     	doc = getDocument("ewestfal");
171     	assertTrue(doc.isAcknowledgeRequested());
172 
173     	// approve the document, it should go PROCESSED
174     	doc = getDocument("user1");
175     	assertTrue(doc.isApprovalRequested());
176     	doc.approve("");
177     	assertTrue(doc.isProcessed());
178 
179     	// revoke at the "One" node where there are no requests, it should be a no-op (the document should stay processed)
180     	doc.revokeAdHocRequests(AdHocRevoke.createRevokeAtNode("One"), "");
181     	doc = getDocument("ewestfal");
182     	assertTrue(doc.isProcessed());
183 
184     	// now revoke the ACKNOWLEDGE to ewestfal by revoking at the "AdHoc" node, the document should go FINAL
185     	doc.revokeAdHocRequests(AdHocRevoke.createRevokeAtNode("AdHoc"), "");
186     	doc = getDocument("ewestfal");
187     	assertTrue(doc.isFinal());
188     }
189 
190     /**
191      * Tests the behavior revocation of ad hoc requests prior to the routing of the document.
192      *
193      * @throws Exception
194      */
195     @Test public void testRevokePriorToRouting() throws Exception {
196     	// ad hoc the document to dewey and the workgroup WorkflowAdmin
197     	WorkflowDocument doc = WorkflowDocumentFactory.createDocument(getPrincipalIdForName("rkirkend"), ADH0C_DOC);
198     	docId = doc.getDocumentId();
199     	doc.adHocToPrincipal(ActionRequestType.APPROVE, "AdHoc", "annotation1", getPrincipalIdForName("dewey"), "respDesc1", false);
200 
201     	doc = getDocument("dewey");
202     	assertFalse("User andlee should not have an approve request yet.  Document not yet routed.", doc.isApprovalRequested());
203     	String groupId = getGroupIdForName(KimConstants.KIM_GROUP_WORKFLOW_NAMESPACE_CODE, "WorkflowAdmin");
204     	doc.adHocToGroup(ActionRequestType.APPROVE, "AdHoc", "annotation2", groupId , "respDesc2", true);
205     	doc = getDocument("quickstart");
206     	assertFalse("User should not have approve request yet.  Document not yet routed.", doc.isApprovalRequested());
207 
208     	// the document should be initiated at this point
209     	assertTrue("Document should still be intitiated.", doc.isInitiated());
210 
211     	// check and revoke the actual ActionRequestVOs
212     	// reaquire the document as the initiator
213     	doc = getDocument("rkirkend");
214     	List<ActionRequest> actionRequestVOs = KewApiServiceLocator.getWorkflowDocumentService().getRootActionRequests(doc.getDocumentId());
215     	assertEquals("There should be 2 ad hoc requests.", 2, actionRequestVOs.size());
216     	for (ActionRequest requestVO : actionRequestVOs) {
217     		assertTrue("Should be an ad hoc request.", requestVO.isAdHocRequest());
218     		// revoke by id
219     		doc.revokeAdHocRequestById(requestVO.getId().toString(), "");
220     	}
221 
222     	// now the document should have no pending action requests on it
223     	List actionRequests = KEWServiceLocator.getActionRequestService().findPendingByDoc(docId);
224     	assertEquals("There should be no pending requests.", 0, actionRequests.size());
225 
226     	// check that the "ActionTakens" have been properly recorded
227     	Collection actionTakens = KEWServiceLocator.getActionTakenService().findByDocIdAndAction(docId, KewApiConstants.ACTION_TAKEN_ADHOC_REVOKED_CD);
228     	assertEquals("There should be 2 'AdHocRevoked' action takens", 2, actionTakens.size());
229 
230     	// now check that the document is still intiated
231     	doc = getDocument("rkirkend");
232     	assertTrue("Document should still be intitiated.", doc.isInitiated());
233     }
234 
235     /**
236      * Tests the revocation of ad hoc requests after a blanket approve.  The goal of this test is to verify that revocation of
237      * ad hoc requests doesn't have any adverse effects on the notification requests
238      */
239     @Test public void testRevokeAfterBlanketApprove() throws Exception {
240     	WorkflowDocument doc = WorkflowDocumentFactory.createDocument(getPrincipalIdForName("rkirkend"), ADH0C_DOC);
241     	docId = doc.getDocumentId();
242     	// send an FYI to the AdHoc node prior to blanket approving
243     	doc.adHocToPrincipal(ActionRequestType.FYI, "AdHoc", "annotationEwestfal1", getPrincipalIdForName("ewestfal"), "respDesc1", false);
244 
245     	// blanket approve the document
246     	doc.blanketApprove("");
247     	assertTrue(doc.isProcessed());
248 
249     	// ewestfal should have his ad hoc FYI and user1 should have an ack from the blanket approve
250     	doc = getDocument("ewestfal");
251     	assertTrue(doc.isFYIRequested());
252     	doc = getDocument("user1");
253     	assertTrue(doc.isAcknowledgeRequested());
254 
255     	// revoke all ad hoc requests
256     	doc.revokeAllAdHocRequests("revoking all adhocs");
257     	assertTrue(doc.isProcessed());
258     	TestUtilities.assertNumberOfPendingRequests(docId, 1);
259 
260     	// user1 should still have acknowledge request
261     	assertTrue(doc.isAcknowledgeRequested());
262 
263     	// ewestfal should no longer have an fyi
264     	doc = getDocument("ewestfal");
265     	assertFalse(doc.isFYIRequested());
266     }
267 
268     private WorkflowDocument getDocument(String netid) throws WorkflowException {
269     	return WorkflowDocumentFactory.loadDocument(getPrincipalIdForName(netid), docId);
270     }
271 
272 }