001 /**
002 * Copyright 2005-2014 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.actiontaken.ActionTakenValue;
020 import org.kuali.rice.kew.api.KewApiConstants;
021 import org.kuali.rice.kew.api.KewApiServiceLocator;
022 import org.kuali.rice.kew.api.WorkflowDocument;
023 import org.kuali.rice.kew.api.WorkflowDocumentFactory;
024 import org.kuali.rice.kew.api.action.ActionRequest;
025 import org.kuali.rice.kew.api.action.ActionRequestType;
026 import org.kuali.rice.kew.api.action.AdHocRevoke;
027 import org.kuali.rice.kew.api.action.InvalidActionTakenException;
028 import org.kuali.rice.kew.api.exception.WorkflowException;
029 import org.kuali.rice.kew.service.KEWServiceLocator;
030 import org.kuali.rice.kew.test.KEWTestCase;
031 import org.kuali.rice.kew.test.TestUtilities;
032 import org.kuali.rice.kim.api.KimConstants;
033
034 import java.util.Collection;
035 import java.util.List;
036
037 import static org.junit.Assert.*;
038
039 public class RevokeAdHocActionTest extends KEWTestCase {
040
041 private static final String ADH0C_DOC = "AdhocRouteTest";
042 private String docId;
043
044 protected void loadTestData() throws Exception {
045 loadXmlFile("ActionsConfig.xml");
046 }
047
048 /**
049 * Tests revoking by action request id.
050 */
051 @Test public void testRevokeByActionRequestId() throws Exception {
052 WorkflowDocument doc = WorkflowDocumentFactory.createDocument(getPrincipalIdForName("rkirkend"), ADH0C_DOC);
053 docId = doc.getDocumentId();
054 doc.adHocToPrincipal(ActionRequestType.APPROVE, "AdHoc", "annotation1", getPrincipalIdForName("dewey"), "respDesc1", false);
055
056 // check the action requests
057 TestUtilities.assertNumberOfPendingRequests(docId, 1);
058 TestUtilities.assertUserHasPendingRequest(docId, "dewey");
059
060 // now revoke by a bad action request id, we should recieve a WorkflowException
061 try {
062 doc.revokeAdHocRequestById("123456789", "");
063 fail("Revoking by a bad action request id should have thrown an exception!");
064 } catch (InvalidActionTakenException e) {}
065
066 // revoke by the real action request id
067 List<ActionRequest> actionRequestVOs = KewApiServiceLocator.getWorkflowDocumentService().getRootActionRequests(docId);
068 assertEquals(1, actionRequestVOs.size());
069 String actionRequestId = actionRequestVOs.get(0).getId();
070 doc.revokeAdHocRequestById(actionRequestId, "");
071
072 // there should now be no pending requests
073 TestUtilities.assertNumberOfPendingRequests(docId, 0);
074
075 // route the document, this doc type is configured to route to user1
076 doc.route("");
077 doc = getDocument("user1");
078 assertTrue(doc.isApprovalRequested());
079
080 // now attempt to revoke this non-adhoc request by id, it should throw an error
081 actionRequestVOs = KewApiServiceLocator.getWorkflowDocumentService().getRootActionRequests(docId);
082 for (int index = 0; index < actionRequestVOs.size(); index++) {
083 if (actionRequestVOs.get(index).isPending()) {
084 try {
085 doc.revokeAdHocRequestById(actionRequestVOs.get(index).getId().toString(), "");
086 fail("Attempted to revoke by an invalid action request id, should have thrown an error!");
087 } catch (InvalidActionTakenException e) {}
088 }
089 }
090
091 }
092
093 /**
094 * Tests revoking by user and workgroup.
095 */
096 @Test public void testRevokeByUserAndGroup() throws Exception {
097 // ad hoc the document to dewey (twice) and the workgroup WorkflowAdmin
098 WorkflowDocument doc =WorkflowDocumentFactory.createDocument(getPrincipalIdForName("rkirkend"), ADH0C_DOC);
099 docId = doc.getDocumentId();
100 String principalId = getPrincipalIdForName("dewey");
101 doc.adHocToPrincipal(ActionRequestType.APPROVE, "AdHoc", "annotationDewey1", principalId, "respDesc1", false);
102 doc.adHocToPrincipal(ActionRequestType.APPROVE, "AdHoc", "annotationDewey2", principalId, "respDesc1", false);
103 String groupId = getGroupIdForName(KimConstants.KIM_GROUP_WORKFLOW_NAMESPACE_CODE, "WorkflowAdmin");
104 doc.adHocToGroup(ActionRequestType.APPROVE, "AdHoc", "Annotation WorkflowAdmin", groupId, "respDesc2", true);
105
106 TestUtilities.assertNumberOfPendingRequests(docId, 3);
107 TestUtilities.assertUserHasPendingRequest(docId, "dewey");
108 TestUtilities.assertUserHasPendingRequest(docId, "quickstart");
109
110 // route the document, this should activate the ad hoc requests
111 doc.route("");
112 assertTrue(doc.isEnroute());
113 TestUtilities.assertAtNodeNew(doc, "AdHoc");
114 TestUtilities.assertNumberOfPendingRequests(docId, 3);
115
116 String testGroupId = getGroupIdForName(KimConstants.KIM_GROUP_WORKFLOW_NAMESPACE_CODE, "TestWorkgroup");
117 // try revoking by a user and workgroup without adhoc requests, it should effectively be a no-op
118 AdHocRevoke revoke = AdHocRevoke.createRevokeFromPrincipal(getPrincipalIdForName("ewestfal"));
119 doc.revokeAdHocRequests(revoke, "This should be a no-op");
120 revoke = AdHocRevoke.createRevokeFromGroup(testGroupId);
121 doc.revokeAdHocRequests(revoke, "This should be a no-op");
122 doc = getDocument("rkirkend");
123 TestUtilities.assertNumberOfPendingRequests(docId, 3);
124 TestUtilities.assertUserHasPendingRequest(docId, "dewey");
125 TestUtilities.assertUserHasPendingRequest(docId, "quickstart");
126
127 // now revoke each request in turn, after the second one is invoked the document should transition to it's next route level
128 // and route to user1
129 revoke = AdHocRevoke.createRevokeFromPrincipal(getPrincipalIdForName("dewey"));
130 doc.revokeAdHocRequests(revoke, "revokeUser");
131 TestUtilities.assertNumberOfPendingRequests(docId, 1);
132 doc = getDocument("dewey");
133 assertFalse("dewey should no longer have an approve request.", doc.isApprovalRequested());
134 revoke = AdHocRevoke.createRevokeFromGroup(groupId);
135 doc.revokeAdHocRequests(revoke, "revokeWorkgroup");
136
137 // the doc should now transition to the next node
138 doc = getDocument("user1");
139 TestUtilities.assertAtNodeNew(doc, "One");
140 assertTrue("user1 should have an approve request.", doc.isApprovalRequested());
141 doc.approve("");
142
143 // doc should now be final
144 assertTrue("doc should be final", doc.isFinal());
145 }
146
147 /**
148 * Tests revoking by node name.
149 */
150 @Test public void testRevokeByNodeName() throws Exception {
151 // ad hoc requests at the AdHoc node and then revoke the entire node
152 WorkflowDocument doc = WorkflowDocumentFactory.createDocument(getPrincipalIdForName("rkirkend"), ADH0C_DOC);
153 docId = doc.getDocumentId();
154 doc.adHocToPrincipal(ActionRequestType.APPROVE, "AdHoc", "annotationDewey1", getPrincipalIdForName("dewey"), "respDesc1", false);
155 String groupId = getGroupIdForName(KimConstants.KIM_GROUP_WORKFLOW_NAMESPACE_CODE, "WorkflowAdmin");
156 doc.adHocToGroup(ActionRequestType.APPROVE, "AdHoc", "Annotation WorkflowAdmin", groupId, "respDesc2", true);
157 TestUtilities.assertNumberOfPendingRequests(docId, 2);
158
159 // now revoke the node
160 doc.revokeAdHocRequests(AdHocRevoke.createRevokeAtNode("AdHoc"), "");
161 TestUtilities.assertNumberOfPendingRequests(docId, 0);
162 // send an Acknowledge to the AdHoc node prior to routing
163 doc.adHocToPrincipal(ActionRequestType.ACKNOWLEDGE, "AdHoc", "annotationEwestfal1", getPrincipalIdForName("ewestfal"), "respDesc1", false);
164
165 // route the document
166 doc = getDocument("rkirkend");
167 doc.route("");
168 TestUtilities.assertAtNodeNew(doc, "One");
169
170 // ewestfal should have an acknowledge request
171 doc = getDocument("ewestfal");
172 assertTrue(doc.isAcknowledgeRequested());
173
174 // approve the document, it should go PROCESSED
175 doc = getDocument("user1");
176 assertTrue(doc.isApprovalRequested());
177 doc.approve("");
178 assertTrue(doc.isProcessed());
179
180 // revoke at the "One" node where there are no requests, it should be a no-op (the document should stay processed)
181 doc.revokeAdHocRequests(AdHocRevoke.createRevokeAtNode("One"), "");
182 doc = getDocument("ewestfal");
183 assertTrue(doc.isProcessed());
184
185 // now revoke the ACKNOWLEDGE to ewestfal by revoking at the "AdHoc" node, the document should go FINAL
186 doc.revokeAdHocRequests(AdHocRevoke.createRevokeAtNode("AdHoc"), "");
187 doc = getDocument("ewestfal");
188 assertTrue(doc.isFinal());
189 }
190
191 /**
192 * Tests the behavior revocation of ad hoc requests prior to the routing of the document.
193 *
194 * @throws Exception
195 */
196 @Test public void testRevokePriorToRouting() throws Exception {
197 // ad hoc the document to dewey and the workgroup WorkflowAdmin
198 WorkflowDocument doc = WorkflowDocumentFactory.createDocument(getPrincipalIdForName("rkirkend"), ADH0C_DOC);
199 docId = doc.getDocumentId();
200 doc.adHocToPrincipal(ActionRequestType.APPROVE, "AdHoc", "annotation1", getPrincipalIdForName("dewey"), "respDesc1", false);
201
202 doc = getDocument("dewey");
203 assertFalse("User andlee should not have an approve request yet. Document not yet routed.", doc.isApprovalRequested());
204 String groupId = getGroupIdForName(KimConstants.KIM_GROUP_WORKFLOW_NAMESPACE_CODE, "WorkflowAdmin");
205 doc.adHocToGroup(ActionRequestType.APPROVE, "AdHoc", "annotation2", groupId , "respDesc2", true);
206 doc = getDocument("quickstart");
207 assertFalse("User should not have approve request yet. Document not yet routed.", doc.isApprovalRequested());
208
209 // the document should be initiated at this point
210 assertTrue("Document should still be intitiated.", doc.isInitiated());
211
212 // check and revoke the actual ActionRequestVOs
213 // reaquire the document as the initiator
214 doc = getDocument("rkirkend");
215 List<ActionRequest> actionRequestVOs = KewApiServiceLocator.getWorkflowDocumentService().getRootActionRequests(doc.getDocumentId());
216 assertEquals("There should be 2 ad hoc requests.", 2, actionRequestVOs.size());
217 for (ActionRequest requestVO : actionRequestVOs) {
218 assertTrue("Should be an ad hoc request.", requestVO.isAdHocRequest());
219 // revoke by id
220 doc.revokeAdHocRequestById(requestVO.getId().toString(), "");
221 }
222
223 // now the document should have no pending action requests on it
224 List actionRequests = KEWServiceLocator.getActionRequestService().findPendingByDoc(docId);
225 assertEquals("There should be no pending requests.", 0, actionRequests.size());
226
227 // check that the "ActionTakens" have been properly recorded
228 Collection<ActionTakenValue> actionTakens = KEWServiceLocator.getActionTakenService().findByDocumentId(docId);
229 // count how many are AdhocRevoked
230 int numAdhocRevoked = 0;
231 for (ActionTakenValue actionTaken : actionTakens) {
232 if (actionTaken.getActionTaken().equals(KewApiConstants.ACTION_TAKEN_ADHOC_REVOKED_CD)) {
233 numAdhocRevoked++;
234 }
235 }
236 assertEquals("There should be 2 'AdHocRevoked' action takens", 2, numAdhocRevoked);
237
238 // now check that the document is still intiated
239 doc = getDocument("rkirkend");
240 assertTrue("Document should still be intitiated.", doc.isInitiated());
241 }
242
243 /**
244 * Tests the revocation of ad hoc requests after a blanket approve. The goal of this test is to verify that revocation of
245 * ad hoc requests doesn't have any adverse effects on the notification requests
246 */
247 @Test public void testRevokeAfterBlanketApprove() throws Exception {
248 WorkflowDocument doc = WorkflowDocumentFactory.createDocument(getPrincipalIdForName("rkirkend"), ADH0C_DOC);
249 docId = doc.getDocumentId();
250 // send an FYI to the AdHoc node prior to blanket approving
251 doc.adHocToPrincipal(ActionRequestType.FYI, "AdHoc", "annotationEwestfal1", getPrincipalIdForName("ewestfal"), "respDesc1", false);
252
253 // blanket approve the document
254 doc.blanketApprove("");
255 assertTrue(doc.isProcessed());
256
257 // ewestfal should have his ad hoc FYI and user1 should have an ack from the blanket approve
258 doc = getDocument("ewestfal");
259 assertTrue(doc.isFYIRequested());
260 doc = getDocument("user1");
261 assertTrue(doc.isAcknowledgeRequested());
262
263 // revoke all ad hoc requests
264 doc.revokeAllAdHocRequests("revoking all adhocs");
265 assertTrue(doc.isProcessed());
266 TestUtilities.assertNumberOfPendingRequests(docId, 1);
267
268 // user1 should still have acknowledge request
269 assertTrue(doc.isAcknowledgeRequested());
270
271 // ewestfal should no longer have an fyi
272 doc = getDocument("ewestfal");
273 assertFalse(doc.isFYIRequested());
274 }
275
276 private WorkflowDocument getDocument(String netid) throws WorkflowException {
277 return WorkflowDocumentFactory.loadDocument(getPrincipalIdForName(netid), docId);
278 }
279
280 }