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.actionitem;
17  
18  import org.junit.Test;
19  import org.kuali.rice.kew.actionlist.service.ActionListService;
20  import org.kuali.rice.kew.api.WorkflowDocument;
21  import org.kuali.rice.kew.api.WorkflowDocumentFactory;
22  import org.kuali.rice.kew.api.action.ActionRequest;
23  import org.kuali.rice.kew.api.action.ActionRequestType;
24  import org.kuali.rice.kew.service.KEWServiceLocator;
25  import org.kuali.rice.kew.test.KEWTestCase;
26  import org.kuali.rice.kim.api.KimConstants;
27  import org.kuali.rice.kim.api.group.Group;
28  import org.kuali.rice.kim.api.group.GroupMember;
29  import org.kuali.rice.kim.api.group.GroupService;
30  import org.kuali.rice.kim.api.identity.principal.Principal;
31  import org.kuali.rice.kim.api.services.KimApiServiceLocator;
32  import org.kuali.rice.test.BaselineTestCase;
33  
34  import java.util.ArrayList;
35  import java.util.Collection;
36  import java.util.Iterator;
37  import java.util.List;
38  
39  import static org.junit.Assert.*;
40  @BaselineTestCase.BaselineMode(BaselineTestCase.Mode.CLEAR_DB)
41  public class ActionItemServiceTest extends KEWTestCase {
42  
43  	private ActionListService actionListService;
44  
45      protected void loadTestData() throws Exception {
46      	loadXmlFile("ActionItemConfig.xml");
47      }
48  
49      protected void setUpAfterDataLoad() throws Exception {
50  		super.setUpAfterDataLoad();
51  		actionListService = KEWServiceLocator.getActionListService();
52  	}
53  
54  	/**
55       * When workgroup membership changes all action items to that workgroup need to reflect
56       * the new membership
57       *
58       * @throws Exception
59       */
60      @Test public void testUpdateActionItemsForWorkgroupChange() throws Exception {
61  
62          WorkflowDocument document = WorkflowDocumentFactory.createDocument(getPrincipalIdForName("user1"), "ActionItemDocumentType");
63          document.setTitle("");
64          document.route("");
65  
66          Group oldWorkgroup = KimApiServiceLocator.getGroupService().getGroupByNamespaceCodeAndName("KR-WKFLW",
67                  "AIWG-Admin");
68          //Group oldWorkgroup = this.getGroupImpl(oldGroup.getId());
69  
70  
71          GroupService groupService = KimApiServiceLocator.getGroupService();
72          assertEquals("Workgroup should have 6 members.", 6, groupService.getMembersOfGroup(oldWorkgroup.getId()).size());
73  
74          Principal user1 = KimApiServiceLocator.getIdentityService().getPrincipalByPrincipalName("user1");
75          Principal user2 = KimApiServiceLocator.getIdentityService().getPrincipalByPrincipalName("user2");
76  
77          Principal rkirkend = KimApiServiceLocator.getIdentityService().getPrincipalByPrincipalName("rkirkend");
78          Principal shenl = KimApiServiceLocator.getIdentityService().getPrincipalByPrincipalName("shenl");
79  
80          List<GroupMember> usersToRemove = new ArrayList<GroupMember>();
81          //remove 'rkirkend' and 'shenl' from the workgroup
82          Collection<GroupMember> members = groupService.getMembersOfGroup(oldWorkgroup.getId());
83          for (GroupMember recipient : members) {
84          		if (recipient.getMemberId().equals(rkirkend.getPrincipalId()) || recipient.getMemberId().equals(shenl.getPrincipalId())) {
85          			KimApiServiceLocator.getGroupService().removePrincipalFromGroup(recipient.getMemberId(), oldWorkgroup.getId());
86          		}
87  
88          }
89  
90          List<GroupMember> loadedNewGroupMembers = groupService.getMembersOfGroup(oldWorkgroup.getId());
91          assertEquals("Workgroup should now have 4 members.", 4, loadedNewGroupMembers.size());
92  
93          //add user1 and user2
94          KimApiServiceLocator.getGroupService().addPrincipalToGroup(user1.getPrincipalId(), oldWorkgroup.getId());
95          KimApiServiceLocator.getGroupService().addPrincipalToGroup(user2.getPrincipalId(), oldWorkgroup.getId());
96  
97  
98          // verify that the new workgroup is sane...
99          Group loadedNewWorkgroup = this.getGroup(oldWorkgroup.getId());
100 
101         boolean foundUser1 = false;
102         boolean foundUser2 = false;
103         loadedNewGroupMembers = groupService.getMembersOfGroup(loadedNewWorkgroup.getId());
104         assertEquals("Workgroup should have 6 members.", 6, loadedNewGroupMembers.size());
105 
106 
107         for (GroupMember recipient : loadedNewGroupMembers) {
108     		if (recipient.getMemberId().equals(user1.getPrincipalId())){
109     			foundUser1 = true;
110     		} else if (recipient.getMemberId().equals(user2.getPrincipalId())){
111     			foundUser2 = true;
112     		}
113     }
114 
115         assertTrue("Did not find user 1 on workgroup.", foundUser1);
116         assertTrue("Did not find user 2 on workgroup.", foundUser2);
117 
118         Collection actionItems = KEWServiceLocator.getActionListService().findByDocumentId(document.getDocumentId());
119         boolean foundrkirkend = false;
120         boolean foundlshen = false;
121         boolean founduser1 = false;
122         boolean founduser2 = false;
123 
124         for (Iterator iter = actionItems.iterator(); iter.hasNext();) {
125             ActionItem actionItem = (ActionItem) iter.next();
126             String authId = actionItem.getPrincipal().getPrincipalName();
127             if (authId.equals("rkirkend")) {
128                 foundrkirkend = true;
129             } else if (authId.equals("user1")) {
130                 founduser1 = true;
131             } else if (authId.equals("lshen")) {
132                 foundlshen = true;
133             } else if (authId.equals("user2")) {
134                 founduser2 = true;
135             }
136         }
137 
138         assertTrue("rkirkend should still have an AI because he is in 2 workgroups that are routed to.", foundrkirkend);
139         assertTrue("user1 should have an AI because they were added to 'AIWG-Admin'", founduser1);
140         assertTrue("user2 should have an AI because they were added to 'AIWG-Admin'", founduser2);
141         assertFalse("lshen should not have an AI because they were removed from 'AIWG-Admin'", foundlshen);
142 
143     }
144 
145     /**
146      * When workgroup membership changes all action items to that workgroup need to reflect
147      * the new membership even in the case of nested workgroups.
148      *
149      * @throws Exception
150      */
151 
152     @Test public void testUpdateActionItemsForNestedGroupChange() throws Exception {
153 
154         WorkflowDocument document = WorkflowDocumentFactory.createDocument(getPrincipalIdForName("user1"), "ActionItemDocumentType");
155         document.setTitle("");
156 
157         Group workgroup1 = KimApiServiceLocator.getGroupService().getGroupByNamespaceCodeAndName("KR-WKFLW",
158                 "AIWG-Admin");
159         document.adHocToGroup(ActionRequestType.APPROVE, "",workgroup1.getId(), "", true);
160         document.route("");
161 
162         Principal ewestfal = KimApiServiceLocator.getIdentityService().getPrincipalByPrincipalName("ewestfal");
163 
164         assertEquals("User should have 1 action item", 1, KEWServiceLocator.getActionListService().findByPrincipalId(ewestfal.getPrincipalId()).size());
165         assertEquals("Workgroup should have 6 members.", 6, KimApiServiceLocator.getGroupService().getMemberPrincipalIds(workgroup1.getId()).size());
166         KimApiServiceLocator.getGroupService().removePrincipalFromGroup(ewestfal.getPrincipalId(), workgroup1.getId());
167 
168         assertEquals("Workgroup should have 5 members.", 5,
169                 KimApiServiceLocator.getGroupService().getMemberPrincipalIds(workgroup1.getId()).size());
170         assertEquals("User should have 0 action item", 0, KEWServiceLocator.getActionListService().findByPrincipalId(ewestfal.getPrincipalId()).size());
171 
172          KimApiServiceLocator.getGroupService().addPrincipalToGroup(ewestfal.getPrincipalId(), workgroup1.getId());
173          assertEquals("Workgroup should have 6 members.", 6, KimApiServiceLocator.getGroupService().getMemberPrincipalIds(workgroup1.getId()).size());
174          assertEquals("User should have 1 action item", 1, KEWServiceLocator.getActionListService().findByPrincipalId(ewestfal.getPrincipalId()).size());
175 
176 
177          // test the save group
178          Group workgroup1Impl = this.getGroup(workgroup1.getId());
179          Principal dewey = KimApiServiceLocator.getIdentityService().getPrincipalByPrincipalName("dewey");
180          KimApiServiceLocator.getGroupService().addPrincipalToGroup(dewey.getPrincipalId(), workgroup1Impl.getId());
181          //GroupMember groupMember = GroupMember.Builder.create(workgroup1Impl.getId(), dewey.getPrincipalId(), KimGroupMemberTypes.PRINCIPAL_MEMBER_TYPE).build();
182          //GroupBo workgroup1Bo = GroupBo.from(workgroup1Impl);
183          //workgroup1Bo.getMembersOfGroup().add(GroupMemberBo.from(groupMember));
184          //workgroup1Impl.getMembersOfGroup().add(groupMember);
185 
186          //KimImplServiceLocator.getGroupInternalService().saveWorkgroup(workgroup1Bo);
187 
188          assertEquals("Workgroup should have 7 members.", 7, KimApiServiceLocator.getGroupService().getMemberPrincipalIds(workgroup1.getId()).size());
189          assertEquals("User should have 1 action item", 1, KEWServiceLocator.getActionListService().findByPrincipalId(dewey.getPrincipalId()).size());
190 
191          // test nested
192          Principal user1 = KimApiServiceLocator.getIdentityService().getPrincipalByPrincipalName("user1");
193 
194          document = WorkflowDocumentFactory.createDocument(getPrincipalIdForName("jhopf"), "ActionItemDocumentType");
195          document.setTitle("");
196 
197          workgroup1 = KimApiServiceLocator.getGroupService().getGroupByNamespaceCodeAndName("KR-WKFLW", "AIWG-Nested1");
198          document.adHocToGroup(ActionRequestType.APPROVE, "",workgroup1.getId(), "", true);
199          document.route("");
200 
201          assertEquals("User should have 1 action item", 1, KEWServiceLocator.getActionListService().findByPrincipalId(user1.getPrincipalId()).size());
202          assertEquals("Workgroup should have 6 members.", 6, KimApiServiceLocator.getGroupService().getMemberPrincipalIds(workgroup1.getId()).size());
203 
204          //get the subgroup so we can remove the member.
205          Group workgroupSub = KimApiServiceLocator.getGroupService().getGroupByNamespaceCodeAndName("KR-WKFLW",
206                  "AIWG-Nested2");
207          KimApiServiceLocator.getGroupService().removePrincipalFromGroup(user1.getPrincipalId(), workgroupSub.getId());
208 
209          assertEquals("Workgroup should have 5 members.", 5, KimApiServiceLocator.getGroupService().getMemberPrincipalIds(workgroup1.getId()).size());
210          assertEquals("User should have 0 action item", 0, KEWServiceLocator.getActionListService().findByPrincipalId(user1.getPrincipalId()).size());
211 
212           KimApiServiceLocator.getGroupService().addPrincipalToGroup(user1.getPrincipalId(), workgroupSub.getId());
213           assertEquals("Workgroup should have 6 members.", 6, KimApiServiceLocator.getGroupService().getMemberPrincipalIds(workgroup1.getId()).size());
214           assertEquals("User should have 1 action item", 1, KEWServiceLocator.getActionListService().findByPrincipalId(user1.getPrincipalId()).size());
215 
216     }
217 
218     /**
219      * addresses the following bug http://fms.dfa.cornell.edu:8080/browse/KULWF-428
220      *
221      * @throws Exception
222      */
223     @Test public void testWorkgroupActionItemGenerationWhenMultipleWorkgroupRequests() throws Exception {
224         WorkflowDocument document = WorkflowDocumentFactory.createDocument(getPrincipalIdForName("user1"), "ActionItemDocumentType");
225         document.setTitle("");
226         document.route("");
227 
228         document = WorkflowDocumentFactory.loadDocument(getPrincipalIdForName("jitrue"), document.getDocumentId());
229 
230         Group testGroup = KimApiServiceLocator.getGroupService().getGroupByNamespaceCodeAndName(
231                 KimConstants.KIM_GROUP_WORKFLOW_NAMESPACE_CODE, "AIWG-Test");
232         Group adminGroup = KimApiServiceLocator.getGroupService().getGroupByNamespaceCodeAndName(
233                 KimConstants.KIM_GROUP_WORKFLOW_NAMESPACE_CODE, "AIWG-Admin");
234 
235         List<ActionRequest> ars = document.getRootActionRequests();
236         boolean routedWorkflowAdmin = false;
237         boolean routedTestWorkgroup = false;
238         for (ActionRequest request : ars) {
239             if (request.isGroupRequest() && testGroup.getId().equals(request.getGroupId())) {
240                 routedTestWorkgroup = true;
241             } else if (request.isGroupRequest() && adminGroup.getId().equals(request.getGroupId())) {
242                 routedWorkflowAdmin = true;
243             }
244         }
245 
246         //verify that our test is sane
247         assertTrue("Should have routed to 'AIWG-Test'", routedTestWorkgroup);
248         assertTrue("Should have routed to 'AIWG-Admin'", routedWorkflowAdmin);
249         assertTrue("Approve should be requested to member of 'AIWG-Test'", document.isApprovalRequested());
250 
251         document.approve("");
252 
253         Collection actionItems = KEWServiceLocator.getActionListService().findByDocumentId(document.getDocumentId());
254 
255         assertEquals("There should be 6 action items to the AIWG-Admin.", 6, actionItems.size());
256 
257         for (Iterator iter = actionItems.iterator(); iter.hasNext();) {
258             ActionItem actionItem = (ActionItem)iter.next();
259             //don't worry about which workgroup - they can get activated in any order
260             assertNotNull("this should be a workgroup request", actionItem.getGroup());
261         }
262     }
263 
264     /**
265      * This test verifies that if someone gets more than one request routed to them then they will get
266      * multiple Action Items but only one of them will show up in their Action List.
267      */
268     @Test public void testMultipleActionItemGeneration() throws Exception {
269     	WorkflowDocument document = WorkflowDocumentFactory.createDocument(getPrincipalIdForName("user1"), "ActionItemDocumentType");
270         document.setTitle("");
271         document.route("");
272 
273         // now the document should be at both the AIWG-Admin workgroup and the AIWG-Test
274         // ewestfal is a member of both Workgroups so verify that he has two action items
275         String ewestfalPrincipalId = getPrincipalIdForName("ewestfal");
276         String jitruePrincipalId = getPrincipalIdForName("jitrue");
277 
278         Collection actionItems = KEWServiceLocator.getActionListService().findByWorkflowUserDocumentId(ewestfalPrincipalId, document.getDocumentId());
279         assertEquals("Ewestfal should have two action items.", 2, actionItems.size());
280 
281         // now check the action list, there should be only one entry
282         actionItems = KEWServiceLocator.getActionListService().getActionList(ewestfalPrincipalId, null);
283         assertEquals("Ewestfal should have one action item in his action list.", 1, actionItems.size());
284         document = WorkflowDocumentFactory.loadDocument(ewestfalPrincipalId, document.getDocumentId());
285         assertTrue("Ewestfal should have an approval requested.", document.isApprovalRequested());
286 
287         // approve as a member from the first workgroup
288         document = WorkflowDocumentFactory.loadDocument(jitruePrincipalId, document.getDocumentId());
289         assertTrue("Jitrue should have an approval requested.", document.isApprovalRequested());
290         document.approve("");
291 
292         // now ewestfal should have only one action item in both his action items and his action list
293         actionItems = KEWServiceLocator.getActionListService().findByWorkflowUserDocumentId(ewestfalPrincipalId, document.getDocumentId());
294         assertEquals("Ewestfal should have one action item.", 1, actionItems.size());
295         String actionItemId = ((ActionItem)actionItems.iterator().next()).getId();
296         actionItems = KEWServiceLocator.getActionListService().getActionList(ewestfalPrincipalId, null);
297         assertEquals("Ewestfal should have one action item in his action list.", 1, actionItems.size());
298         assertEquals("The two action items should be the same.", actionItemId, ((ActionItem)actionItems.iterator().next()).getId());
299     }
300 
301     /**
302      * This tests verifies that bug KULWF-507 has been fixed:
303      *
304      * https://test.kuali.org/jira/browse/KULWF-507
305      *
306      * To fix this, we implemented the system so that multiple action items are generated rather then just
307      * one which gets reassigned across multiple requests as needed.
308      *
309      * This test verifies that after the blanket approval, there should no longer be an orphaned Acknowledge
310      * request.  The workgroup used here is the TestWorkgroup and "user1" is ewestfal with "user2" as rkirkend.
311      *
312      * The routing is configured in the BAOrphanedRequestDocumentType.
313      */
314     @Test public void testOrphanedAcknowledgeFromBlanketApprovalFix() throws Exception {
315     	WorkflowDocument document = WorkflowDocumentFactory.createDocument(getPrincipalIdForName("ewestfal"), "BAOrphanedRequestDocumentType");
316     	document.blanketApprove("");
317     	assertTrue("Document should be processed.", document.isProcessed());
318 
319     	// after the document has blanket approved there should be 2 action items since the blanket approver
320     	// is in the final workgroup.  These action items should be the acknowledges generated to both
321     	// rkirkend and user1
322     	int numActionItems = actionListService.findByDocumentId(document.getDocumentId()).size();
323     	assertEquals("Incorrect number of action items.", 2, numActionItems);
324 
325     	String user1PrincipalId = getPrincipalIdForName("user1");
326     	String rkirkendPrincipalId = getPrincipalIdForName("rkirkend");
327 
328     	// check that user1 has 1 action item
329     	Collection actionItems = actionListService.findByWorkflowUserDocumentId(user1PrincipalId, document.getDocumentId());
330     	assertEquals("user1 should have one action item.", 1, actionItems.size());
331 
332     	// check that rkirkend still has 1, the is where the bug would have manifested itself before, rkirkend would have had
333     	// no action item (hence the orphaned request)
334     	actionItems = actionListService.findByWorkflowUserDocumentId(rkirkendPrincipalId, document.getDocumentId());
335     	assertEquals("rkirkend should have one action item.", 1, actionItems.size());
336 
337     	// lets go ahead and take it to final for funsies
338     	document = WorkflowDocumentFactory.loadDocument(rkirkendPrincipalId, document.getDocumentId());
339     	assertTrue("Should have ack request.", document.isAcknowledgeRequested());
340     	document.acknowledge("");
341     	assertTrue("Should still be PROCESSED.", document.isProcessed());
342 
343     	document = WorkflowDocumentFactory.loadDocument(user1PrincipalId, document.getDocumentId());
344     	assertTrue("Should have ack request.", document.isAcknowledgeRequested());
345     	document.acknowledge("");
346     	assertTrue("Should now be FINAL.", document.isFinal());
347     }
348 
349     /**
350      * Executes a deep copy of the BaseWorkgroup
351      */
352  /*   private BaseWorkgroup copy(BaseWorkgroup workgroup) throws Exception {
353     	BaseWorkgroup workgroupCopy = (BaseWorkgroup)KEWServiceLocator.getWorkgroupService().copy(workgroup);
354     	// copy above does a shallow copy so we need to deep copy members
355     	List<BaseWorkgroupMember> members = workgroupCopy.getWorkgroupMembers();
356     	List<BaseWorkgroupMember> membersCopy = new ArrayList<BaseWorkgroupMember>();
357     	for (BaseWorkgroupMember member : members) {
358     		membersCopy.add(copy(member));
359     	}
360     	workgroupCopy.setWorkgroupMembers(membersCopy);
361     	workgroupCopy.setMembers(new ArrayList<Recipient>());
362     	workgroupCopy.materializeMembers();
363     	return workgroupCopy;
364     }
365 
366     private BaseWorkgroupMember copy(BaseWorkgroupMember member) throws Exception {
367     	return (BaseWorkgroupMember)BeanUtils.cloneBean(member);
368     }
369 */
370 
371     protected Group getGroup(String groupId) {
372 		return KimApiServiceLocator.getGroupService().getGroup(groupId);
373     }
374 }