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.rule.service.impl;
017    
018    
019    import static org.junit.Assert.assertEquals;
020    import static org.junit.Assert.assertTrue;
021    import static org.junit.Assert.fail;
022    
023    import java.util.ArrayList;
024    import java.util.Iterator;
025    import java.util.List;
026    
027    import org.junit.Test;
028    import org.kuali.rice.core.api.exception.RiceIllegalArgumentException;
029    import org.kuali.rice.kew.actionrequest.ActionRequestValue;
030    import org.kuali.rice.kew.api.WorkflowDocument;
031    import org.kuali.rice.kew.api.WorkflowDocumentFactory;
032    import org.kuali.rice.kew.api.action.ActionRequestStatus;
033    import org.kuali.rice.kew.api.action.RecipientType;
034    import org.kuali.rice.kew.role.service.RoleService;
035    import org.kuali.rice.kew.routeheader.DocumentRouteHeaderValue;
036    import org.kuali.rice.kew.routemodule.TestDocContent;
037    import org.kuali.rice.kew.routemodule.TestRecipient;
038    import org.kuali.rice.kew.routemodule.TestResponsibility;
039    import org.kuali.rice.kew.routemodule.TestRouteLevel;
040    import org.kuali.rice.kew.routemodule.TestRouteModuleXMLHelper;
041    import org.kuali.rice.kew.rule.TestRuleAttribute;
042    import org.kuali.rice.kew.service.KEWServiceLocator;
043    import org.kuali.rice.kew.test.KEWTestCase;
044    import org.kuali.rice.kew.api.KewApiConstants;
045    import org.kuali.rice.kim.api.identity.principal.Principal;
046    
047    /**
048     * Tests the role re-resolving.  This test depends on the route queue being synchronous.
049     */
050    public class RoleServiceTest extends KEWTestCase {
051    
052            private static final String TEST_ROLE = "TestRole";
053            private static final String TEST_GROUP_1 = "TestGroup1";
054            private static final String TEST_GROUP_2 = "TestGroup2";
055            private RoleService roleService;
056            private String documentId;
057            private List<String> group1 = new ArrayList<String>();
058            private List<String> group2 = new ArrayList<String>();
059    
060    
061            protected void setUpAfterDataLoad() throws Exception {
062                    super.setUpAfterDataLoad();
063                    roleService = KEWServiceLocator.getRoleService();
064                    initializeAttribute();
065                    documentId = routeDocument();
066            }
067    
068            private void initializeAttribute() throws Exception {
069                    group1.add(getPrincipalIdForName("jhopf"));
070                    group1.add(getPrincipalIdForName("pmckown"));
071                    group2.add(getPrincipalIdForName("xqi"));
072                    group2.add(getPrincipalIdForName("tbazler"));
073                    TestRuleAttribute.addRole(TEST_ROLE);
074                    TestRuleAttribute.addQualifiedRole(TEST_ROLE, TEST_GROUP_1);
075                    TestRuleAttribute.addQualifiedRole(TEST_ROLE, TEST_GROUP_2);
076                    TestRuleAttribute.setRecipientPrincipalIds(TEST_ROLE, TEST_GROUP_1, group1);
077                    TestRuleAttribute.setRecipientPrincipalIds(TEST_ROLE, TEST_GROUP_2, group2);
078            }
079    
080            private String routeDocument() throws Exception {
081            WorkflowDocument document = WorkflowDocumentFactory.createDocument(getPrincipalIdForName("rkirkend"), "TestDocumentType");
082            document.setApplicationContent(TestRouteModuleXMLHelper.toXML(generateDocContent()));
083            document.route("testing only");
084            return document.getDocumentId();
085            }
086    
087            @Test public void testReResolveQualifiedRole() throws Exception {
088                    DocumentRouteHeaderValue loadedDocument = KEWServiceLocator.getRouteHeaderService().getRouteHeader(documentId);
089                    assertEquals(KewApiConstants.ROUTE_HEADER_ENROUTE_CD, loadedDocument.getDocRouteStatus());
090                    List requests = getTestRoleRequests(loadedDocument);
091                    assertEquals("Incorrect number of role control requests.", 2, requests.size());
092                    assertRequestGraphs(requests);
093    
094                    // change the membership in TEST_GROUP_1
095                    List<String> newGroup1Recipients = new ArrayList<String>();
096                    newGroup1Recipients.add(getPrincipalIdForName("bmcgough"));
097                    newGroup1Recipients.add(getPrincipalIdForName("xqi"));
098                    newGroup1Recipients.add(getPrincipalIdForName("rkirkend"));
099                    TestRuleAttribute.setRecipientPrincipalIds(TEST_ROLE, TEST_GROUP_1, newGroup1Recipients);
100                    roleService.reResolveQualifiedRole(loadedDocument, TEST_ROLE, TEST_GROUP_1);
101                    loadedDocument = KEWServiceLocator.getRouteHeaderService().getRouteHeader(documentId);
102                    assertEquals(KewApiConstants.ROUTE_HEADER_ENROUTE_CD, loadedDocument.getDocRouteStatus());
103                    requests = getTestRoleRequests(loadedDocument);
104            // rkirkend is the initiator so his action should count for the TEST_GROUP_1 role after re-resolving, leaving only a single role request
105                    assertEquals("Incorrect number of role control requests.", 1, requests.size());
106                    assertRequestGraphs(requests);
107                    assertInitiatorRequestDone(TEST_ROLE, TEST_GROUP_1);
108    
109            // if we attempt to re-resolve with an non-existant qualified role, it _should_ be legal
110            roleService.reResolveQualifiedRole(loadedDocument, TEST_ROLE, "random cool name");
111            requests = getTestRoleRequests(loadedDocument);
112            assertEquals("Incorrect number of role control requests.", 1, requests.size());
113            assertRequestGraphs(requests);
114            }
115    
116            @Test public void testReResolveQualifiedRoleErrors() throws Exception {
117            // attempting to re-resolve with null values should throw exceptions
118            try {
119                roleService.reResolveQualifiedRole((DocumentRouteHeaderValue)null, null, null);
120                fail("Exception should have been thrown when null values are passed.");
121            } catch (Exception e) {}
122    
123            DocumentRouteHeaderValue loadedDocument = KEWServiceLocator.getRouteHeaderService().getRouteHeader(documentId);
124            try {
125                roleService.reResolveQualifiedRole(loadedDocument, null, null);
126                fail("Exception should have been thrown when null values are passed.");
127            } catch (Exception e) {}
128    
129            // need to have a valid role name
130            try {
131                roleService.reResolveQualifiedRole(loadedDocument, "GimpyRoleName", TEST_GROUP_1);
132                fail("Exception should be thrown when attempting to re-resolve with a bad role name.");
133            } catch (Exception e) {}
134    
135            // now blanket approve a document to make it processed
136            WorkflowDocument document = WorkflowDocumentFactory.createDocument(getPrincipalIdForName("rkirkend"), "TestDocumentType");
137            document.setApplicationContent(TestRouteModuleXMLHelper.toXML(generateDocContent()));
138            document.blanketApprove("");
139            DocumentRouteHeaderValue baDoc = KEWServiceLocator.getRouteHeaderService().getRouteHeader(document.getDocumentId());
140            try {
141                roleService.reResolveQualifiedRole(baDoc, TEST_ROLE, TEST_GROUP_1);
142                fail("Shouldn't be able to resolve on a document with no active nodes.");
143            } catch (Exception e) {}
144    
145        }
146    
147            @Test public void testReResolveRole() throws Exception {
148                    DocumentRouteHeaderValue loadedDocument = KEWServiceLocator.getRouteHeaderService().getRouteHeader(documentId);
149                    assertEquals(KewApiConstants.ROUTE_HEADER_ENROUTE_CD, loadedDocument.getDocRouteStatus());
150                    List requests = getTestRoleRequests(loadedDocument);
151                    assertEquals("Incorrect number of role control requests.", 2, requests.size());
152                    assertRequestGraphs(requests);
153    
154                    // change membership in TEST_GROUP_1 and TEST_GROUP_2
155                    List<String> newGroup1 = new ArrayList<String>();
156                    List<String> newGroup2 = new ArrayList<String>();
157                    newGroup2.add(getPrincipalIdForName("ewestfal"));
158                    newGroup2.add(getPrincipalIdForName("jthomas"));
159                    // TEST_GROUP_1 should now be an empty role, therefore there should not be a request generated for it after re-resolution
160                    TestRuleAttribute.setRecipientPrincipalIds(TEST_ROLE, TEST_GROUP_1, newGroup1);
161                    TestRuleAttribute.setRecipientPrincipalIds(TEST_ROLE, TEST_GROUP_2, newGroup2);
162                    // re-resolve entire role
163                    roleService.reResolveRole(loadedDocument, TEST_ROLE);
164                    loadedDocument = KEWServiceLocator.getRouteHeaderService().getRouteHeader(documentId);
165                    assertEquals(KewApiConstants.ROUTE_HEADER_ENROUTE_CD, loadedDocument.getDocRouteStatus());
166                    requests = getTestRoleRequests(loadedDocument);
167                    // should be 1 because group 1 has no members
168                    assertEquals("Incorrect number of role control requests.", 1, requests.size());
169                    assertRequestGraphs(requests);
170            }
171    
172            @Test public void testReResolveRoleErrors() throws Exception {
173            // attempting to re-resolve with null values should throw exceptions
174            try {
175                roleService.reResolveRole((DocumentRouteHeaderValue)null, null);
176                fail("Exception should have been thrown when null values are passed.");
177            } catch (RiceIllegalArgumentException e) {}
178    
179            DocumentRouteHeaderValue loadedDocument = KEWServiceLocator.getRouteHeaderService().getRouteHeader(documentId);
180            try {
181                roleService.reResolveRole(loadedDocument, null);
182                fail("Exception should have been thrown when null values are passed.");
183            } catch (Exception e) {}
184    
185            // need to have a valid role name
186            try {
187                roleService.reResolveRole(loadedDocument, "GimpyRoleName");
188                fail("Exception should be thrown when attempting to re-resolve with a bad role name.");
189            } catch (Exception e) {}
190    
191            // now blanket approve a document to make it processed
192            WorkflowDocument document = WorkflowDocumentFactory.createDocument(getPrincipalIdForName("rkirkend"), "TestDocumentType");
193            document.setApplicationContent(TestRouteModuleXMLHelper.toXML(generateDocContent()));
194            document.blanketApprove("");
195            DocumentRouteHeaderValue baDoc = KEWServiceLocator.getRouteHeaderService().getRouteHeader(document.getDocumentId());
196            try {
197                roleService.reResolveRole(baDoc, TEST_ROLE);
198                fail("Shouldn't be able to re-resolve on a document with no active nodes.");
199            } catch (Exception e) {}
200        }
201    
202            /**
203             * Extract requests sent to TestRole.
204             */
205            private List getTestRoleRequests(DocumentRouteHeaderValue document) {
206                    List testRoleRequests = new ArrayList();
207                    List requests = KEWServiceLocator.getActionRequestService().findPendingRootRequestsByDocIdAtRouteLevel(document.getDocumentId(), document.getDocRouteLevel());
208                    for (Iterator iterator = requests.iterator(); iterator.hasNext();) {
209                            ActionRequestValue actionRequest = (ActionRequestValue) iterator.next();
210                            if (TEST_ROLE.equals(actionRequest.getRoleName())) {
211                                    testRoleRequests.add(actionRequest);
212                            }
213                    }
214                    return testRoleRequests;
215            }
216    
217            private void assertRequestGraphs(List requests) throws Exception {
218                    for (Iterator iterator = requests.iterator(); iterator.hasNext();) {
219                            ActionRequestValue request = (ActionRequestValue) iterator.next();
220                            if (TEST_GROUP_1.equals(request.getQualifiedRoleName())) {
221                                    assertQualifiedRoleRequest(request, TEST_ROLE, TEST_GROUP_1);
222                            } else if (TEST_GROUP_2.equals(request.getQualifiedRoleName())) {
223                                    assertQualifiedRoleRequest(request, TEST_ROLE, TEST_GROUP_2);
224                            }
225                    }
226            }
227    
228            private void assertQualifiedRoleRequest(ActionRequestValue request, String roleName, String qualifiedRoleName) throws Exception {
229                    assertActionRequest(request, roleName, qualifiedRoleName);
230                    List<String> recipients = TestRuleAttribute.getRecipientPrincipalIds(roleName, qualifiedRoleName);
231                    assertEquals("Incorrect number of children requests.", recipients.size(), request.getChildrenRequests().size());
232                    for (Iterator childIt = request.getChildrenRequests().iterator(); childIt.hasNext();) {
233                            ActionRequestValue childRequest = (ActionRequestValue) childIt.next();
234                            assertActionRequest(childRequest, roleName, qualifiedRoleName);
235                            assertTrue("Child request to invalid user: "+childRequest.getPrincipalId(), containsUser(recipients, childRequest.getPrincipalId()));
236                            assertEquals("Child request should have no children.", 0, childRequest.getChildrenRequests().size());
237                    }
238            }
239    
240            private void assertActionRequest(ActionRequestValue request, String roleName, String qualifiedRoleName) {
241                    assertEquals("Incorrect role name.", roleName, request.getRoleName());
242                    assertEquals("Incorrect qualified role name.", qualifiedRoleName, request.getQualifiedRoleName());
243                    assertEquals("Incorrect qualified role name label.", qualifiedRoleName, request.getQualifiedRoleNameLabel());
244                    assertTrue("Request should be activated or done.", ActionRequestStatus.ACTIVATED.getCode().equals(request.getStatus()) ||
245                                    ActionRequestStatus.DONE.getCode().equals(request.getStatus()));
246            }
247    
248            private boolean containsUser(List<String> principalIds, String principalId) throws Exception {
249                    return principalIds.contains(principalId);
250            }
251    
252            /**
253             * Gets all "DONE" action requests that are to the initiator (rkirkend).  It then verifies that the initiator has a
254             * complete request and a re-resolved request.
255             */
256            private void assertInitiatorRequestDone(String roleName, String qualifiedRoleNameLabel) throws Exception {
257            Principal initiator = KEWServiceLocator.getIdentityHelperService().getPrincipalByPrincipalName("rkirkend");
258                    List requests = KEWServiceLocator.getActionRequestService().findByStatusAndDocId(ActionRequestStatus.DONE.getCode(), documentId);
259                    for (Iterator iterator = requests.iterator(); iterator.hasNext();) {
260                            ActionRequestValue request = (ActionRequestValue) iterator.next();
261                            if (!initiator.getPrincipalId().equals(request.getPrincipalId())) {
262                                    iterator.remove();
263                            }
264                    }
265                    assertEquals("Initiator should have a complete request and their re-resolved request.", 2, requests.size());
266                    int roleRequestCount = 0;
267                    for (Iterator iterator = requests.iterator(); iterator.hasNext();) {
268                            ActionRequestValue actionRequest = (ActionRequestValue) iterator.next();
269                            if (TEST_ROLE.equals(actionRequest.getRoleName())) {
270                                    roleRequestCount++;
271                                    assertActionRequest(actionRequest, roleName, qualifiedRoleNameLabel);
272                                    assertTrue("Initiator request should have a parent.", actionRequest.getParentActionRequest() != null);
273                            }
274                    }
275                    assertEquals("There should be 1 DONE request from the result of the role re-resolve.", 1, roleRequestCount);
276            }
277    
278            private TestDocContent generateDocContent() {
279                    TestDocContent docContent = new TestDocContent();
280                    List routeLevels = new ArrayList();
281                    TestRouteLevel routeLevel1 = new TestRouteLevel();
282                    routeLevels.add(routeLevel1);
283                    docContent.setRouteLevels(routeLevels);
284                    routeLevel1.setPriority(1);
285                    List responsibilities = new ArrayList();
286                    routeLevel1.setResponsibilities(responsibilities);
287                    TestResponsibility responsibility1 = new TestResponsibility();
288                    responsibility1.setActionRequested(KewApiConstants.ACTION_REQUEST_APPROVE_REQ);
289                    responsibility1.setPriority(1);
290                    TestRecipient recipient1 = new TestRecipient();
291                    recipient1.setId(getPrincipalIdForName("rkirkend"));
292                    recipient1.setType(RecipientType.PRINCIPAL.getCode());
293                    responsibility1.setRecipient(recipient1);
294                    responsibilities.add(responsibility1);
295                    return docContent;
296            }
297    
298    }