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 }