001/**
002 * Copyright 2005-2014 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 */
016package org.kuali.rice.kew.engine.node.hierarchyrouting;
017
018import static org.junit.Assert.assertEquals;
019import static org.junit.Assert.assertNotNull;
020import static org.junit.Assert.assertNull;
021import static org.junit.Assert.assertTrue;
022
023import java.io.StringReader;
024import java.util.List;
025
026import javax.xml.parsers.DocumentBuilderFactory;
027
028import org.junit.Test;
029import org.kuali.rice.kew.api.WorkflowDocument;
030import org.kuali.rice.kew.api.WorkflowDocumentFactory;
031import org.kuali.rice.kew.api.exception.WorkflowException;
032import org.kuali.rice.kew.engine.node.hierarchyrouting.HierarchyProvider.Stop;
033import org.kuali.rice.kew.engine.node.hierarchyrouting.SimpleHierarchyProvider.SimpleStop;
034import org.kuali.rice.kew.service.KEWServiceLocator;
035import org.kuali.rice.kew.test.KEWTestCase;
036import org.kuali.rice.kew.test.TestUtilities;
037import org.w3c.dom.Document;
038import org.xml.sax.InputSource;
039
040/**
041 * Tests HeirarchyRoutingNode
042 * @author Kuali Rice Team (rice.collab@kuali.org)
043 *
044 */
045public 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}