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 }