/*
* Copyright (C) 2006-2016 DLR, Germany
*
* All rights reserved
*
* http://www.rcenvironment.de/
*/
package de.rcenvironment.core.component.execution.api;
import static org.junit.Assert.assertEquals;
import java.util.Deque;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Iterator;
import java.util.LinkedList;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.UUID;
import org.apache.commons.lang3.RandomStringUtils;
import org.junit.Test;
import de.rcenvironment.core.datamodel.api.EndpointCharacter;
import de.rcenvironment.core.utils.common.StringUtils;
import junit.framework.Assert;
/**
* Tests for {link WorkflowGraph}.
*
* @author Sascha Zur
* @author Doreen Seider
*/
public class WorkflowGraphTest {
private static final String ZERO = "0";
private static final String INPUT_PREFIX = "inp_";
private static final String INPUT0 = "inp_0";
private static final String INPUT1 = "inp_1";
private static final String OUTPUT_PREFIX = "out_";
private static final String OUTPUT0 = "out_0";
private static final String OUTPUT1 = "out_1";
private static final String NODE = "node";
private static final String SINK_NODE = "sinkNode";
private static final String NODE3 = "node3";
private static final String NODE2 = "node2";
private static final String NODE1 = "node1";
private static final String SINK_NODE0 = "sinkNode0";
private static final String NODE0 = "node0";
private static final String SINK_NODE1 = "sinkNode1";
private static final String OUTER_LOOP_NODE = "outerLoopNode";
private Map<String, WorkflowGraphNode> nodeNamesToNodes;
/** Test. */
@Test
public void testWorkflowGraphFailure() {
WorkflowGraph graph = null;
graph = createCircleWorkflowGraph();
WorkflowGraphNode driver;
try {
driver = graph.getLoopDriver(nodeNamesToNodes.get(NODE0).getExecutionIdentifier());
Assert.assertEquals(nodeNamesToNodes.get(SINK_NODE0).getExecutionIdentifier(), driver.getExecutionIdentifier());
driver = graph.getLoopDriver(nodeNamesToNodes.get(NODE1).getExecutionIdentifier());
Assert.assertEquals(nodeNamesToNodes.get(SINK_NODE0).getExecutionIdentifier(), driver.getExecutionIdentifier());
driver = graph.getLoopDriver(nodeNamesToNodes.get(NODE2).getExecutionIdentifier());
Assert.assertEquals(nodeNamesToNodes.get(SINK_NODE0).getExecutionIdentifier(), driver.getExecutionIdentifier());
graph = createCircleWorkflowGraphWithInnerLoopBack();
driver = graph.getLoopDriver(nodeNamesToNodes.get(NODE0).getExecutionIdentifier());
Assert.assertEquals(nodeNamesToNodes.get(SINK_NODE0).getExecutionIdentifier(), driver.getExecutionIdentifier());
driver = graph.getLoopDriver(nodeNamesToNodes.get(NODE1).getExecutionIdentifier());
Assert.assertEquals(nodeNamesToNodes.get(SINK_NODE0).getExecutionIdentifier(), driver.getExecutionIdentifier());
driver = graph.getLoopDriver(nodeNamesToNodes.get(NODE2).getExecutionIdentifier());
Assert.assertEquals(nodeNamesToNodes.get(SINK_NODE0).getExecutionIdentifier(), driver.getExecutionIdentifier());
graph = createTwoSinksWorkflowGraph();
driver = graph.getLoopDriver(nodeNamesToNodes.get(NODE0).getExecutionIdentifier());
Assert.assertEquals(nodeNamesToNodes.get(OUTER_LOOP_NODE).getExecutionIdentifier(), driver.getExecutionIdentifier());
graph = createTwoSinksWithInnerLoopWorkflowGraph();
driver = graph.getLoopDriver(nodeNamesToNodes.get(NODE3).getExecutionIdentifier());
Assert.assertEquals(nodeNamesToNodes.get(OUTER_LOOP_NODE).getExecutionIdentifier(), driver.getExecutionIdentifier());
driver = graph.getLoopDriver(nodeNamesToNodes.get(NODE0).getExecutionIdentifier());
Assert.assertEquals(nodeNamesToNodes.get(OUTER_LOOP_NODE).getExecutionIdentifier(), driver.getExecutionIdentifier());
driver = graph.getLoopDriver(nodeNamesToNodes.get(NODE1).getExecutionIdentifier());
Assert.assertEquals(nodeNamesToNodes.get(SINK_NODE0).getExecutionIdentifier(), driver.getExecutionIdentifier());
driver = graph.getLoopDriver(nodeNamesToNodes.get(NODE2).getExecutionIdentifier());
Assert.assertEquals(nodeNamesToNodes.get(SINK_NODE1).getExecutionIdentifier(), driver.getExecutionIdentifier());
graph = createReducedInputsWorkflowGraph();
driver = graph.getLoopDriver(nodeNamesToNodes.get(NODE0).getExecutionIdentifier());
Assert.assertEquals(nodeNamesToNodes.get(OUTER_LOOP_NODE).getExecutionIdentifier(), driver.getExecutionIdentifier());
Map<String, Set<Deque<WorkflowGraphHop>>> hops =
graph.getHopsToTraverseOnFailure(nodeNamesToNodes.get(NODE0).getExecutionIdentifier());
Assert.assertEquals(1, hops.keySet().size());
Assert.assertEquals(1, hops.get(hops.keySet().iterator().next()).size());
} catch (ComponentExecutionException e) {
Assert.fail("Unexpected exception: " + e.getMessage());
}
}
/** Test. */
@Test
public void testWorkflowGraphReset() {
WorkflowGraph graph = null;
Map<String, Set<Deque<WorkflowGraphHop>>> hops = null;
Map<String, List<Integer>> hopsCount = new HashMap<>();
List<Integer> counts = new LinkedList<>();
try {
graph = createCircleWorkflowGraph();
hops = graph.getHopsToTraverseWhenResetting(nodeNamesToNodes.get(SINK_NODE0).getExecutionIdentifier());
hopsCount = new HashMap<>();
counts = new LinkedList<>();
counts.add(new Integer(4));
hopsCount.put(OUTPUT_PREFIX + ZERO, counts);
Deque<String> expectedHops = new LinkedList<>();
expectedHops.add(StringUtils.escapeAndConcat(OUTPUT0, nodeNamesToNodes.get(SINK_NODE0).getExecutionIdentifier(),
INPUT0, nodeNamesToNodes.get(NODE0).getExecutionIdentifier()));
expectedHops.add(StringUtils.escapeAndConcat(OUTPUT0, nodeNamesToNodes.get(NODE0).getExecutionIdentifier(),
INPUT0, nodeNamesToNodes.get(NODE1).getExecutionIdentifier()));
expectedHops.add(StringUtils.escapeAndConcat(OUTPUT0, nodeNamesToNodes.get(NODE1).getExecutionIdentifier(),
INPUT0, nodeNamesToNodes.get(NODE2).getExecutionIdentifier()));
expectedHops.add(StringUtils.escapeAndConcat(OUTPUT0, nodeNamesToNodes.get(NODE2).getExecutionIdentifier(),
INPUT0, nodeNamesToNodes.get(SINK_NODE0).getExecutionIdentifier()));
assertWorkflowGraphHops(expectedHops, hops.get(OUTPUT0).iterator().next());
checkResultCorrect(hops, 1, new int[] { 1 }, hopsCount);
graph = createCircleWorkflowGraphWithInnerLoopBack();
hops = graph.getHopsToTraverseWhenResetting(nodeNamesToNodes.get(SINK_NODE0).getExecutionIdentifier());
hopsCount = new HashMap<>();
counts = new LinkedList<>();
counts.add(new Integer(4));
hopsCount.put(OUTPUT_PREFIX + ZERO, counts);
expectedHops = new LinkedList<>();
expectedHops.add(StringUtils.escapeAndConcat(OUTPUT0, nodeNamesToNodes.get(SINK_NODE0).getExecutionIdentifier(),
INPUT0, nodeNamesToNodes.get(NODE0).getExecutionIdentifier()));
expectedHops.add(StringUtils.escapeAndConcat(OUTPUT0, nodeNamesToNodes.get(NODE0).getExecutionIdentifier(),
INPUT0, nodeNamesToNodes.get(NODE1).getExecutionIdentifier()));
expectedHops.add(StringUtils.escapeAndConcat(OUTPUT0, nodeNamesToNodes.get(NODE1).getExecutionIdentifier(),
INPUT0, nodeNamesToNodes.get(NODE2).getExecutionIdentifier()));
expectedHops.add(StringUtils.escapeAndConcat(OUTPUT0, nodeNamesToNodes.get(NODE2).getExecutionIdentifier(),
INPUT0, nodeNamesToNodes.get(SINK_NODE0).getExecutionIdentifier()));
assertWorkflowGraphHops(expectedHops, hops.get(OUTPUT0).iterator().next());
checkResultCorrect(hops, 1, new int[] { 1 }, hopsCount);
graph = createTwoSinksWorkflowGraph();
hops =
graph.getHopsToTraverseWhenResetting(nodeNamesToNodes.get(SINK_NODE0).getExecutionIdentifier());
hopsCount = new HashMap<>();
counts = new LinkedList<>();
hopsCount.put(OUTPUT_PREFIX + ZERO, counts);
// no hops so no assertion
checkResultCorrect(hops, 1, new int[] { 0 }, hopsCount);
graph = createTwoSinksWithInnerLoopWorkflowGraph();
hops =
graph.getHopsToTraverseWhenResetting(nodeNamesToNodes.get(SINK_NODE0).getExecutionIdentifier());
hopsCount = new HashMap<>();
counts = new LinkedList<>();
counts.add(new Integer(2));
hopsCount.put(OUTPUT_PREFIX + ZERO, counts);
hopsCount.put(OUTPUT_PREFIX + "1", new LinkedList<Integer>());
checkResultCorrect(hops, 2, new int[] { 1, 0 }, hopsCount);
} catch (ComponentExecutionException e) {
Assert.fail("Unexpected exception: " + e.getMessage());
}
}
/**
*
* @return A graph were two sinks are in a row with no nested loop, so no resetting Deque should be produced.
*/
private WorkflowGraph createTwoSinksWorkflowGraph() {
nodeNamesToNodes = new HashMap<>();
Map<String, WorkflowGraphNode> nodes = new HashMap<>();
WorkflowGraphNode outerLoopNode = createNewNode(1, 1, true);
nodeNamesToNodes.put(OUTER_LOOP_NODE, outerLoopNode);
nodes.put(outerLoopNode.getExecutionIdentifier(), outerLoopNode);
for (int i = 0; i < 2; i++) {
WorkflowGraphNode node = createNewNode(1, 1, true);
nodeNamesToNodes.put(SINK_NODE + i, node);
nodes.put(node.getExecutionIdentifier(), node);
}
for (int i = 0; i < 1; i++) {
WorkflowGraphNode node = createNewNode(1, 1, false);
nodeNamesToNodes.put(NODE + i, node);
nodes.put(node.getExecutionIdentifier(), node);
}
Map<String, Set<WorkflowGraphEdge>> edges = new HashMap<>();
Set<WorkflowGraphEdge> edgesSet = new HashSet<>();
edgesSet.add(createEdge(nodeNamesToNodes.get(OUTER_LOOP_NODE), 0, EndpointCharacter.SAME_LOOP,
nodeNamesToNodes.get(SINK_NODE0), 0, EndpointCharacter.SAME_LOOP));
edgesSet.add(createEdge(nodeNamesToNodes.get(SINK_NODE0), 0, EndpointCharacter.OUTER_LOOP,
nodeNamesToNodes.get(SINK_NODE1), 0, EndpointCharacter.OUTER_LOOP));
edgesSet.add(createEdge(nodeNamesToNodes.get(SINK_NODE1), 0, EndpointCharacter.OUTER_LOOP,
nodeNamesToNodes.get(NODE0), 0, EndpointCharacter.SAME_LOOP));
edgesSet.add(createEdge(nodeNamesToNodes.get(NODE0), 0, EndpointCharacter.SAME_LOOP,
nodeNamesToNodes.get(OUTER_LOOP_NODE), 0, EndpointCharacter.SAME_LOOP));
generateAndPutEdgeKeys(edges, edgesSet);
return new WorkflowGraph(nodes, edges);
}
/**
*
* @return A graph were two sinks are in a row with no nested loop, so no resetting Deque should be produced.
*/
private WorkflowGraph createReducedInputsWorkflowGraph() {
nodeNamesToNodes = new HashMap<>();
Map<String, WorkflowGraphNode> nodes = new HashMap<>();
WorkflowGraphNode driverNode = createNewNode(1, 1, true);
nodeNamesToNodes.put(OUTER_LOOP_NODE, driverNode);
nodes.put(driverNode.getExecutionIdentifier(), driverNode);
WorkflowGraphNode node0 = createNewNode(1, 2, false);
nodeNamesToNodes.put(NODE + 0, node0);
nodes.put(node0.getExecutionIdentifier(), node0);
WorkflowGraphNode node1 = createNewNode(2, 1, false);
nodeNamesToNodes.put(NODE + 1, node1);
nodes.put(node1.getExecutionIdentifier(), node1);
Map<String, Set<WorkflowGraphEdge>> edges = new HashMap<>();
Set<WorkflowGraphEdge> edgesSet = new HashSet<>();
edgesSet.add(createEdge(nodeNamesToNodes.get(OUTER_LOOP_NODE), 0, EndpointCharacter.SAME_LOOP,
nodeNamesToNodes.get(NODE0), 0, EndpointCharacter.SAME_LOOP));
edgesSet.add(createEdge(nodeNamesToNodes.get(NODE0), 0, EndpointCharacter.OUTER_LOOP,
nodeNamesToNodes.get(NODE1), 0, EndpointCharacter.OUTER_LOOP));
edgesSet.add(createEdge(nodeNamesToNodes.get(NODE0), 1, EndpointCharacter.OUTER_LOOP,
nodeNamesToNodes.get(NODE1), 1, EndpointCharacter.SAME_LOOP));
edgesSet.add(createEdge(nodeNamesToNodes.get(NODE1), 0, EndpointCharacter.SAME_LOOP,
nodeNamesToNodes.get(OUTER_LOOP_NODE), 0, EndpointCharacter.SAME_LOOP));
generateAndPutEdgeKeys(edges, edgesSet);
return new WorkflowGraph(nodes, edges);
}
/**
*
* @return A graph where two sinks are in a row and both have a nested loop. The reset should contain 2 hops.
*/
private WorkflowGraph createTwoSinksWithInnerLoopWorkflowGraph() {
nodeNamesToNodes = new HashMap<>();
Map<String, WorkflowGraphNode> nodes = new HashMap<>();
WorkflowGraphNode outerLoopNode = createNewNode(1, 2, true);
nodeNamesToNodes.put(OUTER_LOOP_NODE, outerLoopNode);
nodes.put(outerLoopNode.getExecutionIdentifier(), outerLoopNode);
for (int i = 0; i < 2; i++) {
WorkflowGraphNode node = createNewNode(3, 2, true);
nodeNamesToNodes.put(SINK_NODE + i, node);
nodes.put(node.getExecutionIdentifier(), node);
}
for (int i = 0; i < 4; i++) {
WorkflowGraphNode node = createNewNode(1, 1, false);
nodeNamesToNodes.put(NODE + i, node);
nodes.put(node.getExecutionIdentifier(), node);
}
Map<String, Set<WorkflowGraphEdge>> edges = new HashMap<>();
Set<WorkflowGraphEdge> edgesSet = new HashSet<>();
edgesSet.add(createEdge(nodeNamesToNodes.get(OUTER_LOOP_NODE), 0, EndpointCharacter.SAME_LOOP,
nodeNamesToNodes.get(NODE0), 0, EndpointCharacter.SAME_LOOP));
edgesSet.add(createEdge(nodeNamesToNodes.get(NODE0), 0, EndpointCharacter.SAME_LOOP,
nodeNamesToNodes.get(SINK_NODE0), 0, EndpointCharacter.OUTER_LOOP));
edgesSet.add(createEdge(nodeNamesToNodes.get(SINK_NODE0), 0, EndpointCharacter.SAME_LOOP,
nodeNamesToNodes.get(NODE1), 0, EndpointCharacter.SAME_LOOP));
edgesSet.add(createEdge(nodeNamesToNodes.get(NODE1), 0, EndpointCharacter.SAME_LOOP,
nodeNamesToNodes.get(SINK_NODE0), 1, EndpointCharacter.SAME_LOOP));
edgesSet.add(createEdge(nodeNamesToNodes.get(SINK_NODE0), 1, EndpointCharacter.OUTER_LOOP,
nodeNamesToNodes.get(SINK_NODE1), 0, EndpointCharacter.OUTER_LOOP));
edgesSet.add(createEdge(nodeNamesToNodes.get(SINK_NODE1), 0, EndpointCharacter.SAME_LOOP,
nodeNamesToNodes.get(NODE2), 0, EndpointCharacter.SAME_LOOP));
edgesSet.add(createEdge(nodeNamesToNodes.get(NODE2), 0, EndpointCharacter.SAME_LOOP,
nodeNamesToNodes.get(SINK_NODE1), 1, EndpointCharacter.SAME_LOOP));
edgesSet.add(createEdge(nodeNamesToNodes.get(SINK_NODE1), 1, EndpointCharacter.OUTER_LOOP,
nodeNamesToNodes.get(NODE3), 0, EndpointCharacter.SAME_LOOP));
edgesSet.add(createEdge(nodeNamesToNodes.get(NODE3), 0, EndpointCharacter.SAME_LOOP,
nodeNamesToNodes.get(OUTER_LOOP_NODE), 0, EndpointCharacter.SAME_LOOP));
generateAndPutEdgeKeys(edges, edgesSet);
return new WorkflowGraph(nodes, edges);
}
/**
*
* @return A circle of nodes connected to a sink, so the circle should be reset.
*/
private WorkflowGraph createCircleWorkflowGraph() {
nodeNamesToNodes = new HashMap<>();
Map<String, WorkflowGraphNode> nodes = new HashMap<>();
for (int i = 0; i < 1; i++) {
WorkflowGraphNode node = createNewNode(1, 1, true);
nodeNamesToNodes.put(SINK_NODE + i, node);
nodes.put(node.getExecutionIdentifier(), node);
}
for (int i = 0; i < 3; i++) {
WorkflowGraphNode node = createNewNode(1, 1, false);
nodeNamesToNodes.put(NODE + i, node);
nodes.put(node.getExecutionIdentifier(), node);
}
Map<String, Set<WorkflowGraphEdge>> edges = new HashMap<>();
WorkflowGraphEdge e1 =
createEdge(nodeNamesToNodes.get(SINK_NODE0), 0, EndpointCharacter.SAME_LOOP,
nodeNamesToNodes.get(NODE0), 0, EndpointCharacter.SAME_LOOP);
WorkflowGraphEdge e2 = createEdge(nodeNamesToNodes.get(NODE0), 0, EndpointCharacter.SAME_LOOP,
nodeNamesToNodes.get(NODE1), 0, EndpointCharacter.SAME_LOOP);
WorkflowGraphEdge e3 = createEdge(nodeNamesToNodes.get(NODE1), 0, EndpointCharacter.SAME_LOOP,
nodeNamesToNodes.get(NODE2), 0, EndpointCharacter.SAME_LOOP);
WorkflowGraphEdge e4 = createEdge(nodeNamesToNodes.get(NODE2), 0, EndpointCharacter.SAME_LOOP,
nodeNamesToNodes.get(SINK_NODE0), 0, EndpointCharacter.SAME_LOOP);
String key1 = WorkflowGraph.createEdgeKey(e1);
String key2 = WorkflowGraph.createEdgeKey(e2);
String key3 = WorkflowGraph.createEdgeKey(e3);
String key4 = WorkflowGraph.createEdgeKey(e4);
edges.put(key1, new HashSet<WorkflowGraphEdge>());
edges.get(key1).add(e1);
edges.put(key2, new HashSet<WorkflowGraphEdge>());
edges.get(key2).add(e2);
edges.put(key3, new HashSet<WorkflowGraphEdge>());
edges.get(key3).add(e3);
edges.put(key4, new HashSet<WorkflowGraphEdge>());
edges.get(key4).add(e4);
return new WorkflowGraph(nodes, edges);
}
/**
*
* @return A circle of nodes connected to a sink, so the circle should be resetted.
*/
private WorkflowGraph createCircleWorkflowGraphWithInnerLoopBack() {
nodeNamesToNodes = new HashMap<>();
Map<String, WorkflowGraphNode> nodes = new HashMap<>();
for (int i = 0; i < 1; i++) {
WorkflowGraphNode node = createNewNode(1, 1, true);
nodeNamesToNodes.put(SINK_NODE + i, node);
nodes.put(node.getExecutionIdentifier(), node);
}
WorkflowGraphNode node0 = createNewNode(2, 1, false);
nodeNamesToNodes.put(NODE + 0, node0);
nodes.put(node0.getExecutionIdentifier(), node0);
WorkflowGraphNode node = createNewNode(1, 1, false);
nodeNamesToNodes.put(NODE + 1, node);
nodes.put(node.getExecutionIdentifier(), node);
WorkflowGraphNode lastNode = createNewNode(1, 2, false);
nodeNamesToNodes.put(NODE + 2, lastNode);
nodes.put(lastNode.getExecutionIdentifier(), lastNode);
Map<String, Set<WorkflowGraphEdge>> edges = new HashMap<>();
WorkflowGraphEdge e1 =
createEdge(nodeNamesToNodes.get(SINK_NODE0), 0, EndpointCharacter.SAME_LOOP,
nodeNamesToNodes.get(NODE0), 0, EndpointCharacter.SAME_LOOP);
WorkflowGraphEdge e2 = createEdge(nodeNamesToNodes.get(NODE0), 0, EndpointCharacter.SAME_LOOP,
nodeNamesToNodes.get(NODE1), 0, EndpointCharacter.SAME_LOOP);
WorkflowGraphEdge e3 = createEdge(nodeNamesToNodes.get(NODE1), 0, EndpointCharacter.SAME_LOOP,
nodeNamesToNodes.get(NODE2), 0, EndpointCharacter.SAME_LOOP);
WorkflowGraphEdge e4 = createEdge(nodeNamesToNodes.get(NODE2), 0, EndpointCharacter.SAME_LOOP,
nodeNamesToNodes.get(SINK_NODE0), 0, EndpointCharacter.SAME_LOOP);
WorkflowGraphEdge e5 = createEdge(nodeNamesToNodes.get(NODE2), 0, EndpointCharacter.SAME_LOOP,
nodeNamesToNodes.get(NODE0), 1, EndpointCharacter.SAME_LOOP);
String key1 = WorkflowGraph.createEdgeKey(e1);
String key2 = WorkflowGraph.createEdgeKey(e2);
String key3 = WorkflowGraph.createEdgeKey(e3);
String key4 = WorkflowGraph.createEdgeKey(e4);
edges.put(key1, new HashSet<WorkflowGraphEdge>());
edges.get(key1).add(e1);
edges.put(key2, new HashSet<WorkflowGraphEdge>());
edges.get(key2).add(e2);
edges.put(key3, new HashSet<WorkflowGraphEdge>());
edges.get(key3).add(e3);
edges.put(key4, new HashSet<WorkflowGraphEdge>());
edges.get(key4).add(e4);
edges.get(key4).add(e5);
return new WorkflowGraph(nodes, edges);
}
/**
* Checks whether the given result is correct.
*
* @param hops calculated result
* @param hopsSize size of the map's keys (should be number of outputs of starting node.
* @param outputDequeSize number of Dequeues per output (array field 0 = 'output0', 1 = 'output1', ..)
* @param hopsCounts map of counts for hops for every output.
*/
private static void checkResultCorrect(Map<String, Set<Deque<WorkflowGraphHop>>> hops, int hopsSize, int[] outputDequeSize,
Map<String, List<Integer>> hopsCounts) {
Assert.assertEquals(hopsSize, hops.size());
for (int i = 0; i < outputDequeSize.length; i++) {
Assert.assertEquals(outputDequeSize[i], hops.get(OUTPUT_PREFIX + i).size());
}
for (String hopsName : hops.keySet()) {
List<Integer> hopsCount = hopsCounts.get(hopsName);
for (Deque<WorkflowGraphHop> hopDeque : hops.get(hopsName)) {
if (hopsCount.contains(new Integer(hopDeque.size()))) {
hopsCount.remove(new Integer(hopDeque.size()));
} else {
Assert.fail("Expected result for " + hopsName + " does not contain hops count " + hopDeque.size());
}
String startIdentifier = hopDeque.peek().getHopExecutionIdentifier();
String currentTargetIdentifier = hopDeque.poll().getTargetExecutionIdentifier();
while (hopDeque.size() > 1) {
WorkflowGraphHop hop = hopDeque.poll();
Assert.assertEquals(currentTargetIdentifier, hop.getHopExecutionIdentifier());
currentTargetIdentifier = hop.getTargetExecutionIdentifier();
}
WorkflowGraphHop lastHop = hopDeque.poll();
Assert.assertEquals(currentTargetIdentifier, lastHop.getHopExecutionIdentifier());
Assert.assertEquals(startIdentifier, lastHop.getTargetExecutionIdentifier());
}
if (!hopsCount.isEmpty()) {
Assert.fail(hopsName + " did not have all result hops.");
}
}
}
/**
* Tests the reset behavior for a loop that has sub-loops. A sub-loop is created if a component like the evaluation memory component is
* used. Such a component has inputs and outputs of type 'outer loop' and 'same loop', but it doesn't control the loop.
*
* @throws ComponentExecutionException on unexpected error
*/
@Test
public void testWorkflowGraphResetInLoopWithSubLoops() throws ComponentExecutionException {
Map<String, WorkflowGraphNode> nodes = new HashMap<>();
WorkflowGraphNode outerDriverNode = createNewNode(1, 1, true, "outer-driver");
nodes.put(outerDriverNode.getExecutionIdentifier(), outerDriverNode);
WorkflowGraphNode nestedDriverNode = createNewNode(1, 1, true, "nested-driver");
nodes.put(nestedDriverNode.getExecutionIdentifier(), nestedDriverNode);
WorkflowGraphNode evalMemNode = createNewNode(2, 2, false, "eval-mem");
nodes.put(evalMemNode.getExecutionIdentifier(), evalMemNode);
WorkflowGraphNode node = createNewNode(1, 1, false, "node");
nodes.put(node.getExecutionIdentifier(), node);
Map<String, Set<WorkflowGraphEdge>> edges = new HashMap<>();
Set<WorkflowGraphEdge> edgesSet = new HashSet<>();
edgesSet.add(createEdge(outerDriverNode, 0, EndpointCharacter.SAME_LOOP,
nestedDriverNode, 0, EndpointCharacter.OUTER_LOOP));
edgesSet.add(createEdge(nestedDriverNode, 0, EndpointCharacter.SAME_LOOP,
evalMemNode, 0, EndpointCharacter.OUTER_LOOP));
edgesSet.add(createEdge(evalMemNode, 1, EndpointCharacter.SAME_LOOP,
node, 0, EndpointCharacter.SAME_LOOP));
edgesSet.add(createEdge(node, 0, EndpointCharacter.SAME_LOOP,
evalMemNode, 1, EndpointCharacter.SAME_LOOP));
edgesSet.add(createEdge(evalMemNode, 0, EndpointCharacter.OUTER_LOOP,
nestedDriverNode, 0, EndpointCharacter.SAME_LOOP));
edgesSet.add(createEdge(nestedDriverNode, 0, EndpointCharacter.OUTER_LOOP,
outerDriverNode, 0, EndpointCharacter.SAME_LOOP));
generateAndPutEdgeKeys(edges, edgesSet);
WorkflowGraph graph = new WorkflowGraph(nodes, edges);
Map<String, Set<Deque<WorkflowGraphHop>>> allHops =
graph.getHopsToTraverseWhenResetting(nestedDriverNode.getExecutionIdentifier());
assertEquals(1, allHops.size());
Set<Deque<WorkflowGraphHop>> hopDequesForOnlyOutput = allHops.get(OUTPUT0);
assertEquals(1, hopDequesForOnlyOutput.size());
Deque<WorkflowGraphHop> actualHops = hopDequesForOnlyOutput.iterator().next();
assertEquals(4, actualHops.size());
Deque<String> expectedHops = new LinkedList<>();
expectedHops.add(StringUtils.escapeAndConcat(OUTPUT0, nestedDriverNode.getExecutionIdentifier(),
INPUT0, evalMemNode.getExecutionIdentifier()));
expectedHops.add(StringUtils.escapeAndConcat(OUTPUT1, evalMemNode.getExecutionIdentifier(),
INPUT0, node.getExecutionIdentifier()));
expectedHops.add(StringUtils.escapeAndConcat(OUTPUT0, node.getExecutionIdentifier(),
INPUT1, evalMemNode.getExecutionIdentifier()));
expectedHops.add(StringUtils.escapeAndConcat(OUTPUT0, evalMemNode.getExecutionIdentifier(),
INPUT0, nestedDriverNode.getExecutionIdentifier()));
assertWorkflowGraphHops(expectedHops, actualHops);
}
private void assertWorkflowGraphHops(Deque<String> expectedHops, Deque<WorkflowGraphHop> actualHops) {
assertEquals(expectedHops.size(), actualHops.size());
Iterator<WorkflowGraphHop> hopsIterator = actualHops.iterator();
while (hopsIterator.hasNext()) {
WorkflowGraphHop hop = hopsIterator.next();
String[] hopParts = StringUtils.splitAndUnescape(expectedHops.poll());
assertEquals(hopParts[0], hop.getHopOuputName());
assertEquals(hopParts[1], hop.getHopExecutionIdentifier());
assertEquals(hopParts[2], hop.getTargetInputName());
assertEquals(hopParts[3], hop.getTargetExecutionIdentifier());
}
}
private static WorkflowGraphEdge createEdge(WorkflowGraphNode source, int outputNumber, EndpointCharacter outputType,
WorkflowGraphNode target,
int inputNumber, EndpointCharacter inputType) {
String outputIdentifier = null;
for (String output : source.getOutputIdentifiers()) {
if (source.getEndpointName(output).equals(OUTPUT_PREFIX + outputNumber)) {
outputIdentifier = output;
}
}
String inputIdentifier = null;
for (String input : target.getInputIdentifiers()) {
if (target.getEndpointName(input).equals(INPUT_PREFIX + inputNumber)) {
inputIdentifier = input;
}
}
if (outputIdentifier != null && inputIdentifier != null) {
return new WorkflowGraphEdge(source.getExecutionIdentifier(), outputIdentifier, outputType, target.getExecutionIdentifier(),
inputIdentifier, inputType);
}
return null;
}
private static WorkflowGraphNode createNewNode(int inputCount, int outputCount, boolean isDriver) {
return createNewNode(inputCount, outputCount, isDriver, RandomStringUtils.randomAlphabetic(5));
}
private static WorkflowGraphNode createNewNode(int inputCount, int outputCount, boolean isDriver, String name) {
Set<String> inputs = new HashSet<>();
for (int i = 0; i < inputCount; i++) {
inputs.add(UUID.randomUUID().toString());
}
Set<String> outputs = new HashSet<>();
for (int i = 0; i < outputCount; i++) {
outputs.add(UUID.randomUUID().toString());
}
Map<String, String> endpointnames = new HashMap<>();
int i = 0;
for (String input : inputs) {
endpointnames.put(input, INPUT_PREFIX + i);
i++;
}
i = 0;
for (String output : outputs) {
endpointnames.put(output, OUTPUT_PREFIX + i);
i++;
}
return new WorkflowGraphNode(UUID.randomUUID().toString(), inputs, outputs, endpointnames, isDriver, false, name);
}
private void generateAndPutEdgeKeys(Map<String, Set<WorkflowGraphEdge>> edges, Set<WorkflowGraphEdge> edgesSet) {
for (WorkflowGraphEdge egdge : edgesSet) {
String key = WorkflowGraph.createEdgeKey(egdge);
if (!edges.containsKey(key)) {
edges.put(key, new HashSet<WorkflowGraphEdge>());
}
edges.get(key).add(egdge);
}
}
}