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    }