001 /**
002 * Copyright 2005-2011 The Kuali Foundation
003 *
004 * Licensed under the Educational Community License, Version 2.0 (the "License");
005 * you may not use this file except in compliance with the License.
006 * You may obtain a copy of the License at
007 *
008 * http://www.opensource.org/licenses/ecl2.php
009 *
010 * Unless required by applicable law or agreed to in writing, software
011 * distributed under the License is distributed on an "AS IS" BASIS,
012 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
013 * See the License for the specific language governing permissions and
014 * limitations under the License.
015 */
016 package org.kuali.rice.kew.actions;
017
018 import org.junit.Test;
019 import org.kuali.rice.kew.api.KewApiServiceLocator;
020 import org.kuali.rice.kew.api.WorkflowDocument;
021 import org.kuali.rice.kew.api.WorkflowDocumentFactory;
022 import org.kuali.rice.kew.api.action.ActionRequest;
023 import org.kuali.rice.kew.api.action.ActionRequestType;
024 import org.kuali.rice.kew.api.action.AdHocRevoke;
025 import org.kuali.rice.kew.api.action.InvalidActionTakenException;
026 import org.kuali.rice.kew.api.exception.WorkflowException;
027 import org.kuali.rice.kew.service.KEWServiceLocator;
028 import org.kuali.rice.kew.test.KEWTestCase;
029 import org.kuali.rice.kew.test.TestUtilities;
030 import org.kuali.rice.kew.api.KewApiConstants;
031 import org.kuali.rice.kim.api.KimConstants;
032
033 import java.util.Collection;
034 import java.util.List;
035
036 import static org.junit.Assert.*;
037
038 public class RevokeAdHocActionTest extends KEWTestCase {
039
040 private static final String ADH0C_DOC = "AdhocRouteTest";
041 private String docId;
042
043 protected void loadTestData() throws Exception {
044 loadXmlFile("ActionsConfig.xml");
045 }
046
047 /**
048 * Tests revoking by action request id.
049 */
050 @Test public void testRevokeByActionRequestId() throws Exception {
051 WorkflowDocument doc = WorkflowDocumentFactory.createDocument(getPrincipalIdForName("rkirkend"), ADH0C_DOC);
052 docId = doc.getDocumentId();
053 doc.adHocToPrincipal(ActionRequestType.APPROVE, "AdHoc", "annotation1", getPrincipalIdForName("dewey"), "respDesc1", false);
054
055 // check the action requests
056 TestUtilities.assertNumberOfPendingRequests(docId, 1);
057 TestUtilities.assertUserHasPendingRequest(docId, "dewey");
058
059 // now revoke by a bad action request id, we should recieve a WorkflowException
060 try {
061 doc.revokeAdHocRequestById("123456789", "");
062 fail("Revoking by a bad action request id should have thrown an exception!");
063 } catch (InvalidActionTakenException e) {}
064
065 // revoke by the real action request id
066 List<ActionRequest> actionRequestVOs = KewApiServiceLocator.getWorkflowDocumentService().getRootActionRequests(docId);
067 assertEquals(1, actionRequestVOs.size());
068 String actionRequestId = actionRequestVOs.get(0).getId();
069 doc.revokeAdHocRequestById(actionRequestId, "");
070
071 // there should now be no pending requests
072 TestUtilities.assertNumberOfPendingRequests(docId, 0);
073
074 // route the document, this doc type is configured to route to user1
075 doc.route("");
076 doc = getDocument("user1");
077 assertTrue(doc.isApprovalRequested());
078
079 // now attempt to revoke this non-adhoc request by id, it should throw an error
080 actionRequestVOs = KewApiServiceLocator.getWorkflowDocumentService().getRootActionRequests(docId);
081 for (int index = 0; index < actionRequestVOs.size(); index++) {
082 if (actionRequestVOs.get(index).isPending()) {
083 try {
084 doc.revokeAdHocRequestById(actionRequestVOs.get(index).getId().toString(), "");
085 fail("Attempted to revoke by an invalid action request id, should have thrown an error!");
086 } catch (InvalidActionTakenException e) {}
087 }
088 }
089
090 }
091
092 /**
093 * Tests revoking by user and workgroup.
094 */
095 @Test public void testRevokeByUserAndGroup() throws Exception {
096 // ad hoc the document to dewey (twice) and the workgroup WorkflowAdmin
097 WorkflowDocument doc =WorkflowDocumentFactory.createDocument(getPrincipalIdForName("rkirkend"), ADH0C_DOC);
098 docId = doc.getDocumentId();
099 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 }