View Javadoc

1   /**
2    * Copyright 2005-2011 The Kuali Foundation
3    *
4    * Licensed under the Educational Community License, Version 2.0 (the "License");
5    * you may not use this file except in compliance with the License.
6    * You may obtain a copy of the License at
7    *
8    * http://www.opensource.org/licenses/ecl2.php
9    *
10   * Unless required by applicable law or agreed to in writing, software
11   * distributed under the License is distributed on an "AS IS" BASIS,
12   * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13   * See the License for the specific language governing permissions and
14   * limitations under the License.
15   */
16  package org.kuali.rice.kew.rule.service.impl;
17  
18  
19  import static org.junit.Assert.assertEquals;
20  import static org.junit.Assert.assertTrue;
21  import static org.junit.Assert.fail;
22  
23  import java.util.ArrayList;
24  import java.util.Iterator;
25  import java.util.List;
26  
27  import org.junit.Test;
28  import org.kuali.rice.core.api.exception.RiceIllegalArgumentException;
29  import org.kuali.rice.kew.actionrequest.ActionRequestValue;
30  import org.kuali.rice.kew.api.WorkflowDocument;
31  import org.kuali.rice.kew.api.WorkflowDocumentFactory;
32  import org.kuali.rice.kew.api.action.ActionRequestStatus;
33  import org.kuali.rice.kew.api.action.RecipientType;
34  import org.kuali.rice.kew.role.service.RoleService;
35  import org.kuali.rice.kew.routeheader.DocumentRouteHeaderValue;
36  import org.kuali.rice.kew.routemodule.TestDocContent;
37  import org.kuali.rice.kew.routemodule.TestRecipient;
38  import org.kuali.rice.kew.routemodule.TestResponsibility;
39  import org.kuali.rice.kew.routemodule.TestRouteLevel;
40  import org.kuali.rice.kew.routemodule.TestRouteModuleXMLHelper;
41  import org.kuali.rice.kew.rule.TestRuleAttribute;
42  import org.kuali.rice.kew.service.KEWServiceLocator;
43  import org.kuali.rice.kew.test.KEWTestCase;
44  import org.kuali.rice.kew.api.KewApiConstants;
45  import org.kuali.rice.kim.api.identity.principal.Principal;
46  
47  /**
48   * Tests the role re-resolving.  This test depends on the route queue being synchronous.
49   */
50  public class RoleServiceTest extends KEWTestCase {
51  
52  	private static final String TEST_ROLE = "TestRole";
53  	private static final String TEST_GROUP_1 = "TestGroup1";
54  	private static final String TEST_GROUP_2 = "TestGroup2";
55  	private RoleService roleService;
56  	private String documentId;
57  	private List<String> group1 = new ArrayList<String>();
58  	private List<String> group2 = new ArrayList<String>();
59  
60  
61  	protected void setUpAfterDataLoad() throws Exception {
62  		super.setUpAfterDataLoad();
63  		roleService = KEWServiceLocator.getRoleService();
64  		initializeAttribute();
65  		documentId = routeDocument();
66  	}
67  
68  	private void initializeAttribute() throws Exception {
69  		group1.add(getPrincipalIdForName("jhopf"));
70  		group1.add(getPrincipalIdForName("pmckown"));
71  		group2.add(getPrincipalIdForName("xqi"));
72  		group2.add(getPrincipalIdForName("tbazler"));
73  		TestRuleAttribute.addRole(TEST_ROLE);
74  		TestRuleAttribute.addQualifiedRole(TEST_ROLE, TEST_GROUP_1);
75  		TestRuleAttribute.addQualifiedRole(TEST_ROLE, TEST_GROUP_2);
76  		TestRuleAttribute.setRecipientPrincipalIds(TEST_ROLE, TEST_GROUP_1, group1);
77  		TestRuleAttribute.setRecipientPrincipalIds(TEST_ROLE, TEST_GROUP_2, group2);
78  	}
79  
80  	private String routeDocument() throws Exception {
81          WorkflowDocument document = WorkflowDocumentFactory.createDocument(getPrincipalIdForName("rkirkend"), "TestDocumentType");
82          document.setApplicationContent(TestRouteModuleXMLHelper.toXML(generateDocContent()));
83          document.route("testing only");
84          return document.getDocumentId();
85  	}
86  
87  	@Test public void testReResolveQualifiedRole() throws Exception {
88  		DocumentRouteHeaderValue loadedDocument = KEWServiceLocator.getRouteHeaderService().getRouteHeader(documentId);
89  		assertEquals(KewApiConstants.ROUTE_HEADER_ENROUTE_CD, loadedDocument.getDocRouteStatus());
90  		List requests = getTestRoleRequests(loadedDocument);
91  		assertEquals("Incorrect number of role control requests.", 2, requests.size());
92  		assertRequestGraphs(requests);
93  
94  		// change the membership in TEST_GROUP_1
95  		List<String> newGroup1Recipients = new ArrayList<String>();
96  		newGroup1Recipients.add(getPrincipalIdForName("bmcgough"));
97  		newGroup1Recipients.add(getPrincipalIdForName("xqi"));
98  		newGroup1Recipients.add(getPrincipalIdForName("rkirkend"));
99  		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 }