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.engine.node.hierarchyrouting;
017    
018    import static org.junit.Assert.assertEquals;
019    import static org.junit.Assert.assertNotNull;
020    import static org.junit.Assert.assertNull;
021    import static org.junit.Assert.assertTrue;
022    
023    import java.io.StringReader;
024    import java.util.List;
025    
026    import javax.xml.parsers.DocumentBuilderFactory;
027    
028    import org.junit.Test;
029    import org.kuali.rice.kew.api.WorkflowDocument;
030    import org.kuali.rice.kew.api.WorkflowDocumentFactory;
031    import org.kuali.rice.kew.api.exception.WorkflowException;
032    import org.kuali.rice.kew.engine.node.hierarchyrouting.HierarchyProvider.Stop;
033    import org.kuali.rice.kew.engine.node.hierarchyrouting.SimpleHierarchyProvider.SimpleStop;
034    import org.kuali.rice.kew.service.KEWServiceLocator;
035    import org.kuali.rice.kew.test.KEWTestCase;
036    import org.kuali.rice.kew.test.TestUtilities;
037    import org.w3c.dom.Document;
038    import org.xml.sax.InputSource;
039    
040    /**
041     * Tests HeirarchyRoutingNode
042     * @author Kuali Rice Team (rice.collab@kuali.org)
043     *
044     */
045    public class HierarchyRoutingNodeTest extends KEWTestCase {
046    
047        private static final String HIERARCHY =
048        "<stop id=\"root\" type=\"user\" recipient=\"dewey\">" +
049          "<stop id=\"child1\" type=\"user\" recipient=\"user3\">" +
050            "<stop id=\"child1-1\" type=\"user\" recipient=\"user2\"/>" +
051            "<stop id=\"child1-2\" type=\"user\" recipient=\"user1\"/>" +
052          "</stop>" +
053          "<stop id=\"child2\" type=\"user\" recipient=\"quickstart\">" +
054            "<stop id=\"child2-1\" type=\"user\" recipient=\"temay\"/>" +
055            "<stop id=\"child2-2\" type=\"user\" recipient=\"jhopf\"/>" +
056          "</stop>" +
057        "</stop>";
058        private static final String HIERARCHY_UPDATED =
059        "<stop id=\"root\" type=\"user\" recipient=\"dewey\">" +
060          "<stop id=\"child1\" type=\"user\" recipient=\"user3\">" +
061            "<stop id=\"child1-1\" type=\"user\" recipient=\"user2\"/>" +
062            "<stop id=\"child1-2\" type=\"user\" recipient=\"user1\"/>" +
063            "<stop id=\"child1-3\" type=\"user\" recipient=\"delyea\"/>" +
064          "</stop>" +
065          "<stop id=\"child2\" type=\"user\" recipient=\"quickstart\">" +
066            "<stop id=\"child2-1\" type=\"user\" recipient=\"temay\"/>" +
067            "<stop id=\"child2-2\" type=\"user\" recipient=\"jhopf\"/>" +
068            "<stop id=\"child2-3\" type=\"user\" recipient=\"pzhang\"/>" +
069          "</stop>" +
070          "<stop id=\"child3\" type=\"user\" recipient=\"shenl\"/>" +
071        "</stop>";
072    
073        protected void assertStop(HierarchyProvider provider, String name, String parentName, String[] childNames) {
074            Stop stop = provider.getStopByIdentifier(name);
075            assertNotNull(stop);
076            if (parentName == null) {
077                assertNull(provider.getParent(stop));
078            } else {
079                Stop parent = provider.getStopByIdentifier(parentName);
080                assertNotNull(parent);
081                assertEquals(parent, ((SimpleStop) stop).parent);
082            }
083            assertEquals(childNames.length, ((SimpleStop) stop).children.size());
084            List<SimpleStop> children = ((SimpleStop) stop).children;
085            for (String childName: childNames) {
086                Stop child = provider.getStopByIdentifier(childName);
087                assertTrue(children.contains(child));
088            }
089        }
090    
091        @Test
092        public void testParseHierarchy() throws Exception {
093            Document doc = DocumentBuilderFactory.newInstance().newDocumentBuilder().parse(new InputSource(new StringReader(HIERARCHY)));
094            SimpleHierarchyProvider provider = new SimpleHierarchyProvider();
095            provider.init(doc.getDocumentElement());
096            
097            assertStop(provider, "root", null, new String[] { "child1", "child2" });
098            
099            assertStop(provider, "child1", "root", new String[] { "child1-1", "child1-2" });
100            assertStop(provider, "child1-1", "child1", new String[] { });
101            assertStop(provider, "child1-2", "child1", new String[] { });
102            
103            assertStop(provider, "child2", "root", new String[] { "child2-1", "child2-2" });
104            assertStop(provider, "child2-1", "child2", new String[] { });
105            assertStop(provider, "child2-2", "child2", new String[] { });
106            
107            List<Stop> leaves = provider.getLeafStops(null);
108            assertEquals(4, leaves.size());
109            assertTrue(leaves.contains(provider.getStopByIdentifier("child1-1")));
110            assertTrue(leaves.contains(provider.getStopByIdentifier("child1-2")));
111            assertTrue(leaves.contains(provider.getStopByIdentifier("child2-1")));
112            assertTrue(leaves.contains(provider.getStopByIdentifier("child2-2")));
113        }
114    
115        @Test
116        public void testHierarchyRoutingNode() throws WorkflowException {
117            loadXmlFile("HierarchyRoutingNodeConfig.xml");
118            
119            WorkflowDocument doc = WorkflowDocumentFactory.createDocument(getPrincipalIdForName("arh14"), "HierarchyDocType");
120            
121            
122            doc.setApplicationContent(HIERARCHY);
123            doc.route("initial route");
124            
125            TestUtilities.assertApprovals(doc.getDocumentId(), new String[] { "user2", "user1", "temay", "jhopf" }, true);
126            TestUtilities.assertApprovals(doc.getDocumentId(), new String[] { "user3", "quickstart", "dewey" }, false);
127            
128            doc = WorkflowDocumentFactory.loadDocument(getPrincipalIdForName("user2"), doc.getDocumentId());
129            doc.approve("approving as user2");
130            
131            TestUtilities.assertApprovals(doc.getDocumentId(), new String[] { "user1", "temay", "jhopf" }, true);
132            TestUtilities.assertApprovals(doc.getDocumentId(), new String[] { "user2", "user3", "quickstart", "dewey" }, false);
133            
134            doc = WorkflowDocumentFactory.loadDocument(getPrincipalIdForName("jhopf"), doc.getDocumentId());
135            doc.approve("approving as jhopf");
136            
137            TestUtilities.assertApprovals(doc.getDocumentId(), new String[] { "user1", "temay" }, true);
138            TestUtilities.assertApprovals(doc.getDocumentId(), new String[] { "jhopf", "user2", "user3", "quickstart", "dewey" }, false);
139            
140            doc = WorkflowDocumentFactory.loadDocument(getPrincipalIdForName("user1"), doc.getDocumentId());
141            doc.approve("approving as user1");
142            
143            TestUtilities.assertApprovals(doc.getDocumentId(), new String[] { "user3", "temay" }, true);
144            TestUtilities.assertApprovals(doc.getDocumentId(), new String[] { "user1", "jhopf", "user2", "quickstart", "dewey" }, false);
145            
146            doc = WorkflowDocumentFactory.loadDocument(getPrincipalIdForName("temay"), doc.getDocumentId());
147            doc.approve("approving as temay");
148            
149            TestUtilities.assertApprovals(doc.getDocumentId(), new String[] { "user3", "quickstart" }, true);
150            TestUtilities.assertApprovals(doc.getDocumentId(), new String[] { "temay", "user1", "jhopf", "user2", "dewey" }, false);
151            
152            doc = WorkflowDocumentFactory.loadDocument(getPrincipalIdForName("user3"), doc.getDocumentId());
153            doc.approve("approving as user3");
154            
155            TestUtilities.assertApprovals(doc.getDocumentId(), new String[] { "quickstart" }, true);
156            TestUtilities.assertApprovals(doc.getDocumentId(), new String[] { "user3", "temay", "user1", "jhopf", "user2", "dewey" }, false);
157            
158            doc = WorkflowDocumentFactory.loadDocument(getPrincipalIdForName("quickstart"), doc.getDocumentId());
159            doc.approve("approving as quickstart");
160            
161            TestUtilities.assertApprovals(doc.getDocumentId(), new String[] { "dewey" }, true);
162            TestUtilities.assertApprovals(doc.getDocumentId(), new String[] { "user3", "temay", "user1", "jhopf", "user2", "quickstart" }, false);
163            
164    
165            doc = WorkflowDocumentFactory.loadDocument(getPrincipalIdForName("dewey"), doc.getDocumentId());
166            doc.approve("approving as dewey");
167            
168            TestUtilities.assertApprovals(doc.getDocumentId(), new String[] { "dewey", "user3", "temay", "user1", "jhopf", "user2", "quickstart" }, false);
169            
170            assertTrue(doc.isFinal());
171        }
172        
173        @Test
174        public void testHierarchyRoutingNodeUnevenApproval() throws WorkflowException {
175            loadXmlFile("HierarchyRoutingNodeConfig.xml");
176            
177            WorkflowDocument doc = WorkflowDocumentFactory.createDocument(getPrincipalIdForName("arh14"), "HierarchyDocType");
178            
179            doc.setApplicationContent(HIERARCHY);
180            doc.route("initial route");
181            
182            TestUtilities.assertApprovals(doc.getDocumentId(), new String[] { "user2", "user1", "temay", "jhopf" }, true);
183            TestUtilities.assertApprovals(doc.getDocumentId(), new String[] { "user3", "quickstart", "dewey" }, false);
184            
185            doc = WorkflowDocumentFactory.loadDocument(getPrincipalIdForName("user2"), doc.getDocumentId());
186            doc.approve("approving as user2");
187            
188            TestUtilities.assertApprovals(doc.getDocumentId(), new String[] { "user1", "temay", "jhopf" }, true);
189            TestUtilities.assertApprovals(doc.getDocumentId(), new String[] { "user2", "user3", "quickstart", "dewey" }, false);
190            
191            doc = WorkflowDocumentFactory.loadDocument(getPrincipalIdForName("jhopf"), doc.getDocumentId());
192            doc.approve("approving as jhopf");
193            
194            TestUtilities.assertApprovals(doc.getDocumentId(), new String[] { "user1", "temay" }, true);
195            TestUtilities.assertApprovals(doc.getDocumentId(), new String[] { "jhopf", "user2", "user3", "quickstart", "dewey" }, false);
196            
197            doc = WorkflowDocumentFactory.loadDocument(getPrincipalIdForName("user1"), doc.getDocumentId());
198            doc.approve("approving as user1");
199            
200            TestUtilities.assertApprovals(doc.getDocumentId(), new String[] { "user3", "temay" }, true);
201            TestUtilities.assertApprovals(doc.getDocumentId(), new String[] { "user1", "jhopf", "user2", "quickstart", "dewey" }, false);
202            
203            doc = WorkflowDocumentFactory.loadDocument(getPrincipalIdForName("user3"), doc.getDocumentId());
204            doc.approve("approving as user3");
205            
206            TestUtilities.assertApprovals(doc.getDocumentId(), new String[] { "temay" }, true);
207            TestUtilities.assertApprovals(doc.getDocumentId(), new String[] { "user3", "user1", "jhopf", "user2", "dewey" }, false);
208            
209            doc = WorkflowDocumentFactory.loadDocument(getPrincipalIdForName("temay"), doc.getDocumentId());
210            doc.approve("approving as temay");
211            
212            TestUtilities.assertApprovals(doc.getDocumentId(), new String[] { "quickstart" }, true);
213            TestUtilities.assertApprovals(doc.getDocumentId(), new String[] { "user3", "temay", "user1", "jhopf", "user2", "dewey" }, false);
214            
215            doc = WorkflowDocumentFactory.loadDocument(getPrincipalIdForName("quickstart"), doc.getDocumentId());
216            doc.approve("approving as quickstart");
217            
218            TestUtilities.assertApprovals(doc.getDocumentId(), new String[] { "dewey" }, true);
219            TestUtilities.assertApprovals(doc.getDocumentId(), new String[] { "user3", "temay", "user1", "jhopf", "user2", "quickstart" }, false);
220    
221            doc = WorkflowDocumentFactory.loadDocument(getPrincipalIdForName("dewey"), doc.getDocumentId());
222            doc.approve("approving as dewey");
223            
224            TestUtilities.assertApprovals(doc.getDocumentId(), new String[] { "dewey", "user3", "temay", "user1", "jhopf", "user2", "quickstart" }, false);
225            
226            assertTrue(doc.isFinal());
227        }
228        
229        @Test
230        public void testHierarchyRoutingNodeUnevenApprovalExtraStops() throws WorkflowException {
231            loadXmlFile("HierarchyRoutingNodeConfig.xml");
232            
233            WorkflowDocument doc = WorkflowDocumentFactory.createDocument(getPrincipalIdForName("arh14"), "HierarchyDocType");
234            
235            doc.setApplicationContent(HIERARCHY);
236            doc.route("initial route");
237            
238            TestUtilities.assertApprovals(doc.getDocumentId(), new String[] { "user2", "user1", "temay", "jhopf" }, true);
239            TestUtilities.assertApprovals(doc.getDocumentId(), new String[] { "user3", "quickstart", "dewey" }, false);
240            
241            doc = WorkflowDocumentFactory.loadDocument(getPrincipalIdForName("user2"), doc.getDocumentId());
242            doc.approve("approving as user2");
243            
244            TestUtilities.assertApprovals(doc.getDocumentId(), new String[] { "user1", "temay", "jhopf" }, true);
245            TestUtilities.assertApprovals(doc.getDocumentId(), new String[] { "user2", "user3", "quickstart", "dewey" }, false);
246            
247            doc = WorkflowDocumentFactory.loadDocument(getPrincipalIdForName("jhopf"), doc.getDocumentId());
248            doc.approve("approving as jhopf");
249            
250            TestUtilities.assertApprovals(doc.getDocumentId(), new String[] { "user1", "temay" }, true);
251            TestUtilities.assertApprovals(doc.getDocumentId(), new String[] { "jhopf", "user2", "user3", "quickstart", "dewey" }, false);
252            
253            doc = WorkflowDocumentFactory.loadDocument(getPrincipalIdForName("user1"), doc.getDocumentId());
254            doc.setApplicationContent(HIERARCHY_UPDATED);
255            doc.approve("approving as user1");
256            
257            TestUtilities.assertApprovals(doc.getDocumentId(), new String[] { "user3", "temay", "delyea", "pzhang", "shenl" }, true);
258            TestUtilities.assertApprovals(doc.getDocumentId(), new String[] { "user1", "jhopf", "user2", "quickstart", "dewey" }, false);
259            
260            doc = WorkflowDocumentFactory.loadDocument(getPrincipalIdForName("user3"), doc.getDocumentId());
261            doc.approve("approving as user3");
262            
263            TestUtilities.assertApprovals(doc.getDocumentId(), new String[] { "temay", "delyea", "pzhang", "shenl" }, true);
264            TestUtilities.assertApprovals(doc.getDocumentId(), new String[] { "user3", "user1", "jhopf", "user2", "dewey" }, false);
265            
266            doc = WorkflowDocumentFactory.loadDocument(getPrincipalIdForName("temay"), doc.getDocumentId());
267            doc.approve("approving as temay");
268            
269            TestUtilities.assertApprovals(doc.getDocumentId(), new String[] { "delyea", "pzhang", "shenl" }, true);
270            TestUtilities.assertApprovals(doc.getDocumentId(), new String[] { "user3", "temay", "user1", "jhopf", "user2", "dewey", "quickstart" }, false);
271            
272            doc = WorkflowDocumentFactory.loadDocument(getPrincipalIdForName("delyea"), doc.getDocumentId());
273            doc.approve("approving as delyea");
274            
275            TestUtilities.assertApprovals(doc.getDocumentId(), new String[] { "user3", "pzhang", "shenl" }, true);
276            TestUtilities.assertApprovals(doc.getDocumentId(), new String[] { "delyea", "temay", "user1", "jhopf", "user2", "quickstart", "dewey" }, false);
277    
278            doc = WorkflowDocumentFactory.loadDocument(getPrincipalIdForName("user3"), doc.getDocumentId());
279            doc.approve("approving as user3");
280    
281            TestUtilities.assertApprovals(doc.getDocumentId(), new String[] { "pzhang", "shenl" }, true);
282            TestUtilities.assertApprovals(doc.getDocumentId(), new String[] { "delyea", "temay", "user1", "jhopf", "user2", "quickstart", "dewey" }, false);
283    
284            doc = WorkflowDocumentFactory.loadDocument(getPrincipalIdForName("pzhang"), doc.getDocumentId());
285            doc.approve("approving as pzhang");
286    
287            TestUtilities.assertApprovals(doc.getDocumentId(), new String[] { "quickstart", "shenl" }, true);
288            TestUtilities.assertApprovals(doc.getDocumentId(), new String[] { "pzhang", "delyea", "temay", "user1", "jhopf", "user2", "dewey" }, false);
289    
290            doc = WorkflowDocumentFactory.loadDocument(getPrincipalIdForName("quickstart"), doc.getDocumentId());
291            doc.approve("approving as quickstart");
292    
293            TestUtilities.assertApprovals(doc.getDocumentId(), new String[] { "shenl" }, true);
294            TestUtilities.assertApprovals(doc.getDocumentId(), new String[] { "pzhang", "delyea", "temay", "user1", "jhopf", "user2", "quickstart", "dewey" }, false);
295    
296            doc = WorkflowDocumentFactory.loadDocument(getPrincipalIdForName("shenl"), doc.getDocumentId());
297            doc.approve("approving as shenl");
298            
299            TestUtilities.assertApprovals(doc.getDocumentId(), new String[] { "dewey" }, true);
300            TestUtilities.assertApprovals(doc.getDocumentId(), new String[] { "pzhang", "delyea", "temay", "user1", "jhopf", "user2", "quickstart", "shenl" }, false);
301    
302            doc = WorkflowDocumentFactory.loadDocument(getPrincipalIdForName("dewey"), doc.getDocumentId());
303            doc.approve("approving as dewey");
304            
305            TestUtilities.assertApprovals(doc.getDocumentId(), new String[] { "shenl", "dewey", "pzhang", "delyea", "user3", "temay", "user1", "jhopf", "user2", "quickstart" }, false);
306            
307            assertTrue(doc.isFinal());
308        }
309    
310        @Test
311        public void testHierarchyRoutingNodeUnevenApprovalDisapprove() throws WorkflowException {
312            loadXmlFile("HierarchyRoutingNodeConfig.xml");
313            
314            WorkflowDocument doc = WorkflowDocumentFactory.createDocument(getPrincipalIdForName("arh14"), "HierarchyDocType");
315            
316            doc.setApplicationContent(HIERARCHY);
317            doc.route("initial route");
318            
319            TestUtilities.assertApprovals(doc.getDocumentId(), new String[] { "user2", "user1", "temay", "jhopf" }, true);
320            TestUtilities.assertApprovals(doc.getDocumentId(), new String[] { "user3", "quickstart", "dewey" }, false);
321            
322            doc = WorkflowDocumentFactory.loadDocument(getPrincipalIdForName("user2"), doc.getDocumentId());
323            doc.approve("approving as user2");
324            
325            TestUtilities.assertApprovals(doc.getDocumentId(), new String[] { "user1", "temay", "jhopf" }, true);
326            TestUtilities.assertApprovals(doc.getDocumentId(), new String[] { "user2", "user3", "quickstart", "dewey" }, false);
327            
328            doc = WorkflowDocumentFactory.loadDocument(getPrincipalIdForName("jhopf"), doc.getDocumentId());
329            doc.approve("approving as jhopf");
330            
331            TestUtilities.assertApprovals(doc.getDocumentId(), new String[] { "user1", "temay" }, true);
332            TestUtilities.assertApprovals(doc.getDocumentId(), new String[] { "jhopf", "user2", "user3", "quickstart", "dewey" }, false);
333            
334            doc = WorkflowDocumentFactory.loadDocument(getPrincipalIdForName("user1"), doc.getDocumentId());
335            doc.approve("approving as user1");
336            
337            TestUtilities.assertApprovals(doc.getDocumentId(), new String[] { "user3", "temay" }, true);
338            TestUtilities.assertApprovals(doc.getDocumentId(), new String[] { "user1", "jhopf", "user2", "quickstart", "dewey" }, false);
339            
340            doc = WorkflowDocumentFactory.loadDocument(getPrincipalIdForName("user3"), doc.getDocumentId());
341            doc.disapprove("disapproving as user3");
342            
343            doc = WorkflowDocumentFactory.loadDocument(getPrincipalIdForName("arh14"), doc.getDocumentId());
344    
345            //TestUtilities.assertApprovals(doc.getDocumentId(), new String[] { "user3", "temay", "user1", "jhopf", "user2", "quickstart", "dewey" }, false);
346    
347            assertTrue(doc.isDisapproved());
348     
349            TestUtilities.logActionRequests(doc.getDocumentId());
350    
351            // these are ok, these are the ACKs for the previous approvers
352            int numActionRequests = KEWServiceLocator.getActionRequestService().findPendingByDoc(doc.getDocumentId()).size();
353            assertEquals("Incorrect number of action requests", 4, numActionRequests);
354            int numActionItems = KEWServiceLocator.getActionListService().findByDocumentId(doc.getDocumentId()).size();
355            assertEquals("Incorrect number of action items.", 4, numActionItems);
356            
357            doc = WorkflowDocumentFactory.loadDocument(getPrincipalIdForName("user2"), doc.getDocumentId());
358            doc.acknowledge("acknowledging disapproval as user2");
359            doc = WorkflowDocumentFactory.loadDocument(getPrincipalIdForName("jhopf"), doc.getDocumentId());
360            doc.acknowledge("acknowledging disapproval as jhopf");
361            doc = WorkflowDocumentFactory.loadDocument(getPrincipalIdForName("user1"), doc.getDocumentId());
362            doc.acknowledge("acknowledging disapproval as user1");
363            doc = WorkflowDocumentFactory.loadDocument(getPrincipalIdForName("arh14"), doc.getDocumentId());
364            doc.acknowledge("acknowledging disapproval as arh14");
365            
366            assertTrue(doc.isDisapproved());
367    
368            numActionRequests = KEWServiceLocator.getActionRequestService().findPendingByDoc(doc.getDocumentId()).size();
369            assertEquals("Incorrect number of action requests", 0, numActionRequests);
370            numActionItems = KEWServiceLocator.getActionListService().findByDocumentId(doc.getDocumentId()).size();
371            assertEquals("Incorrect number of action items.", 0, numActionItems);
372            
373        }
374    }