View Javadoc
1   /**
2    * Copyright 2005-2014 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  import org.junit.Test;
19  import org.kuali.rice.core.api.exception.RiceIllegalArgumentException;
20  import org.kuali.rice.kew.actionrequest.ActionRequestValue;
21  import org.kuali.rice.kew.api.KewApiConstants;
22  import org.kuali.rice.kew.api.WorkflowDocument;
23  import org.kuali.rice.kew.api.WorkflowDocumentFactory;
24  import org.kuali.rice.kew.api.action.ActionRequestStatus;
25  import org.kuali.rice.kew.api.action.RecipientType;
26  import org.kuali.rice.kew.role.service.RoleService;
27  import org.kuali.rice.kew.routeheader.DocumentRouteHeaderValue;
28  import org.kuali.rice.kew.routemodule.TestDocContent;
29  import org.kuali.rice.kew.routemodule.TestRecipient;
30  import org.kuali.rice.kew.routemodule.TestResponsibility;
31  import org.kuali.rice.kew.routemodule.TestRouteLevel;
32  import org.kuali.rice.kew.routemodule.TestRouteModuleXMLHelper;
33  import org.kuali.rice.kew.rule.TestRuleAttribute;
34  import org.kuali.rice.kew.service.KEWServiceLocator;
35  import org.kuali.rice.kew.test.KEWTestCase;
36  import org.kuali.rice.kim.api.identity.principal.Principal;
37  
38  import java.util.ArrayList;
39  import java.util.Iterator;
40  import java.util.List;
41  
42  import static org.junit.Assert.*;
43  
44  /**
45   * Tests the role re-resolving.  This test depends on the route queue being synchronous.
46   */
47  public class RoleServiceTest extends KEWTestCase {
48  
49  	private static final String TEST_ROLE = "TestRole";
50  	private static final String TEST_GROUP_1 = "TestGroup1";
51  	private static final String TEST_GROUP_2 = "TestGroup2";
52  	private RoleService roleService;
53  	private String documentId;
54  	private List<String> group1 = new ArrayList<String>();
55  	private List<String> group2 = new ArrayList<String>();
56  
57  
58  	protected void setUpAfterDataLoad() throws Exception {
59  		super.setUpAfterDataLoad();
60  		roleService = KEWServiceLocator.getRoleService();
61  		initializeAttribute();
62  		documentId = routeDocument();
63  	}
64  
65  	private void initializeAttribute() throws Exception {
66  		group1.add(getPrincipalIdForName("jhopf"));
67  		group1.add(getPrincipalIdForName("pmckown"));
68  		group2.add(getPrincipalIdForName("xqi"));
69  		group2.add(getPrincipalIdForName("tbazler"));
70  		TestRuleAttribute.addRole(TEST_ROLE);
71  		TestRuleAttribute.addQualifiedRole(TEST_ROLE, TEST_GROUP_1);
72  		TestRuleAttribute.addQualifiedRole(TEST_ROLE, TEST_GROUP_2);
73  		TestRuleAttribute.setRecipientPrincipalIds(TEST_ROLE, TEST_GROUP_1, group1);
74  		TestRuleAttribute.setRecipientPrincipalIds(TEST_ROLE, TEST_GROUP_2, group2);
75  	}
76  
77  	private String routeDocument() throws Exception {
78          WorkflowDocument document = WorkflowDocumentFactory.createDocument(getPrincipalIdForName("rkirkend"), "TestDocumentType");
79          document.setApplicationContent(TestRouteModuleXMLHelper.toXML(generateDocContent()));
80          document.route("testing only");
81          return document.getDocumentId();
82  	}
83  
84  	@Test public void testReResolveQualifiedRole() throws Exception {
85  		DocumentRouteHeaderValue loadedDocument = KEWServiceLocator.getRouteHeaderService().getRouteHeader(documentId);
86  		assertEquals(KewApiConstants.ROUTE_HEADER_ENROUTE_CD, loadedDocument.getDocRouteStatus());
87  		List<ActionRequestValue> requests = getTestRoleRequests(loadedDocument);
88  		assertEquals("Incorrect number of role control requests.", 2, requests.size());
89  		assertRequestGraphs(requests);
90  
91  		// change the membership in TEST_GROUP_1
92  		List<String> newGroup1Recipients = new ArrayList<String>();
93  		newGroup1Recipients.add(getPrincipalIdForName("bmcgough"));
94  		newGroup1Recipients.add(getPrincipalIdForName("xqi"));
95  		newGroup1Recipients.add(getPrincipalIdForName("rkirkend"));
96  		TestRuleAttribute.setRecipientPrincipalIds(TEST_ROLE, TEST_GROUP_1, newGroup1Recipients);
97  		roleService.reResolveQualifiedRole(loadedDocument, TEST_ROLE, TEST_GROUP_1);
98  		loadedDocument = KEWServiceLocator.getRouteHeaderService().getRouteHeader(documentId);
99  		assertEquals(KewApiConstants.ROUTE_HEADER_ENROUTE_CD, loadedDocument.getDocRouteStatus());
100 		requests = getTestRoleRequests(loadedDocument);
101         // rkirkend is the initiator so his action should count for the TEST_GROUP_1 role after re-resolving, leaving only a single role request
102 		assertEquals("Incorrect number of role control requests.", 1, requests.size());
103 		assertRequestGraphs(requests);
104 		assertInitiatorRequestDone(TEST_ROLE, TEST_GROUP_1);
105 
106         // if we attempt to re-resolve with an non-existant qualified role, it _should_ be legal
107         roleService.reResolveQualifiedRole(loadedDocument, TEST_ROLE, "random cool name");
108         requests = getTestRoleRequests(loadedDocument);
109         assertEquals("Incorrect number of role control requests.", 1, requests.size());
110         assertRequestGraphs(requests);
111 	}
112 
113 	@Test public void testReResolveQualifiedRoleErrors() throws Exception {
114         // attempting to re-resolve with null values should throw exceptions
115         try {
116             roleService.reResolveQualifiedRole((DocumentRouteHeaderValue)null, null, null);
117             fail("Exception should have been thrown when null values are passed.");
118         } catch (Exception e) {}
119 
120         DocumentRouteHeaderValue loadedDocument = KEWServiceLocator.getRouteHeaderService().getRouteHeader(documentId);
121         try {
122             roleService.reResolveQualifiedRole(loadedDocument, null, null);
123             fail("Exception should have been thrown when null values are passed.");
124         } catch (Exception e) {}
125 
126         // need to have a valid role name
127         try {
128             roleService.reResolveQualifiedRole(loadedDocument, "GimpyRoleName", TEST_GROUP_1);
129             fail("Exception should be thrown when attempting to re-resolve with a bad role name.");
130         } catch (Exception e) {}
131 
132         // now blanket approve a document to make it processed
133         WorkflowDocument document = WorkflowDocumentFactory.createDocument(getPrincipalIdForName("rkirkend"), "TestDocumentType");
134         document.setApplicationContent(TestRouteModuleXMLHelper.toXML(generateDocContent()));
135         document.blanketApprove("");
136         DocumentRouteHeaderValue baDoc = KEWServiceLocator.getRouteHeaderService().getRouteHeader(document.getDocumentId());
137         try {
138             roleService.reResolveQualifiedRole(baDoc, TEST_ROLE, TEST_GROUP_1);
139             fail("Shouldn't be able to resolve on a document with no active nodes.");
140         } catch (Exception e) {}
141 
142     }
143 
144 	@Test public void testReResolveRole() throws Exception {
145 		DocumentRouteHeaderValue loadedDocument = KEWServiceLocator.getRouteHeaderService().getRouteHeader(documentId);
146 		assertEquals(KewApiConstants.ROUTE_HEADER_ENROUTE_CD, loadedDocument.getDocRouteStatus());
147 		List<ActionRequestValue> requests = getTestRoleRequests(loadedDocument);
148 		assertEquals("Incorrect number of role control requests.", 2, requests.size());
149 		assertRequestGraphs(requests);
150 
151 		// change membership in TEST_GROUP_1 and TEST_GROUP_2
152 		List<String> newGroup1 = new ArrayList<String>();
153 		List<String> newGroup2 = new ArrayList<String>();
154 		newGroup2.add(getPrincipalIdForName("ewestfal"));
155 		newGroup2.add(getPrincipalIdForName("jthomas"));
156 		// TEST_GROUP_1 should now be an empty role, therefore there should not be a request generated for it after re-resolution
157 		TestRuleAttribute.setRecipientPrincipalIds(TEST_ROLE, TEST_GROUP_1, newGroup1);
158 		TestRuleAttribute.setRecipientPrincipalIds(TEST_ROLE, TEST_GROUP_2, newGroup2);
159 		// re-resolve entire role
160 		roleService.reResolveRole(loadedDocument, TEST_ROLE);
161 		loadedDocument = KEWServiceLocator.getRouteHeaderService().getRouteHeader(documentId);
162 		assertEquals(KewApiConstants.ROUTE_HEADER_ENROUTE_CD, loadedDocument.getDocRouteStatus());
163 		requests = getTestRoleRequests(loadedDocument);
164 		// should be 1 because group 1 has no members
165 		assertEquals("Incorrect number of role control requests.", 1, requests.size());
166 		assertRequestGraphs(requests);
167 	}
168 
169 	@Test public void testReResolveRoleErrors() throws Exception {
170         // attempting to re-resolve with null values should throw exceptions
171         try {
172             roleService.reResolveRole((DocumentRouteHeaderValue)null, null);
173             fail("Exception should have been thrown when null values are passed.");
174         } catch (RiceIllegalArgumentException e) {}
175 
176         DocumentRouteHeaderValue loadedDocument = KEWServiceLocator.getRouteHeaderService().getRouteHeader(documentId);
177         try {
178             roleService.reResolveRole(loadedDocument, null);
179             fail("Exception should have been thrown when null values are passed.");
180         } catch (Exception e) {}
181 
182         // need to have a valid role name
183         try {
184             roleService.reResolveRole(loadedDocument, "GimpyRoleName");
185             fail("Exception should be thrown when attempting to re-resolve with a bad role name.");
186         } catch (Exception e) {}
187 
188         // now blanket approve a document to make it processed
189         WorkflowDocument document = WorkflowDocumentFactory.createDocument(getPrincipalIdForName("rkirkend"), "TestDocumentType");
190         document.setApplicationContent(TestRouteModuleXMLHelper.toXML(generateDocContent()));
191         document.blanketApprove("");
192         DocumentRouteHeaderValue baDoc = KEWServiceLocator.getRouteHeaderService().getRouteHeader(document.getDocumentId());
193         try {
194             roleService.reResolveRole(baDoc, TEST_ROLE);
195             fail("Shouldn't be able to re-resolve on a document with no active nodes.");
196         } catch (Exception e) {}
197     }
198 
199 	/**
200 	 * Extract requests sent to TestRole.
201 	 */
202 	private List<ActionRequestValue> getTestRoleRequests(DocumentRouteHeaderValue document) {
203 		List<ActionRequestValue> testRoleRequests = new ArrayList();
204 		List<ActionRequestValue> requests = KEWServiceLocator.getActionRequestService().findPendingRootRequestsByDocId(document.getDocumentId());
205         for (ActionRequestValue actionRequest : requests) {
206 			if (TEST_ROLE.equals(actionRequest.getRoleName())) {
207 				testRoleRequests.add(actionRequest);
208 			}
209 		}
210 		return testRoleRequests;
211 	}
212 
213 	private void assertRequestGraphs(List<ActionRequestValue> requests) throws Exception {
214         for (ActionRequestValue request : requests) {
215 			if (TEST_GROUP_1.equals(request.getQualifiedRoleName())) {
216 				assertQualifiedRoleRequest(request, TEST_ROLE, TEST_GROUP_1);
217 			} else if (TEST_GROUP_2.equals(request.getQualifiedRoleName())) {
218 				assertQualifiedRoleRequest(request, TEST_ROLE, TEST_GROUP_2);
219 			}
220 		}
221 	}
222 
223 	private void assertQualifiedRoleRequest(ActionRequestValue request, String roleName, String qualifiedRoleName) throws Exception {
224 		assertActionRequest(request, roleName, qualifiedRoleName);
225 		List<String> recipients = TestRuleAttribute.getRecipientPrincipalIds(roleName, qualifiedRoleName);
226 		assertEquals("Incorrect number of children requests.", recipients.size(), request.getChildrenRequests().size());
227 		for (ActionRequestValue childRequest : request.getChildrenRequests()) {
228 			assertActionRequest(childRequest, roleName, qualifiedRoleName);
229 			assertTrue("Child request to invalid user: "+childRequest.getPrincipalId(), containsUser(recipients, childRequest.getPrincipalId()));
230 			assertEquals("Child request should have no children.", 0, childRequest.getChildrenRequests().size());
231 		}
232 	}
233 
234 	private void assertActionRequest(ActionRequestValue request, String roleName, String qualifiedRoleName) {
235 		assertEquals("Incorrect role name.", roleName, request.getRoleName());
236 		assertEquals("Incorrect qualified role name.", qualifiedRoleName, request.getQualifiedRoleName());
237 		assertEquals("Incorrect qualified role name label.", qualifiedRoleName, request.getQualifiedRoleNameLabel());
238 		assertTrue("Request should be activated or done.", ActionRequestStatus.ACTIVATED.getCode().equals(request.getStatus()) ||
239 				ActionRequestStatus.DONE.getCode().equals(request.getStatus()));
240 	}
241 
242 	private boolean containsUser(List<String> principalIds, String principalId) throws Exception {
243 		return principalIds.contains(principalId);
244 	}
245 
246 	/**
247 	 * Gets all "DONE" action requests that are to the initiator (rkirkend).  It then verifies that the initiator has a
248 	 * complete request and a re-resolved request.
249 	 */
250 	private void assertInitiatorRequestDone(String roleName, String qualifiedRoleNameLabel) throws Exception {
251         Principal initiator = KEWServiceLocator.getIdentityHelperService().getPrincipalByPrincipalName("rkirkend");
252 		List<ActionRequestValue> requests =
253                 new ArrayList<ActionRequestValue>(KEWServiceLocator.getActionRequestService().findByStatusAndDocId(ActionRequestStatus.DONE.getCode(), documentId));
254 		for (Iterator<ActionRequestValue> iterator = requests.iterator(); iterator.hasNext();) {
255 			ActionRequestValue request = iterator.next();
256 			if (!initiator.getPrincipalId().equals(request.getPrincipalId())) {
257 				iterator.remove();
258 			}
259 		}
260 		assertEquals("Initiator should have a complete request and their re-resolved request.", 2, requests.size());
261 		int roleRequestCount = 0;
262         for (ActionRequestValue actionRequest : requests) {
263 			if (TEST_ROLE.equals(actionRequest.getRoleName())) {
264 				roleRequestCount++;
265 				assertActionRequest(actionRequest, roleName, qualifiedRoleNameLabel);
266 				assertTrue("Initiator request should have a parent.", actionRequest.getParentActionRequest() != null);
267 			}
268 		}
269 		assertEquals("There should be 1 DONE request from the result of the role re-resolve.", 1, roleRequestCount);
270 	}
271 
272 	private TestDocContent generateDocContent() {
273 		TestDocContent docContent = new TestDocContent();
274 		List<TestRouteLevel> routeLevels = new ArrayList<TestRouteLevel>();
275 		TestRouteLevel routeLevel1 = new TestRouteLevel();
276 		routeLevels.add(routeLevel1);
277 		docContent.setRouteLevels(routeLevels);
278 		routeLevel1.setPriority(1);
279 		List<TestResponsibility> responsibilities = new ArrayList<TestResponsibility>();
280 		routeLevel1.setResponsibilities(responsibilities);
281 		TestResponsibility responsibility1 = new TestResponsibility();
282 		responsibility1.setActionRequested(KewApiConstants.ACTION_REQUEST_APPROVE_REQ);
283 		responsibility1.setPriority(1);
284 		TestRecipient recipient1 = new TestRecipient();
285 		recipient1.setId(getPrincipalIdForName("rkirkend"));
286 		recipient1.setType(RecipientType.PRINCIPAL.getCode());
287 		responsibility1.setRecipient(recipient1);
288 		responsibilities.add(responsibility1);
289 		return docContent;
290 	}
291 
292 }