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 */
016package org.kuali.rice.kew.actions;
017
018import org.junit.Test;
019import org.kuali.rice.kew.actionrequest.ActionRequestValue;
020import org.kuali.rice.kew.actions.BlanketApproveTest.NotifySetup;
021import org.kuali.rice.kew.api.KewApiServiceLocator;
022import org.kuali.rice.kew.api.WorkflowDocument;
023import org.kuali.rice.kew.api.WorkflowDocumentFactory;
024import org.kuali.rice.kew.api.action.ActionRequest;
025import org.kuali.rice.kew.api.action.ActionType;
026import org.kuali.rice.kew.api.action.ReturnPoint;
027import org.kuali.rice.kew.api.document.DocumentStatus;
028import org.kuali.rice.kew.service.KEWServiceLocator;
029import org.kuali.rice.kew.test.KEWTestCase;
030import org.kuali.rice.kew.test.TestUtilities;
031import org.kuali.rice.test.BaselineTestCase;
032
033import java.util.Iterator;
034import java.util.List;
035
036import static org.junit.Assert.*;
037
038/**
039 * Tests the super user actions available on the API.
040 */
041@BaselineTestCase.BaselineMode(BaselineTestCase.Mode.NONE)
042public class SuperUserActionTest extends KEWTestCase {
043    private static final org.apache.log4j.Logger LOG = org.apache.log4j.Logger.getLogger(SuperUserActionTest.class);
044
045    protected void loadTestData() throws Exception {
046        loadXmlFile("ActionsConfig.xml");
047    }
048        
049    @Test public void testSuperUserApprove() throws Exception {
050        WorkflowDocument document = WorkflowDocumentFactory.createDocument(getPrincipalIdForName("ewestfal"), NotifySetup.DOCUMENT_TYPE_NAME);
051        document.route("");
052        
053        document = WorkflowDocumentFactory.loadDocument(getPrincipalIdForName("jhopf"), document.getDocumentId());
054        assertTrue("WorkflowDocument should indicate jhopf as SuperUser", document.isValidAction(ActionType.SU_BLANKET_APPROVE));
055        document.superUserBlanketApprove("");
056        assertTrue("Document should be 'processed' after Super User Approve", document.isProcessed());
057        List<ActionRequestValue> requests = KEWServiceLocator.getActionRequestService().findPendingByDoc(document.getDocumentId());
058        assertTrue("Should be active requests still", requests.size() == 2);//number of acks and fyi's configured through rules
059        for ( ActionRequestValue request : requests ) {
060                        if (request.isApproveOrCompleteRequest()) {
061                                fail("There should be no approve or complete requests after su approve");
062                        }
063                }
064        }
065
066    // SUApprove == SUBlanketApprove...what?
067    @Test public void testSuperUserApproveDisallowedOnFinalNode() throws Exception {
068        WorkflowDocument document = WorkflowDocumentFactory.createDocument(getPrincipalIdForName("ewestfal"), "SUApproveFinalNodeDisallowed");
069        document.route("");
070
071        // approve down to last node, at every step (except the last) jhopf should be able to su_approve
072        // omit "bmcgough", the last approver
073        String nodeBeforeLast = null;
074        for (String user: new String[] { "jhopf", "ewestfal", "rkirkend", "natjohns" }) {
075            document = WorkflowDocumentFactory.loadDocument(getPrincipalIdForName("jhopf"), document.getDocumentId());
076            System.err.println(document.getCurrentNodeNames());
077            nodeBeforeLast = document.getCurrentNodeNames().iterator().next();
078            assertTrue("jhopf should be able to SU Approve", document.isValidAction(ActionType.SU_BLANKET_APPROVE));
079
080            WorkflowDocumentFactory.loadDocument(getPrincipalIdForName(user), document.getDocumentId()).approve("");
081        }
082
083        document = WorkflowDocumentFactory.loadDocument(getPrincipalIdForName("jhopf"), document.getDocumentId());
084        // it's the last node, no SU Approve for you!
085        assertFalse("jhopf should NOT be able to SU Approve", document.isValidAction(ActionType.SU_BLANKET_APPROVE));
086
087        // move back a step
088        document = WorkflowDocumentFactory.loadDocument(getPrincipalIdForName("jhopf"), document.getDocumentId());
089        document.superUserReturnToPreviousNode(ReturnPoint.create("Split"), "returning to non-final node");
090        // now we can SU Approve
091        assertTrue("jhopf should be able to SU Approve", document.isValidAction(ActionType.SU_BLANKET_APPROVE));
092        document.superUserBlanketApprove("blanket approving as jhopf");
093
094        assertEquals("Document status incorrect", DocumentStatus.PROCESSED, document.getStatus());
095        assertFalse("jhopf should NOT be able to SU Approve", document.isValidAction(ActionType.SU_BLANKET_APPROVE));
096
097        List<ActionRequestValue> requests = KEWServiceLocator.getActionRequestService().findPendingByDoc(document.getDocumentId());
098        assertEquals("Should be active requests still", 5, requests.size());//number of acks and fyi's configured through rules
099        for (ActionRequestValue request: requests) {
100            System.err.println(request.getActionRequestedLabel() + " -> " + request.getPrincipal().getPrincipalName());
101            if (request.isApproveOrCompleteRequest()) {
102                fail("There should be no approve or complete requests after su approve.  Found: " + request);
103            }
104        }
105    }
106        
107    @Test public void testSuperUserApproveExceptionCases() throws Exception {
108        WorkflowDocument document = WorkflowDocumentFactory.createDocument(getPrincipalIdForName("user1"), "SUApproveDocument");
109        document.route("");
110        document = WorkflowDocumentFactory.loadDocument(getPrincipalIdForName("user2"), document.getDocumentId());
111        try {
112                document.approve("");
113        } catch (Exception e) {
114        }
115        TestUtilities.getExceptionThreader().join();
116        document = WorkflowDocumentFactory.loadDocument(getPrincipalIdForName("rkirkend"), document.getDocumentId());
117        assertEquals("Document status incorrect", DocumentStatus.EXCEPTION, document.getStatus());
118        document.superUserBlanketApprove("");
119        document = WorkflowDocumentFactory.loadDocument(getPrincipalIdForName("rkirkend"), document.getDocumentId());
120        assertEquals("Document status incorrect", DocumentStatus.FINAL, document.getStatus());
121        
122        List<ActionRequestValue> actionRequests = KEWServiceLocator.getActionRequestService().findPendingByDoc(document.getDocumentId());
123        assertEquals("Should be no active requests for SU Approved document.  Found: " + actionRequests, 0, actionRequests.size());
124    }
125    
126    @Test public void testSuperUserApproveExceptionCasesWithNotifications() throws Exception {
127        WorkflowDocument document = WorkflowDocumentFactory.createDocument(getPrincipalIdForName("user1"), "SUApproveDocumentNotifications");
128        document.route("");
129        document = WorkflowDocumentFactory.loadDocument(getPrincipalIdForName("user2"), document.getDocumentId());
130        try {
131                document.approve("");
132        } catch (Exception e) {
133        }
134        TestUtilities.getExceptionThreader().join();
135        document = WorkflowDocumentFactory.loadDocument(getPrincipalIdForName("rkirkend"), document.getDocumentId());
136        assertEquals("Document status incorrect", DocumentStatus.EXCEPTION, document.getStatus());
137        document.superUserBlanketApprove("");
138        document = WorkflowDocumentFactory.loadDocument(getPrincipalIdForName("rkirkend"), document.getDocumentId());
139        assertEquals("Document status incorrect after blanket approve", DocumentStatus.PROCESSED, document.getStatus());
140        
141        List<ActionRequestValue> actionRequests = KEWServiceLocator.getActionRequestService().findPendingByDoc(document.getDocumentId());
142        assertFalse("Should be active requests for SU Approved document", actionRequests.isEmpty());
143        for (ActionRequestValue request: actionRequests) {
144                        assertEquals("Should be an ack notification request", ActionType.ACKNOWLEDGE, ActionType.fromCode(request.getActionRequested()) );
145                }
146    }
147    
148    @Test public void testSuperUserInitiatorApprove() throws Exception {
149                WorkflowDocument document = WorkflowDocumentFactory.createDocument(getPrincipalIdForName("ewestfal"), NotifySetup.DOCUMENT_TYPE_NAME);
150        assertTrue("WorkflowDocument should indicate ewestfal as SuperUser", document.isValidAction(ActionType.SU_BLANKET_APPROVE));
151        document.superUserBlanketApprove("");
152        assertEquals("Document status incorrect after super user approve", DocumentStatus.PROCESSED, document.getStatus());
153        List<ActionRequestValue> requests = KEWServiceLocator.getActionRequestService().findPendingByDoc(document.getDocumentId());
154        assertEquals("Should be active requests still", 2, requests.size() );//number of acks and fyi's configured through rules
155        for (ActionRequestValue request: requests) {
156                        if (request.isApproveOrCompleteRequest()) {
157                                fail("There should be no approve or complete requests after su approve");
158                        }
159                }
160        }
161        
162        @Test public void testSuperUserApproveWithNotifications() throws Exception {
163                WorkflowDocument document = WorkflowDocumentFactory.createDocument(getPrincipalIdForName("ewestfal"), "NotificationTestChild");
164        assertTrue("WorkflowDocument should indicate ewestfal as SuperUser", document.isValidAction(ActionType.SU_BLANKET_APPROVE));
165        document.superUserBlanketApprove("");
166        assertEquals("Document status incorrect after super user approve", DocumentStatus.PROCESSED, document.getStatus());
167        List requests = KEWServiceLocator.getActionRequestService().findPendingByDoc(document.getDocumentId());
168        assertTrue("Should be active requests still", requests.size() > 2);//number of acks and fyi's configured through rules - we need these for approvals too
169        for (Iterator iter = requests.iterator(); iter.hasNext();) {
170                        ActionRequestValue request = (ActionRequestValue) iter.next();
171                        if (request.isApproveOrCompleteRequest()) {
172                                fail("There should be no approve or complete requests after su approve");
173                        }
174                } 
175        }
176        
177        @Test public void testSuperUserApproveInvalidUser() throws Exception {
178                WorkflowDocument document = WorkflowDocumentFactory.createDocument(getPrincipalIdForName("ewestfal"), NotifySetup.DOCUMENT_TYPE_NAME);
179        document.route("");
180        
181        document = WorkflowDocumentFactory.loadDocument(getPrincipalIdForName("quickstart"), document.getDocumentId());
182        try {
183                assertFalse("WorkflowDocument should not indicate quickstart as SuperUser", document.isValidAction(ActionType.SU_BLANKET_APPROVE));
184                document.superUserBlanketApprove("");
185                fail("invalid user attempted to SuperUserApprove");
186        } catch (Exception e) {
187        }
188        
189        }
190        
191        @Test public void testSuperUserActionDisregardPostProcessing() throws Exception {
192                
193                String bmcgoughPrincipalId = getPrincipalIdForName("bmcgough");
194                
195            // verify that the post processor class still throws exceptions when post processing document
196        WorkflowDocument document = WorkflowDocumentFactory.loadDocument(getPrincipalIdForName("rkirkend"), generateDummyEnrouteDocument("ewestfal").getDocumentId());
197        try {
198            document.superUserBlanketApprove("");
199            fail("Document should throw exception from post processor");
200        } catch (Exception e) {
201        }
202        
203        // test that ignoring the post processor works correctly
204        document = WorkflowDocumentFactory.loadDocument(getPrincipalIdForName("rkirkend"), generateDummyEnrouteDocument("ewestfal").getDocumentId());
205        try {
206            KEWServiceLocator.getWorkflowDocumentService().superUserCancelAction(bmcgoughPrincipalId, KEWServiceLocator.getRouteHeaderService().getRouteHeader(document.getDocumentId()), "", false);
207        } catch (Exception e) {
208            LOG.error("Exception Found:", e);
209            fail("Document should not throw an exception when ignoring post processor during superUserCancelAction " + e.getClass().getName() + " : " + e.getMessage() );
210        }
211
212        document = WorkflowDocumentFactory.loadDocument(getPrincipalIdForName("rkirkend"), generateDummyEnrouteDocument("ewestfal").getDocumentId());
213        try {
214            KEWServiceLocator.getWorkflowDocumentService().superUserDisapproveAction(bmcgoughPrincipalId, KEWServiceLocator.getRouteHeaderService().getRouteHeader(document.getDocumentId()), "", false);
215        } catch (Exception e) {
216            LOG.error("Exception Found:", e);
217            fail("Document should not throw an exception when ignoring post processor during superUserDisapproveAction");
218        }
219
220        document = WorkflowDocumentFactory.loadDocument(getPrincipalIdForName("rkirkend"), generateDummyEnrouteDocument("ewestfal").getDocumentId());
221        try {
222            KEWServiceLocator.getWorkflowDocumentService().superUserApprove(bmcgoughPrincipalId, KEWServiceLocator.getRouteHeaderService().getRouteHeader(document.getDocumentId()), "", false);
223        } catch (Exception e) {
224            LOG.error("Exception Found:", e);
225            fail("Document should not throw an exception when ignoring post processor during superUserApprove");
226        }
227
228        document = WorkflowDocumentFactory.loadDocument(getPrincipalIdForName("rkirkend"), generateDummyEnrouteDocument("ewestfal").getDocumentId());
229        try {
230            KEWServiceLocator.getWorkflowDocumentService().superUserNodeApproveAction(bmcgoughPrincipalId, document.getDocumentId(), "Acknowledge1", "", false);
231        } catch (Exception e) {
232            LOG.error("Exception Found:", e);
233            fail("Document should not throw an exception when ignoring post processor during superUserNodeApprove");
234        }
235
236        document = WorkflowDocumentFactory.loadDocument(getPrincipalIdForName("rkirkend"), generateDummyEnrouteDocument("ewestfal").getDocumentId());
237        try {
238            KEWServiceLocator.getWorkflowDocumentService().superUserReturnDocumentToPreviousNode(bmcgoughPrincipalId, document.getDocumentId(), "WorkflowDocumentTemplate", "", false);
239        } catch (Exception e) {
240            LOG.error("Exception Found:", e);
241            fail("Document should not throw an exception when ignoring post processor during superUserReturnDocumentToPreviousNode");
242        }
243
244        document = WorkflowDocumentFactory.loadDocument(getPrincipalIdForName("rkirkend"), generateDummyEnrouteDocument("ewestfal").getDocumentId());
245        try {
246                String actionRequestId = null;
247            // get actionRequestId to use... there should only be one active action request
248            List<ActionRequest> actionRequests = KewApiServiceLocator.getWorkflowDocumentService().getRootActionRequests(document.getDocumentId());
249            for (ActionRequest actionRequest : actionRequests) {
250                if (actionRequest.isActivated()) {
251                    // if we already found an active action request fail the test
252                    if (actionRequestId != null) {
253                        fail("Found two active action requests for document.  Ids: " + actionRequestId + "  &  " + actionRequest.getId());
254                    }
255                    actionRequestId = actionRequest.getId();
256                }
257            }
258            
259            KEWServiceLocator.getWorkflowDocumentService().superUserActionRequestApproveAction(bmcgoughPrincipalId, document.getDocumentId(), actionRequestId, "", false);
260        } catch (Exception e) {
261            LOG.error("Exception Found:", e);
262            fail("Document should not throw an exception when ignoring post processor during superUserActionRequestApproveAction");
263        }
264
265        }
266        
267        private WorkflowDocument generateDummyEnrouteDocument(String initiatorNetworkId) throws Exception {
268        WorkflowDocument document = WorkflowDocumentFactory.createDocument(getPrincipalIdForName(initiatorNetworkId), "SuperUserActionInvalidPostProcessor");
269        assertEquals("Document should be at start node","AdHoc", document.getNodeNames().iterator().next());
270        document.route("");
271        assertEquals("Document should be at WorkflowDocument2 node","WorkflowDocument2", document.getNodeNames().iterator().next());
272        assertEquals("Document should be enroute", DocumentStatus.ENROUTE, document.getStatus());
273        return document;
274        }
275        
276        
277}