From cbdb5c818e986cbd90794b8eeff47c8592c02b04 Mon Sep 17 00:00:00 2001 From: Greg Schueler Date: Sat, 18 Jan 2014 10:17:27 -0800 Subject: [PATCH] WIP: add parsing for execution state --- .../org/rundeck/api/domain/BaseState.java | 47 +++++++ .../api/domain/RundeckExecutionState.java | 38 ++++++ .../api/domain/RundeckWFExecState.java | 43 ++++++ .../org/rundeck/api/domain/WorkflowState.java | 40 ++++++ .../api/domain/WorkflowStepContextState.java | 25 ++++ .../rundeck/api/domain/WorkflowStepState.java | 37 ++++++ .../rundeck/api/parser/BaseStateParser.java | 42 ++++++ .../api/parser/ExecutionStateParser.java | 60 +++++++++ .../IndexedWorkflowStepStateParser.java | 61 +++++++++ .../api/parser/WorkflowStateParser.java | 83 ++++++++++++ .../WorkflowStepContextStateParser.java | 27 ++++ .../api/parser/WorkflowStepStateParser.java | 51 ++++++++ .../api/parser/BaseStateParserTest.java | 40 ++++++ .../api/parser/ExecutionStateParserTest.java | 43 ++++++ .../IndexedWorkflowStepStateParserTest.java | 73 +++++++++++ .../api/parser/WorkflowStateParserTest.java | 65 ++++++++++ .../parser/WorkflowStepStateParserTest.java | 122 ++++++++++++++++++ .../rundeck/api/parser/execution-state1.xml | 81 ++++++++++++ .../rundeck/api/parser/execution-state2.xml | 96 ++++++++++++++ 19 files changed, 1074 insertions(+) create mode 100644 src/main/java/org/rundeck/api/domain/BaseState.java create mode 100644 src/main/java/org/rundeck/api/domain/RundeckExecutionState.java create mode 100644 src/main/java/org/rundeck/api/domain/RundeckWFExecState.java create mode 100644 src/main/java/org/rundeck/api/domain/WorkflowState.java create mode 100644 src/main/java/org/rundeck/api/domain/WorkflowStepContextState.java create mode 100644 src/main/java/org/rundeck/api/domain/WorkflowStepState.java create mode 100644 src/main/java/org/rundeck/api/parser/BaseStateParser.java create mode 100644 src/main/java/org/rundeck/api/parser/ExecutionStateParser.java create mode 100644 src/main/java/org/rundeck/api/parser/IndexedWorkflowStepStateParser.java create mode 100644 src/main/java/org/rundeck/api/parser/WorkflowStateParser.java create mode 100644 src/main/java/org/rundeck/api/parser/WorkflowStepContextStateParser.java create mode 100644 src/main/java/org/rundeck/api/parser/WorkflowStepStateParser.java create mode 100644 src/test/java/org/rundeck/api/parser/BaseStateParserTest.java create mode 100644 src/test/java/org/rundeck/api/parser/ExecutionStateParserTest.java create mode 100644 src/test/java/org/rundeck/api/parser/IndexedWorkflowStepStateParserTest.java create mode 100644 src/test/java/org/rundeck/api/parser/WorkflowStateParserTest.java create mode 100644 src/test/java/org/rundeck/api/parser/WorkflowStepStateParserTest.java create mode 100644 src/test/resources/org/rundeck/api/parser/execution-state1.xml create mode 100644 src/test/resources/org/rundeck/api/parser/execution-state2.xml diff --git a/src/main/java/org/rundeck/api/domain/BaseState.java b/src/main/java/org/rundeck/api/domain/BaseState.java new file mode 100644 index 0000000..7c7c146 --- /dev/null +++ b/src/main/java/org/rundeck/api/domain/BaseState.java @@ -0,0 +1,47 @@ +package org.rundeck.api.domain; + +import java.util.Date; +import java.util.List; +import java.util.Set; + +/** + * $INTERFACE is ... User: greg Date: 1/17/14 Time: 11:26 AM + */ +public class BaseState { + private Date startTime; + private Date endTime; + private Date updateTime; + private RundeckWFExecState executionState; + + public Date getStartTime() { + return startTime; + } + + public void setStartTime(Date startTime) { + this.startTime = startTime; + } + + public Date getEndTime() { + return endTime; + } + + public void setEndTime(Date endTime) { + this.endTime = endTime; + } + + public RundeckWFExecState getExecutionState() { + return executionState; + } + + public void setExecutionState(RundeckWFExecState executionState) { + this.executionState = executionState; + } + + public Date getUpdateTime() { + return updateTime; + } + + public void setUpdateTime(Date updateTime) { + this.updateTime = updateTime; + } +} diff --git a/src/main/java/org/rundeck/api/domain/RundeckExecutionState.java b/src/main/java/org/rundeck/api/domain/RundeckExecutionState.java new file mode 100644 index 0000000..139a76d --- /dev/null +++ b/src/main/java/org/rundeck/api/domain/RundeckExecutionState.java @@ -0,0 +1,38 @@ +package org.rundeck.api.domain; + +import java.util.List; +import java.util.Map; +import java.util.Set; + +/** + * $INTERFACE is ... User: greg Date: 1/16/14 Time: 5:41 PM + */ +public class RundeckExecutionState extends WorkflowState{ + private long executionId; + private Set allNodes; + private Map> nodeStates; + + public Set getAllNodes() { + return allNodes; + } + + public void setAllNodes(Set allNodes) { + this.allNodes = allNodes; + } + + public Map> getNodeStates() { + return nodeStates; + } + + public void setNodeStates(Map> nodeStates) { + this.nodeStates = nodeStates; + } + + public long getExecutionId() { + return executionId; + } + + public void setExecutionId(long executionId) { + this.executionId = executionId; + } +} diff --git a/src/main/java/org/rundeck/api/domain/RundeckWFExecState.java b/src/main/java/org/rundeck/api/domain/RundeckWFExecState.java new file mode 100644 index 0000000..f15f8ea --- /dev/null +++ b/src/main/java/org/rundeck/api/domain/RundeckWFExecState.java @@ -0,0 +1,43 @@ +package org.rundeck.api.domain; + +/** + * $INTERFACE is ... User: greg Date: 1/17/14 Time: 11:27 AM + */ +public enum RundeckWFExecState { + /** + * Waiting to start running + */ + WAITING, + /** + * Currently running + */ + RUNNING, + /** + * Running error handler + */ + RUNNING_HANDLER, + /** + * Finished running successfully + */ + SUCCEEDED, + /** + * Finished with a failure + */ + FAILED, + /** + * Execution was aborted + */ + ABORTED, + /** + * Partial success for some nodes + */ + NODE_PARTIAL_SUCCEEDED, + /** + * Mixed states among nodes + */ + NODE_MIXED, + /** + * After waiting the execution did not start + */ + NOT_STARTED,; +} diff --git a/src/main/java/org/rundeck/api/domain/WorkflowState.java b/src/main/java/org/rundeck/api/domain/WorkflowState.java new file mode 100644 index 0000000..753ecab --- /dev/null +++ b/src/main/java/org/rundeck/api/domain/WorkflowState.java @@ -0,0 +1,40 @@ +package org.rundeck.api.domain; + +import java.util.Date; +import java.util.List; +import java.util.Map; +import java.util.Set; + +/** + * $INTERFACE is ... User: greg Date: 1/16/14 Time: 5:44 PM + */ +public class WorkflowState extends BaseState{ + private int stepCount; + private Set targetNodes; + private List steps; + + public int getStepCount() { + return stepCount; + } + + public void setStepCount(int stepCount) { + this.stepCount = stepCount; + } + + public Set getTargetNodes() { + return targetNodes; + } + + public void setTargetNodes(Set targetNodes) { + this.targetNodes = targetNodes; + } + + public List getSteps() { + return steps; + } + + public void setSteps(List steps) { + this.steps = steps; + } + +} diff --git a/src/main/java/org/rundeck/api/domain/WorkflowStepContextState.java b/src/main/java/org/rundeck/api/domain/WorkflowStepContextState.java new file mode 100644 index 0000000..3bebc05 --- /dev/null +++ b/src/main/java/org/rundeck/api/domain/WorkflowStepContextState.java @@ -0,0 +1,25 @@ +package org.rundeck.api.domain; + +/** + * A state for a particular step + */ +public class WorkflowStepContextState extends BaseState { + private String stepContextId; + private String stepNum; + + public String getStepContextId() { + return stepContextId; + } + + public void setStepContextId(String stepContextId) { + this.stepContextId = stepContextId; + } + + public String getStepNum() { + return stepNum; + } + + public void setStepNum(String stepNum) { + this.stepNum = stepNum; + } +} diff --git a/src/main/java/org/rundeck/api/domain/WorkflowStepState.java b/src/main/java/org/rundeck/api/domain/WorkflowStepState.java new file mode 100644 index 0000000..b7e6306 --- /dev/null +++ b/src/main/java/org/rundeck/api/domain/WorkflowStepState.java @@ -0,0 +1,37 @@ +package org.rundeck.api.domain; + +import java.util.List; +import java.util.Map; + +/** + * $INTERFACE is ... User: greg Date: 1/17/14 Time: 12:03 PM + */ +public class WorkflowStepState extends WorkflowStepContextState { + private boolean nodeStep; + private WorkflowState subWorkflow; + private Map nodeStates; + + public boolean isNodeStep() { + return nodeStep; + } + + public void setNodeStep(boolean nodeStep) { + this.nodeStep = nodeStep; + } + + public WorkflowState getSubWorkflow() { + return subWorkflow; + } + + public void setSubWorkflow(WorkflowState subWorkflow) { + this.subWorkflow = subWorkflow; + } + + public Map getNodeStates() { + return nodeStates; + } + + public void setNodeStates(Map nodeStates) { + this.nodeStates = nodeStates; + } +} diff --git a/src/main/java/org/rundeck/api/parser/BaseStateParser.java b/src/main/java/org/rundeck/api/parser/BaseStateParser.java new file mode 100644 index 0000000..5cd31d1 --- /dev/null +++ b/src/main/java/org/rundeck/api/parser/BaseStateParser.java @@ -0,0 +1,42 @@ +package org.rundeck.api.parser; + +import org.apache.commons.lang.StringUtils; +import org.dom4j.Node; +import org.rundeck.api.domain.BaseState; +import org.rundeck.api.domain.RundeckWFExecState; + +/** + * $INTERFACE is ... User: greg Date: 1/17/14 Time: 12:19 PM + */ +public class BaseStateParser implements XmlNodeParser { + public static void parseBaseState(Node targetNode, BaseState state) { + state.setEndTime(WorkflowStateParser.parseDate(StringUtils.trimToNull(targetNode.valueOf("endTime")))); + state.setStartTime(WorkflowStateParser.parseDate(StringUtils.trimToNull(targetNode.valueOf("startTime")))); + state.setUpdateTime(WorkflowStateParser.parseDate(StringUtils.trimToNull(targetNode.valueOf("updateTime")))); + + try { + state.setExecutionState(RundeckWFExecState.valueOf(StringUtils.upperCase(targetNode.valueOf + ("executionState")))); + } catch (IllegalArgumentException e) { + state.setExecutionState(null); + } + } + + private String xpath; + + public BaseStateParser() { + } + + public BaseStateParser(String xpath) { + + this.xpath = xpath; + } + + @Override + public BaseState parseXmlNode(Node node) { + Node targetNode = xpath != null ? node.selectSingleNode(xpath) : node; + BaseState baseState = new BaseState(); + parseBaseState(targetNode, baseState); + return baseState; + } +} diff --git a/src/main/java/org/rundeck/api/parser/ExecutionStateParser.java b/src/main/java/org/rundeck/api/parser/ExecutionStateParser.java new file mode 100644 index 0000000..180b425 --- /dev/null +++ b/src/main/java/org/rundeck/api/parser/ExecutionStateParser.java @@ -0,0 +1,60 @@ +package org.rundeck.api.parser; + +import org.apache.commons.lang.StringUtils; +import org.dom4j.Node; +import org.rundeck.api.domain.*; + +import java.util.HashMap; +import java.util.HashSet; +import java.util.List; + +/** + * $INTERFACE is ... User: greg Date: 1/16/14 Time: 5:42 PM + */ +public class ExecutionStateParser implements XmlNodeParser { + private String xpath; + + public ExecutionStateParser() { + super(); + } + + /** + * @param xpath of the execution element if it is not the root node + */ + public ExecutionStateParser(String xpath) { + this(); + this.xpath = xpath; + } + + @Override + public RundeckExecutionState parseXmlNode(Node node) { + Node targetNode = xpath != null ? node.selectSingleNode(xpath) : node; + RundeckExecutionState rundeckExecutionState = new RundeckExecutionState(); + rundeckExecutionState.setExecutionId(Long.valueOf(targetNode.valueOf("@id"))); + + WorkflowStateParser.parseWorkflowState(targetNode, rundeckExecutionState); + + + final List rundeckNodes = + new ListParser(new NodeParser(), "allNodes/nodes/node").parseXmlNode(targetNode); + rundeckExecutionState.setAllNodes(new HashSet(rundeckNodes)); + + + //node states + HashMap> nodeStates = new HashMap>(); + + for (Object o : targetNode.selectNodes("nodes/node")) { + final Node nodeStateNode = (Node) o; + final String nodeName = StringUtils.trimToNull(nodeStateNode.valueOf("@name")); + if (null != nodeName) { + ListParser workflowStepStateListParser + = new ListParser(new IndexedWorkflowStepStateParser(rundeckExecutionState, nodeName) + , "steps/step"); + nodeStates.put(nodeName, workflowStepStateListParser.parseXmlNode(nodeStateNode)); + } + } + rundeckExecutionState.setNodeStates(nodeStates); + + return rundeckExecutionState; + } +} diff --git a/src/main/java/org/rundeck/api/parser/IndexedWorkflowStepStateParser.java b/src/main/java/org/rundeck/api/parser/IndexedWorkflowStepStateParser.java new file mode 100644 index 0000000..16f7fd4 --- /dev/null +++ b/src/main/java/org/rundeck/api/parser/IndexedWorkflowStepStateParser.java @@ -0,0 +1,61 @@ +package org.rundeck.api.parser; + +import org.apache.commons.lang.StringUtils; +import org.dom4j.Node; +import org.rundeck.api.domain.WorkflowState; +import org.rundeck.api.domain.WorkflowStepContextState; +import org.rundeck.api.domain.WorkflowStepState; + +/** + * Returns a WorkflowStepContextState by looking up the given Rundeck node's state in the workflow, using the step + * context path of the "stepctx" element of the selected DOM node. + */ +public class IndexedWorkflowStepStateParser implements XmlNodeParser { + private final WorkflowState workflowState; + private String rundeckNodeName; + + @Override + public WorkflowStepContextState parseXmlNode(final Node node) { + //look for workflow step state based on node name and stepctx found on the node + final String stepctx = StringUtils.trimToNull(node.valueOf("stepctx")); + final WorkflowStepState foundStep = lookupContext(stepctx, workflowState); + //look up node state for this node + if (null != foundStep + && null != foundStep.getNodeStates() + && null != foundStep.getNodeStates().get(rundeckNodeName)) { + return foundStep.getNodeStates().get(rundeckNodeName); + } + + + return null; + } + + /** + * look up the workflow step state for the step context, from the root workflow + * + * @param stepctx + * @param initial + * + * @return + */ + public static WorkflowStepState lookupContext(final String stepctx, final WorkflowState initial) { + final String[] parts = stepctx.split("/"); + //descend workflow steps to find correct step + WorkflowState current = initial; + WorkflowStepState currentStep = null; + for (int i = 0; i < parts.length; i++) { + final String part = parts[i]; + final WorkflowStepState workflowStepState = current.getSteps().get(Integer.parseInt(part) - 1); + currentStep = workflowStepState; + if (i < parts.length - 1) { + current = currentStep.getSubWorkflow(); + } + } + return currentStep; + } + + public IndexedWorkflowStepStateParser(final WorkflowState workflowState, final String rundeckNodeName) { + this.workflowState = workflowState; + this.rundeckNodeName = rundeckNodeName; + } +} diff --git a/src/main/java/org/rundeck/api/parser/WorkflowStateParser.java b/src/main/java/org/rundeck/api/parser/WorkflowStateParser.java new file mode 100644 index 0000000..36ffe57 --- /dev/null +++ b/src/main/java/org/rundeck/api/parser/WorkflowStateParser.java @@ -0,0 +1,83 @@ +package org.rundeck.api.parser; + +import org.apache.commons.lang.StringUtils; +import org.dom4j.Node; +import org.rundeck.api.domain.*; + +import java.text.DateFormat; +import java.text.ParseException; +import java.text.SimpleDateFormat; +import java.util.*; + +/** + * $INTERFACE is ... User: greg Date: 1/16/14 Time: 5:44 PM + */ +public class WorkflowStateParser implements XmlNodeParser { + private String xpath; + + public WorkflowStateParser() { + } + + public WorkflowStateParser(String xpath) { + this(); + this.xpath = xpath; + } + + private static final ThreadLocal w3cDateFormat = new ThreadLocal() { + protected DateFormat initialValue() { + SimpleDateFormat fmt = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss'Z'", Locale.US); + fmt.setTimeZone(TimeZone.getTimeZone("GMT")); + return fmt; + } + }; + public static Date parseDate(String s) { + if (null == s) { + return null; + } + try { + Date parse = w3cDateFormat.get().parse(s); + return parse; + } catch (ParseException e) { + return null; + } + } + + private static int integerValue(final String value, final int defValue) { + int parseMax = defValue; + try { + parseMax = null != value ? Integer.parseInt(value) : defValue; + } catch (NumberFormatException e) { + } + return parseMax; + } + + @Override + public WorkflowState parseXmlNode(Node node) { + Node targetNode = xpath != null ? node.selectSingleNode(xpath) : node; + WorkflowState state = new WorkflowState(); + parseWorkflowState(targetNode, state); + + + return state; + } + + /** + * Parse the workflow state components from the given dom node + * @param targetNode + * @param state + */ + public static void parseWorkflowState(Node targetNode, WorkflowState state) { + BaseStateParser.parseBaseState(targetNode, state); + + state.setStepCount(integerValue(StringUtils.trimToNull(targetNode.valueOf("stepCount")), 0)); + + final List rundeckNodes = + new ListParser(new NodeParser(), "targetNodes/nodes/node").parseXmlNode(targetNode); + state.setTargetNodes(new HashSet(rundeckNodes)); + + //steps + state.setSteps(new ListParser(new WorkflowStepStateParser(), + "steps/step").parseXmlNode(targetNode)); + } + +} diff --git a/src/main/java/org/rundeck/api/parser/WorkflowStepContextStateParser.java b/src/main/java/org/rundeck/api/parser/WorkflowStepContextStateParser.java new file mode 100644 index 0000000..c744cac --- /dev/null +++ b/src/main/java/org/rundeck/api/parser/WorkflowStepContextStateParser.java @@ -0,0 +1,27 @@ +package org.rundeck.api.parser; + +import org.dom4j.Node; +import org.rundeck.api.domain.WorkflowStepContextState; +import org.rundeck.api.domain.WorkflowStepState; + +/** + * $INTERFACE is ... User: greg Date: 1/17/14 Time: 12:39 PM + */ +public class WorkflowStepContextStateParser implements XmlNodeParser { + WorkflowStepContextState inherit; + + public WorkflowStepContextStateParser(WorkflowStepContextState inherit) { + this.inherit = inherit; + } + + @Override + public WorkflowStepContextState parseXmlNode(Node node) { + WorkflowStepContextState workflowStepState = new WorkflowStepContextState(); + if(null!=inherit) { + workflowStepState.setStepNum(inherit.getStepNum()); + workflowStepState.setStepContextId(inherit.getStepContextId()); + } + BaseStateParser.parseBaseState(node, workflowStepState); + return workflowStepState; + } +} diff --git a/src/main/java/org/rundeck/api/parser/WorkflowStepStateParser.java b/src/main/java/org/rundeck/api/parser/WorkflowStepStateParser.java new file mode 100644 index 0000000..ede8d7c --- /dev/null +++ b/src/main/java/org/rundeck/api/parser/WorkflowStepStateParser.java @@ -0,0 +1,51 @@ +package org.rundeck.api.parser; + +import org.apache.commons.lang.StringUtils; +import org.dom4j.Node; +import org.rundeck.api.domain.BaseState; +import org.rundeck.api.domain.WorkflowStepContextState; +import org.rundeck.api.domain.WorkflowStepState; + +import java.util.HashMap; + +/** + * $INTERFACE is ... User: greg Date: 1/17/14 Time: 12:09 PM + */ +public class WorkflowStepStateParser implements XmlNodeParser { + private String xpath; + + public WorkflowStepStateParser(final String xpath) { + this.xpath = xpath; + } + + public WorkflowStepStateParser() { + } + + @Override + public WorkflowStepState parseXmlNode(final Node node) { + final Node targetNode = xpath != null ? node.selectSingleNode(xpath) : node; + final WorkflowStepState state = new WorkflowStepState(); + + BaseStateParser.parseBaseState(targetNode, state); + state.setStepContextId(StringUtils.trimToNull(targetNode.valueOf("@stepctx"))); + state.setStepNum(StringUtils.trimToNull(targetNode.valueOf("@id"))); + state.setNodeStep(Boolean.valueOf(StringUtils.trimToNull(targetNode.valueOf("nodeStep")))); + if (Boolean.valueOf(StringUtils.trimToNull(targetNode.valueOf("hasSubworkflow")))) { + //parse sub workflow + state.setSubWorkflow(new WorkflowStateParser("workflow").parseXmlNode(targetNode)); + } + if (Boolean.valueOf(StringUtils.trimToNull(targetNode.valueOf("nodeStep")))) { + //node states + final HashMap nodeStates = new HashMap(); + for (final Object o : targetNode.selectNodes("nodeStates/nodeState")) { + final Node nodeStateNode = (Node) o; + final String nodeName = StringUtils.trimToNull(nodeStateNode.valueOf("@name")); + if (null != nodeName) { + nodeStates.put(nodeName, new WorkflowStepContextStateParser(state).parseXmlNode(nodeStateNode)); + } + } + state.setNodeStates(nodeStates); + } + return state; + } +} diff --git a/src/test/java/org/rundeck/api/parser/BaseStateParserTest.java b/src/test/java/org/rundeck/api/parser/BaseStateParserTest.java new file mode 100644 index 0000000..3c17f27 --- /dev/null +++ b/src/test/java/org/rundeck/api/parser/BaseStateParserTest.java @@ -0,0 +1,40 @@ +package org.rundeck.api.parser; + +import junit.framework.Assert; +import org.dom4j.Document; +import org.junit.Test; +import org.rundeck.api.domain.BaseState; +import org.rundeck.api.domain.RundeckWFExecState; + +import java.io.InputStream; +import java.util.Date; + +/** + * $INTERFACE is ... User: greg Date: 1/18/14 Time: 8:33 AM + */ +public class BaseStateParserTest { + @Test + public void testBase1(){ + InputStream input = getClass().getResourceAsStream("execution-state1.xml"); + Document document = ParserHelper.loadDocument(input); + BaseState baseState = new BaseState(); + BaseStateParser.parseBaseState(document.selectSingleNode("/result/executionState"), baseState); + + Assert.assertEquals(1390066160000L, baseState.getEndTime().getTime()); + Assert.assertEquals(1390066159000L, baseState.getStartTime().getTime()); + Assert.assertEquals(1390066160000L, baseState.getUpdateTime().getTime()); + Assert.assertEquals(RundeckWFExecState.SUCCEEDED, baseState.getExecutionState()); + } + @Test + public void testBase2(){ + InputStream input = getClass().getResourceAsStream("execution-state1.xml"); + Document document = ParserHelper.loadDocument(input); + BaseState baseState = new BaseState(); + BaseStateParser.parseBaseState(document.selectSingleNode("/result/executionState/steps/step[1]"), baseState); + + Assert.assertEquals(1390066159000L, baseState.getStartTime().getTime()); + Assert.assertEquals(1390066160000L, baseState.getEndTime().getTime()); + Assert.assertEquals(1390066160000L, baseState.getUpdateTime().getTime()); + Assert.assertEquals(RundeckWFExecState.SUCCEEDED, baseState.getExecutionState()); + } +} diff --git a/src/test/java/org/rundeck/api/parser/ExecutionStateParserTest.java b/src/test/java/org/rundeck/api/parser/ExecutionStateParserTest.java new file mode 100644 index 0000000..c8170bd --- /dev/null +++ b/src/test/java/org/rundeck/api/parser/ExecutionStateParserTest.java @@ -0,0 +1,43 @@ +package org.rundeck.api.parser; + +import junit.framework.Assert; +import org.dom4j.Document; +import org.junit.Test; +import org.rundeck.api.domain.RundeckExecutionState; +import org.rundeck.api.domain.RundeckNodeIdentity; + +import java.io.InputStream; +import java.util.Arrays; +import java.util.HashSet; + +/** + * $INTERFACE is ... User: greg Date: 1/16/14 Time: 5:42 PM + */ +public class ExecutionStateParserTest { + @Test + public void testBasic(){ + InputStream input = getClass().getResourceAsStream("execution-state1.xml"); + Document document = ParserHelper.loadDocument(input); + + RundeckExecutionState execution = new ExecutionStateParser("/result/executionState").parseXmlNode + (document); + + Assert.assertEquals(149L, execution.getExecutionId()); + + HashSet expectedTargetNodes = new HashSet(Arrays.asList( + "node-111.qa.subgroup.mycompany.com", + "node-14.qa.subgroup.mycompany.com", + "node-6.qa.subgroup.mycompany.com" + )); + + Assert.assertEquals(3, execution.getAllNodes().size()); + for (RundeckNodeIdentity rundeckNodeIdentity : execution.getAllNodes()) { + Assert.assertTrue(expectedTargetNodes.contains(rundeckNodeIdentity.getName())); + } + + Assert.assertEquals(3,execution.getNodeStates().size()); + for (String s : execution.getNodeStates().keySet()) { + Assert.assertTrue(expectedTargetNodes.contains(s)); + } + } +} diff --git a/src/test/java/org/rundeck/api/parser/IndexedWorkflowStepStateParserTest.java b/src/test/java/org/rundeck/api/parser/IndexedWorkflowStepStateParserTest.java new file mode 100644 index 0000000..7b865c8 --- /dev/null +++ b/src/test/java/org/rundeck/api/parser/IndexedWorkflowStepStateParserTest.java @@ -0,0 +1,73 @@ +package org.rundeck.api.parser; + +import junit.framework.Assert; +import org.dom4j.Document; +import org.dom4j.DocumentException; +import org.dom4j.DocumentHelper; +import org.dom4j.Element; +import org.junit.Test; +import org.rundeck.api.domain.WorkflowState; +import org.rundeck.api.domain.WorkflowStepContextState; +import org.rundeck.api.domain.WorkflowStepState; + +import java.util.Arrays; +import java.util.HashMap; + +/** + * $INTERFACE is ... User: greg Date: 1/18/14 Time: 9:57 AM + */ +public class IndexedWorkflowStepStateParserTest { + @Test + public void testLookupContextSimple1(){ + WorkflowState workflowState = new WorkflowState(); + WorkflowStepState step1 = new WorkflowStepState(); + workflowState.setSteps(Arrays.asList(step1)); + WorkflowStepState stepState = IndexedWorkflowStepStateParser.lookupContext("1", workflowState); + Assert.assertEquals(step1,stepState); + } + @Test + public void testLookupContextSimple2(){ + WorkflowState workflowState = new WorkflowState(); + WorkflowStepState step1 = new WorkflowStepState(); + WorkflowStepState step2 = new WorkflowStepState(); + workflowState.setSteps(Arrays.asList(step1,step2)); + WorkflowStepState stepState = IndexedWorkflowStepStateParser.lookupContext("2", workflowState); + Assert.assertEquals(step2,stepState); + } + @Test + public void testLookupContextDescend1(){ + WorkflowState workflowState = new WorkflowState(); + WorkflowStepState step1 = new WorkflowStepState(); + WorkflowStepState step2 = new WorkflowStepState(); + WorkflowState sub1 = new WorkflowState(); + step2.setSubWorkflow(sub1); + workflowState.setSteps(Arrays.asList(step1,step2)); + + WorkflowStepState step21 = new WorkflowStepState(); + sub1.setSteps(Arrays.asList(step21)); + + WorkflowStepState stepState = IndexedWorkflowStepStateParser.lookupContext("2/1", workflowState); + Assert.assertEquals(step21,stepState); + } + @Test + public void testParse1() throws DocumentException { + WorkflowState workflowState = new WorkflowState(); + WorkflowStepState step1 = new WorkflowStepState(); + WorkflowStepState step2 = new WorkflowStepState(); + WorkflowState sub1 = new WorkflowState(); + step2.setSubWorkflow(sub1); + workflowState.setSteps(Arrays.asList(step1,step2)); + + WorkflowStepState step21 = new WorkflowStepState(); + sub1.setSteps(Arrays.asList(step21)); + HashMap nodeStates = new HashMap(); + WorkflowStepContextState nodeState1 = new WorkflowStepContextState(); + nodeStates.put("dignan", nodeState1); + step21.setNodeStates(nodeStates); + + Document document = DocumentHelper.parseText("2/1"); + + WorkflowStepContextState result = new IndexedWorkflowStepStateParser(workflowState,"dignan").parseXmlNode(document); + Assert.assertEquals(nodeState1,result); + } +} diff --git a/src/test/java/org/rundeck/api/parser/WorkflowStateParserTest.java b/src/test/java/org/rundeck/api/parser/WorkflowStateParserTest.java new file mode 100644 index 0000000..3d90d9e --- /dev/null +++ b/src/test/java/org/rundeck/api/parser/WorkflowStateParserTest.java @@ -0,0 +1,65 @@ +package org.rundeck.api.parser; + +import junit.framework.Assert; +import org.dom4j.Document; +import org.junit.Test; +import org.rundeck.api.domain.*; + +import java.io.InputStream; +import java.util.Arrays; +import java.util.Date; +import java.util.HashSet; + +/** + * $INTERFACE is ... User: greg Date: 1/16/14 Time: 5:47 PM + */ +public class WorkflowStateParserTest { + @Test + public void parseBasic(){ + InputStream input = getClass().getResourceAsStream("execution-state1.xml"); + Document document = ParserHelper.loadDocument(input); + + WorkflowState execution = new WorkflowStateParser("result/executionState").parseXmlNode(document); + Assert.assertEquals(1390066159000L, execution.getStartTime().getTime()); + Assert.assertEquals(1390066160000L, execution.getEndTime().getTime()); + Assert.assertEquals(1390066160000L, execution.getUpdateTime().getTime()); + Assert.assertEquals(RundeckWFExecState.SUCCEEDED, execution.getExecutionState()); + Assert.assertEquals(1, execution.getStepCount()); + Assert.assertEquals(3, execution.getTargetNodes().size()); + HashSet expectedTargetNodes = new HashSet(Arrays.asList( + "node-111.qa.subgroup.mycompany.com", + "node-14.qa.subgroup.mycompany.com", + "node-6.qa.subgroup.mycompany.com" + )); + for (RundeckNodeIdentity rundeckNodeIdentity : execution.getTargetNodes()) { + Assert.assertTrue(expectedTargetNodes.contains(rundeckNodeIdentity.getName())); + } + + // + Assert.assertEquals(1,execution.getSteps().size()); + WorkflowStepState step1 = execution.getSteps().get(0); + } + @Test + public void parse(){ + InputStream input = getClass().getResourceAsStream("execution-state2.xml"); + Document document = ParserHelper.loadDocument(input); + + WorkflowState execution = new WorkflowStateParser("result/executionState").parseXmlNode(document); + Assert.assertEquals(1390066061000L, execution.getStartTime().getTime()); + Assert.assertEquals(null, execution.getEndTime()); + Assert.assertEquals(1390066067000L, execution.getUpdateTime().getTime()); + Assert.assertEquals(RundeckWFExecState.RUNNING, execution.getExecutionState()); + Assert.assertEquals(2, execution.getStepCount()); + Assert.assertEquals(1, execution.getTargetNodes().size()); + HashSet expectedTargetNodes = new HashSet(Arrays.asList( + "dignan" + )); + for (RundeckNodeIdentity rundeckNodeIdentity : execution.getTargetNodes()) { + Assert.assertTrue(expectedTargetNodes.contains(rundeckNodeIdentity.getName())); + } + + // + Assert.assertEquals(2,execution.getSteps().size()); + WorkflowStepState step1 = execution.getSteps().get(0); + } +} diff --git a/src/test/java/org/rundeck/api/parser/WorkflowStepStateParserTest.java b/src/test/java/org/rundeck/api/parser/WorkflowStepStateParserTest.java new file mode 100644 index 0000000..418ecdb --- /dev/null +++ b/src/test/java/org/rundeck/api/parser/WorkflowStepStateParserTest.java @@ -0,0 +1,122 @@ +package org.rundeck.api.parser; + +import junit.framework.Assert; +import org.dom4j.Document; +import org.junit.Test; +import org.rundeck.api.domain.*; + +import java.io.InputStream; +import java.util.Arrays; +import java.util.HashSet; + +/** + * $INTERFACE is ... User: greg Date: 1/18/14 Time: 9:00 AM + */ +public class WorkflowStepStateParserTest { + + @Test + public void testParse1() { + InputStream input = getClass().getResourceAsStream("execution-state1.xml"); + Document document = ParserHelper.loadDocument(input); + WorkflowStepState stepState = new WorkflowStepStateParser().parseXmlNode(document.selectSingleNode + ("/result/executionState/steps/step[1]")); + + Assert.assertNotNull(stepState); + Assert.assertEquals(true, stepState.isNodeStep()); + Assert.assertEquals(null, stepState.getSubWorkflow()); + Assert.assertNotNull(stepState.getNodeStates()); + Assert.assertEquals("1", stepState.getStepContextId()); + Assert.assertEquals("1", stepState.getStepNum()); + Assert.assertEquals(1390066159000L, stepState.getStartTime().getTime()); + Assert.assertEquals(1390066160000L, stepState.getEndTime().getTime()); + Assert.assertEquals(1390066160000L, stepState.getUpdateTime().getTime()); + Assert.assertEquals(RundeckWFExecState.SUCCEEDED, stepState.getExecutionState()); + HashSet expectedTargetNodes = new HashSet(Arrays.asList( + "node-111.qa.subgroup.mycompany.com", + "node-14.qa.subgroup.mycompany.com", + "node-6.qa.subgroup.mycompany.com" + )); + + int i = 0; + for (String s : stepState.getNodeStates().keySet()) { + Assert.assertTrue(expectedTargetNodes.contains(s)); + WorkflowStepContextState workflowStepContextState = stepState.getNodeStates().get(s); + Assert.assertEquals("1", workflowStepContextState.getStepContextId()); + Assert.assertEquals("1", workflowStepContextState.getStepNum()); + Assert.assertEquals(1390066159000L + (i * 1000), workflowStepContextState.getStartTime().getTime()); + Assert.assertEquals(1390066159000L + (i * 1000), workflowStepContextState.getEndTime().getTime()); + Assert.assertEquals(1390066159000L + (i * 1000), workflowStepContextState.getUpdateTime().getTime()); + Assert.assertEquals(RundeckWFExecState.SUCCEEDED, workflowStepContextState.getExecutionState()); + i++; + } + + } + @Test + public void testParseRunning1() { + InputStream input = getClass().getResourceAsStream("execution-state2.xml"); + Document document = ParserHelper.loadDocument(input); + + WorkflowStepState stepState = new WorkflowStepStateParser().parseXmlNode(document.selectSingleNode + ("/result/executionState/steps/step[1]")); + + Assert.assertNotNull(stepState); + Assert.assertEquals(true, stepState.isNodeStep()); + Assert.assertEquals(null, stepState.getSubWorkflow()); + Assert.assertEquals("1", stepState.getStepContextId()); + Assert.assertEquals("1", stepState.getStepNum()); + Assert.assertNotNull(stepState.getNodeStates()); + Assert.assertEquals(1390066061000L, stepState.getStartTime().getTime()); + Assert.assertEquals(1390066066000L, stepState.getEndTime().getTime()); + Assert.assertEquals(1390066061000L, stepState.getUpdateTime().getTime()); + Assert.assertEquals(RundeckWFExecState.SUCCEEDED, stepState.getExecutionState()); + HashSet expectedTargetNodes = new HashSet(Arrays.asList( + "dignan" + )); + + WorkflowStepContextState workflowStepContextState = stepState.getNodeStates().get("dignan"); + Assert.assertEquals("1", workflowStepContextState.getStepContextId()); + Assert.assertEquals("1", workflowStepContextState.getStepNum()); + Assert.assertEquals(1390066061000L, workflowStepContextState.getStartTime().getTime()); + Assert.assertEquals(1390066066000L, workflowStepContextState.getEndTime().getTime()); + Assert.assertEquals(1390066066000L, workflowStepContextState.getUpdateTime().getTime()); + Assert.assertEquals(RundeckWFExecState.SUCCEEDED, workflowStepContextState.getExecutionState()); + + } + @Test + public void testParseRunning2() { + InputStream input = getClass().getResourceAsStream("execution-state2.xml"); + Document document = ParserHelper.loadDocument(input); + + WorkflowStepState stepState = new WorkflowStepStateParser().parseXmlNode(document.selectSingleNode + ("/result/executionState/steps/step[2]")); + + Assert.assertNotNull(stepState); + Assert.assertEquals(false, stepState.isNodeStep()); + Assert.assertNotNull(stepState.getSubWorkflow()); + Assert.assertNull(stepState.getNodeStates()); + Assert.assertEquals("2", stepState.getStepContextId()); + Assert.assertEquals("2",stepState.getStepNum()); + Assert.assertEquals(1390066066000L, stepState.getStartTime().getTime()); + Assert.assertNull(stepState.getEndTime()); + Assert.assertEquals(1390066066000L, stepState.getUpdateTime().getTime()); + Assert.assertEquals(RundeckWFExecState.RUNNING, stepState.getExecutionState()); + + + //sub workflow + WorkflowState subWorkflow = stepState.getSubWorkflow(); + Assert.assertEquals(1,subWorkflow.getSteps().size()); + Assert.assertEquals(1,subWorkflow.getTargetNodes().size()); + + WorkflowStepState stepState1 = subWorkflow.getSteps().get(0); + Assert.assertEquals(true, stepState1.isNodeStep()); + Assert.assertNull(stepState1.getSubWorkflow()); + Assert.assertNotNull(stepState1.getNodeStates()); + Assert.assertEquals("2/1", stepState1.getStepContextId()); + Assert.assertEquals("1", stepState1.getStepNum()); + Assert.assertEquals(1390066067000L, stepState1.getStartTime().getTime()); + Assert.assertNull(stepState1.getEndTime()); + Assert.assertEquals(1390066067000L, stepState1.getUpdateTime().getTime()); + Assert.assertEquals(RundeckWFExecState.RUNNING, stepState1.getExecutionState()); + + } +} diff --git a/src/test/resources/org/rundeck/api/parser/execution-state1.xml b/src/test/resources/org/rundeck/api/parser/execution-state1.xml new file mode 100644 index 0000000..71c47af --- /dev/null +++ b/src/test/resources/org/rundeck/api/parser/execution-state1.xml @@ -0,0 +1,81 @@ + + + 149 + dignan + SUCCEEDED + true + + + + + + + + + + + + + + + 1 + 2014-01-18T17:29:20Z + 2014-01-18T17:29:19Z + 2014-01-18T17:29:20Z + + + true + SUCCEEDED + 2014-01-18T17:29:19Z + 2014-01-18T17:29:20Z + 2014-01-18T17:29:20Z + + + SUCCEEDED + 2014-01-18T17:29:19Z + 2014-01-18T17:29:19Z + 2014-01-18T17:29:19Z + + + SUCCEEDED + 2014-01-18T17:29:20Z + 2014-01-18T17:29:20Z + 2014-01-18T17:29:20Z + + + SUCCEEDED + 2014-01-18T17:29:21Z + 2014-01-18T17:29:21Z + 2014-01-18T17:29:21Z + + + + + + + + + 1 + SUCCEEDED + + + + + + + 1 + SUCCEEDED + + + + + + + 1 + SUCCEEDED + + + + + + diff --git a/src/test/resources/org/rundeck/api/parser/execution-state2.xml b/src/test/resources/org/rundeck/api/parser/execution-state2.xml new file mode 100644 index 0000000..f867aba --- /dev/null +++ b/src/test/resources/org/rundeck/api/parser/execution-state2.xml @@ -0,0 +1,96 @@ + + + 148 + dignan + RUNNING + false + + + + + + + + + + + 2 + 2014-01-18T17:27:47Z + 2014-01-18T17:27:41Z + + + + true + SUCCEEDED + 2014-01-18T17:27:41Z + 2014-01-18T17:27:41Z + 2014-01-18T17:27:46Z + + + SUCCEEDED + 2014-01-18T17:27:41Z + 2014-01-18T17:27:46Z + 2014-01-18T17:27:46Z + + + + + true + + RUNNING + false + + + + + + + + + + + 1 + 2014-01-18T17:27:47Z + 2014-01-18T17:27:47Z + + + + true + RUNNING + 2014-01-18T17:27:47Z + 2014-01-18T17:27:47Z + + + + RUNNING + 2014-01-18T17:27:47Z + 2014-01-18T17:27:47Z + + + + + + + false + RUNNING + 2014-01-18T17:27:46Z + 2014-01-18T17:27:46Z + + + + + + + + 1 + SUCCEEDED + + + 2/1 + RUNNING + + + + + +