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;
017
018
019import static org.junit.Assert.assertEquals;
020import static org.junit.Assert.assertNotNull;
021import static org.junit.Assert.assertNull;
022import static org.junit.Assert.assertTrue;
023
024import java.util.List;
025
026import org.junit.Test;
027import org.kuali.rice.kew.api.WorkflowDocument;
028import org.kuali.rice.kew.api.WorkflowDocumentFactory;
029import org.kuali.rice.kew.engine.node.DynamicNode;
030import org.kuali.rice.kew.engine.node.DynamicResult;
031import org.kuali.rice.kew.engine.node.NodeState;
032import org.kuali.rice.kew.engine.node.RouteNode;
033import org.kuali.rice.kew.engine.node.RouteNodeInstance;
034import org.kuali.rice.kew.routeheader.DocumentRouteHeaderValue;
035import org.kuali.rice.kew.service.KEWServiceLocator;
036import org.kuali.rice.kew.test.KEWTestCase;
037
038
039public class DynamicRoutingTest extends KEWTestCase {
040
041    private static final String SEQ_DOC_TYPE_NAME = "DynSeqDocType";
042    private static final String INIT = "Initial";
043    private static final String FIRST = "First";
044    private static final String DYNAMIC_SEQ = "DynSeq";
045    private static final String SUB_REQUESTS = "SubRequests";
046    private static final String LAST = "Last";
047
048    @Override
049    protected void loadTestData() throws Exception {
050        loadXmlFile("EngineConfig.xml");
051    }
052
053    @Test public void testDynamicParallelRoute() throws Exception {
054        WorkflowDocument document = WorkflowDocumentFactory.createDocument(getPrincipalIdForName("ewestfal"), SEQ_DOC_TYPE_NAME);
055        document.saveDocumentData();
056        assertTrue("Document should be initiated", document.isInitiated());
057        assertEquals("Should be no action requests.", 0, document.getRootActionRequests().size());
058        List<RouteNodeInstance> nodeInstances = KEWServiceLocator.getRouteNodeService().getActiveNodeInstances(document.getDocumentId());
059        assertEquals("Wrong number of active nodes.", 1, nodeInstances.size());
060        assertEquals("Wrong active node.", INIT, nodeInstances.iterator().next().getRouteNode().getRouteNodeName());
061        document.route("");
062
063        document = WorkflowDocumentFactory.loadDocument(getPrincipalIdForName("bmcgough"), document.getDocumentId());
064        assertTrue("Approve should be requested.", document.isApprovalRequested());
065        document.approve("");
066
067        nodeInstances = KEWServiceLocator.getRouteNodeService().getActiveNodeInstances(document.getDocumentId());
068        assertEquals("Wrong number of active nodes.", 1, nodeInstances.size());
069        document = WorkflowDocumentFactory.loadDocument(getPrincipalIdForName("pmckown"), document.getDocumentId());
070        assertTrue("Approve should be requested.", document.isApprovalRequested());
071        document.approve("");
072
073        document = WorkflowDocumentFactory.loadDocument(getPrincipalIdForName("temay"), document.getDocumentId());
074        assertTrue("Approve should be requested.", document.isApprovalRequested());
075        document.approve("");
076
077        document = WorkflowDocumentFactory.loadDocument(getPrincipalIdForName("jhopf"), document.getDocumentId());
078        assertTrue("Approve should be requested.", document.isApprovalRequested());
079        document.approve("");
080
081        document = WorkflowDocumentFactory.loadDocument(getPrincipalIdForName("rkirkend"), document.getDocumentId());
082        assertTrue("Approve should be requested.", document.isApprovalRequested());
083        document.approve("");
084
085        //        document = WorkflowDocumentFactory.loadDocument(new NetworkIdVO("ewestfal"), document.getDocumentId());
086        //        assertTrue("Document should be final.", document.isFinal());
087
088        verifyRoutingPath(document.getDocumentId());
089    }
090
091    private void verifyRoutingPath(String documentId) {
092        DocumentRouteHeaderValue document = KEWServiceLocator.getRouteHeaderService().getRouteHeader(documentId);
093        List<RouteNodeInstance> initial = document.getInitialRouteNodeInstances();
094        assertEquals(1, initial.size());
095        RouteNodeInstance init = initial.get(0);
096        assertEquals(INIT, init.getRouteNode().getRouteNodeName());
097        assertEquals(0, init.getPreviousNodeInstances().size());
098
099        List<RouteNodeInstance> next = init.getNextNodeInstances();
100        assertEquals(1, next.size());
101        RouteNodeInstance first = next.get(0);
102        assertEquals(FIRST, first.getRouteNode().getRouteNodeName());
103        assertEquals(1, first.getPreviousNodeInstances().size());
104
105        next = first.getNextNodeInstances();
106        assertEquals(1, next.size());
107        RouteNodeInstance pmckownNode = next.get(0);
108        assertEquals(SUB_REQUESTS, pmckownNode.getRouteNode().getRouteNodeName());
109        assertEquals(1, pmckownNode.getPreviousNodeInstances().size());
110        assertInSubProcess(pmckownNode);
111
112        next = pmckownNode.getNextNodeInstances();
113        assertEquals(1, next.size());
114        RouteNodeInstance temayNode = next.get(0);
115        assertEquals(SUB_REQUESTS, temayNode.getRouteNode().getRouteNodeName());
116        assertEquals(1, temayNode.getPreviousNodeInstances().size());
117        assertInSubProcess(temayNode);
118
119        next = temayNode.getNextNodeInstances();
120        assertEquals(1, next.size());
121        RouteNodeInstance jhopfNode = next.get(0);
122        assertEquals(SUB_REQUESTS, jhopfNode.getRouteNode().getRouteNodeName());
123        assertEquals(1, jhopfNode.getPreviousNodeInstances().size());
124        assertInSubProcess(jhopfNode);
125
126        next = jhopfNode.getNextNodeInstances();
127        assertEquals(1, next.size());
128        RouteNodeInstance last = next.get(0);
129        assertNull(last.getProcess());
130        assertEquals(LAST, last.getRouteNode().getRouteNodeName());
131        assertEquals(1, last.getPreviousNodeInstances().size());
132        assertEquals(0, last.getNextNodeInstances().size());
133    }
134
135    private void assertInSubProcess(RouteNodeInstance nodeInstance) {
136        RouteNodeInstance subProcess = nodeInstance.getProcess();
137        assertNotNull(subProcess);
138        assertEquals(DYNAMIC_SEQ, subProcess.getRouteNode().getRouteNodeName());
139    }
140
141    public static class MockSequentialDynamicNode implements DynamicNode {
142
143        @Override
144        public DynamicResult transitioningInto(RouteContext context, RouteNodeInstance process, RouteHelper helper) throws Exception {
145            RouteNodeInstance routeNodeInstance = context.getNodeInstance();
146            RouteNode dynamicRequestNode = helper.getNodeFactory().getRouteNode(context, SUB_REQUESTS);
147            RouteNodeInstance dynamicRequestNodeInstance1 = helper.getNodeFactory().createRouteNodeInstance(context.getDocument().getDocumentId(), dynamicRequestNode);
148            dynamicRequestNodeInstance1.addNodeState(new NodeState("role", "pmckown"));
149            RouteNodeInstance dynamicRequestNodeInstance2 = helper.getNodeFactory().createRouteNodeInstance(context.getDocument().getDocumentId(), dynamicRequestNode);
150            dynamicRequestNodeInstance2.addNodeState(new NodeState("role", "temay"));
151            RouteNodeInstance dynamicRequestNodeInstance3 = helper.getNodeFactory().createRouteNodeInstance(context.getDocument().getDocumentId(), dynamicRequestNode);
152            dynamicRequestNodeInstance3.addNodeState(new NodeState("role", "jhopf"));
153            dynamicRequestNodeInstance1.addNextNodeInstance(dynamicRequestNodeInstance2);
154            dynamicRequestNodeInstance2.addNextNodeInstance(dynamicRequestNodeInstance3);
155            routeNodeInstance.addNodeState(new NodeState("beenHere", "val"));
156            return new DynamicResult(true, dynamicRequestNodeInstance1);
157        }
158
159        @Override
160        public DynamicResult transitioningOutOf(RouteContext context, RouteHelper helper) throws Exception {
161            return new DynamicResult(true, null);
162        }
163    }
164}