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.actionitem;
017    
018    import org.junit.Test;
019    import org.kuali.rice.kew.actionlist.service.ActionListService;
020    import org.kuali.rice.kew.api.WorkflowDocument;
021    import org.kuali.rice.kew.api.WorkflowDocumentFactory;
022    import org.kuali.rice.kew.api.action.ActionRequest;
023    import org.kuali.rice.kew.api.action.ActionRequestType;
024    import org.kuali.rice.kew.service.KEWServiceLocator;
025    import org.kuali.rice.kew.test.KEWTestCase;
026    import org.kuali.rice.kim.api.KimConstants;
027    import org.kuali.rice.kim.api.group.Group;
028    import org.kuali.rice.kim.api.group.GroupMember;
029    import org.kuali.rice.kim.api.group.GroupService;
030    import org.kuali.rice.kim.api.identity.principal.Principal;
031    import org.kuali.rice.kim.api.services.KimApiServiceLocator;
032    import org.kuali.rice.test.BaselineTestCase;
033    
034    import java.util.ArrayList;
035    import java.util.Collection;
036    import java.util.Iterator;
037    import java.util.List;
038    
039    import static org.junit.Assert.*;
040    @BaselineTestCase.BaselineMode(BaselineTestCase.Mode.NONE)
041    public class ActionItemServiceTest extends KEWTestCase {
042    
043            private ActionListService actionListService;
044    
045        protected void loadTestData() throws Exception {
046            loadXmlFile("ActionItemConfig.xml");
047        }
048    
049        protected void setUpAfterDataLoad() throws Exception {
050                    super.setUpAfterDataLoad();
051                    actionListService = KEWServiceLocator.getActionListService();
052            }
053    
054            /**
055         * When workgroup membership changes all action items to that workgroup need to reflect
056         * the new membership
057         *
058         * @throws Exception
059         */
060        @Test public void testUpdateActionItemsForWorkgroupChange() throws Exception {
061    
062            WorkflowDocument document = WorkflowDocumentFactory.createDocument(getPrincipalIdForName("user1"), "ActionItemDocumentType");
063            document.setTitle("");
064            document.route("");
065    
066            Group oldWorkgroup = KimApiServiceLocator.getGroupService().getGroupByNamespaceCodeAndName("KR-WKFLW",
067                    "AIWG-Admin");
068            //Group oldWorkgroup = this.getGroupImpl(oldGroup.getId());
069    
070    
071            GroupService groupService = KimApiServiceLocator.getGroupService();
072            assertEquals("Workgroup should have 6 members.", 6, groupService.getMembersOfGroup(oldWorkgroup.getId()).size());
073    
074            Principal user1 = KimApiServiceLocator.getIdentityService().getPrincipalByPrincipalName("user1");
075            Principal user2 = KimApiServiceLocator.getIdentityService().getPrincipalByPrincipalName("user2");
076    
077            Principal rkirkend = KimApiServiceLocator.getIdentityService().getPrincipalByPrincipalName("rkirkend");
078            Principal shenl = KimApiServiceLocator.getIdentityService().getPrincipalByPrincipalName("shenl");
079    
080            List<GroupMember> usersToRemove = new ArrayList<GroupMember>();
081            //remove 'rkirkend' and 'shenl' from the workgroup
082            Collection<GroupMember> members = groupService.getMembersOfGroup(oldWorkgroup.getId());
083            for (GroupMember recipient : members) {
084                            if (recipient.getMemberId().equals(rkirkend.getPrincipalId()) || recipient.getMemberId().equals(shenl.getPrincipalId())) {
085                                    KimApiServiceLocator.getGroupService().removePrincipalFromGroup(recipient.getMemberId(), oldWorkgroup.getId());
086                            }
087    
088            }
089    
090            //add user1 and user2
091            KimApiServiceLocator.getGroupService().addPrincipalToGroup(user1.getPrincipalId(), oldWorkgroup.getId());
092            KimApiServiceLocator.getGroupService().addPrincipalToGroup(user2.getPrincipalId(), oldWorkgroup.getId());
093    
094    
095            // verify that the new workgroup is sane...
096            Group loadedNewWorkgroup = this.getGroup(oldWorkgroup.getId());
097    
098            boolean foundUser1 = false;
099            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    }