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