UX-396# durationInMillis added to node details object.

This commit is contained in:
Vivek Pandey 2016-05-06 15:53:48 -07:00
parent a3a1d4f8c7
commit 2e148cf352
7 changed files with 813 additions and 737 deletions

View File

@ -38,6 +38,19 @@
<version>2.2-beta-1</version>
</dependency>
<dependency>
<groupId>org.jenkins-ci.plugins.workflow</groupId>
<artifactId>workflow-cps</artifactId>
<version>2.1</version>
</dependency>
<dependency>
<groupId>org.jenkins-ci.plugins.workflow</groupId>
<artifactId>workflow-api</artifactId>
<version>2.0</version>
</dependency>
<dependency>
<groupId>org.jenkins-ci.plugins.workflow</groupId>
<artifactId>workflow-step-api</artifactId>
@ -72,7 +85,7 @@
<artifactId>github-branch-source</artifactId>
<version>1.6</version>
</dependency>
<!-- Test plugins -->
<!-- Random test failing bug due to an assertion in pipeline plugin. See https://github.com/jenkinsci/pipeline-stage-step-plugin/pull/1 -->
<dependency>
@ -94,12 +107,6 @@
<version>2.0</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.jenkins-ci.plugins.workflow</groupId>
<artifactId>workflow-cps</artifactId>
<version>2.1</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.jenkins-ci.plugins.workflow</groupId>
<artifactId>workflow-scm-step</artifactId>

View File

@ -1,19 +1,24 @@
package io.jenkins.blueocean.service.embedded.rest;
import com.google.common.collect.ImmutableList;
import com.google.common.collect.Iterables;
import io.jenkins.blueocean.rest.model.BluePipelineNode;
import io.jenkins.blueocean.rest.model.BlueRun;
import org.jenkinsci.plugins.workflow.actions.NotExecutedNodeAction;
import org.jenkinsci.plugins.workflow.actions.TimingAction;
import org.jenkinsci.plugins.workflow.cps.nodes.StepEndNode;
import org.jenkinsci.plugins.workflow.graph.FlowGraphWalker;
import org.jenkinsci.plugins.workflow.graph.FlowNode;
import org.jenkinsci.plugins.workflow.job.WorkflowRun;
import org.jenkinsci.plugins.workflow.support.visualization.table.FlowGraphTable;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Comparator;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
import java.util.TreeSet;
/**
* Filters {@link FlowGraphTable} to BlueOcean specific model representing DAG like graph objects
@ -32,15 +37,27 @@ public class PipelineNodeGraphBuilder {
public PipelineNodeGraphBuilder(WorkflowRun run) {
this.run = run;
FlowGraphTable nodeGraphTable = new FlowGraphTable(run.getExecution());
nodeGraphTable.build();
List<FlowNode> nodes = new ArrayList<>();
for (FlowGraphTable.Row r : nodeGraphTable.getRows()) {
nodes.add(r.getNode());
}
this.sortedNodes = Collections.unmodifiableList(nodes);
TreeSet<FlowNode> nodeTreeSet = new TreeSet<>(new Comparator<FlowNode>() {
@Override
public int compare(FlowNode node1, FlowNode node2) {
return Integer.compare(parseIota(node1), parseIota(node2));
}
private int parseIota(FlowNode node) {
try {
return Integer.parseInt(node.getId());
} catch (NumberFormatException e) {
return 0;
}
}
});
Iterables.addAll(nodeTreeSet, new FlowGraphWalker(run.getExecution()));
this.sortedNodes = Collections.unmodifiableList(new ArrayList<>(nodeTreeSet));
// dumpNodes();
build();
//dumpNodes();
}
private void build(){
@ -60,8 +77,6 @@ public class PipelineNodeGraphBuilder {
for (FlowNode n : branches) {
addChild(n, node);
}
nodeStatusMap.put(previousBranch,
new PipelineNodeGraphBuilder.NodeRunStatus(sortedNodes.get(count - 1)));
previousBranch = null;
} else if (previousStage != null) {
//node before this stage is the last node before previousStage stage
@ -76,8 +91,9 @@ public class PipelineNodeGraphBuilder {
} else if (PipelineNodeUtil.isParallelBranch(node)) { //branch
addChild(node, null);
addChild(previousStage, node);
if (previousBranch != null) {
nodeStatusMap.put(previousBranch, new PipelineNodeGraphBuilder.NodeRunStatus(sortedNodes.get(count - 1)));
FlowNode endNode = getEndParallelNode(node);
if (endNode != null) {
nodeStatusMap.put(node, new PipelineNodeGraphBuilder.NodeRunStatus(endNode));
}
previousBranch = node;
}
@ -85,12 +101,24 @@ public class PipelineNodeGraphBuilder {
}
int size = parentToChildrenMap.keySet().size();
if (size > 0) {
PipelineNodeGraphBuilder.NodeRunStatus runStatus = new PipelineNodeGraphBuilder.NodeRunStatus(sortedNodes.get(sortedNodes.size() - 1));
FlowNode lastNode = getLastNode();
PipelineNodeGraphBuilder.NodeRunStatus runStatus = PipelineNodeUtil.getStatus(run);
FlowNode lastNode = getLastStageNode();
nodeStatusMap.put(lastNode, runStatus);
}
}
private FlowNode getEndParallelNode(FlowNode startNode){
for(int i = sortedNodes.size() - 1; i >=0; i--){
FlowNode n = sortedNodes.get(i);
if(isEnd(n)){
StepEndNode endNode = (StepEndNode) n;
if(endNode.getStartNode().equals(startNode))
return endNode;
}
}
return null;
}
/**
* Create a union of current pipeline nodes with the one from future. Term future indicates that
* this list of nodes are either in the middle of processing or failed somewhere in middle and we are
@ -155,11 +183,60 @@ public class PipelineNodeGraphBuilder {
} else if (status == null) {
status = getEffectiveBranchStatus(n);
}
nodes.add(new PipelineNodeImpl(run, n, status, parentToChildrenMap.get(n)));
nodes.add(new PipelineNodeImpl(run, n, status, this));
}
return nodes;
}
public List<FlowNode> getChildren(FlowNode parent){
return parentToChildrenMap.get(parent);
}
public Long getDurationInMillis(FlowNode node){
long startTime = TimingAction.getStartTime(node);
if( startTime == 0){
return null;
}
/**
* For Stage node:
*
* Find next stage node
* duration = nextStageNodeStartTime - thisStageNode.startTime
*
* For Parallel node:
*
* Find the endNode of the parallel branch
* duration = endNode.startTime - thisNode.startTime
*
* If this happens to be the last stage or parallel node in the pipeline
* duration = pipelineEndTime - thisStageNode.startTime
*
*/
if(PipelineNodeUtil.isStage(node)){
boolean lookForNextStage = false;
for(FlowNode n: parentToChildrenMap.keySet()){
if(n.equals(node)){
lookForNextStage = true;
continue;
}
if(lookForNextStage && PipelineNodeUtil.isStage(n)){ //we got the next stage
return TimingAction.getStartTime(n) - startTime;
}
}
}else if(PipelineNodeUtil.isParallelBranch(node)){
FlowNode endNode = getEndParallelNode(node);
if(endNode != null){
return TimingAction.getStartTime(endNode) - startTime;
}
}
return run.getExecution().isComplete()
? (run.getDuration() + run.getStartTimeInMillis()) - startTime
: System.currentTimeMillis() - startTime;
}
private boolean isEnd(FlowNode n){
return n instanceof StepEndNode;
}
private FlowNode getLastNode() {
if (parentToChildrenMap.keySet().isEmpty()) {
return null;
@ -262,7 +339,7 @@ public class PipelineNodeGraphBuilder {
public void dumpNodes() {
for (FlowNode n : sortedNodes) {
System.out.println(String.format("id: %s, name: %s, startTime: %s", n.getId(), n.getDisplayName(), TimingAction.getStartTime(n)));
System.out.println(String.format("id: %s, name: %s, startTime: %s, type: %s", n.getId(), n.getDisplayName(), TimingAction.getStartTime(n), n.getClass()));
}
}

View File

@ -22,19 +22,26 @@ import java.util.List;
* @see FlowNode
*/
public class PipelineNodeImpl extends BluePipelineNode {
/*package*/ final FlowNode node;
private final FlowNode node;
private final List<FlowNode> children;
private final List<Edge> edges;
private final WorkflowRun run;
private final Long durationInMillis;
private final PipelineNodeGraphBuilder.NodeRunStatus status;
public PipelineNodeImpl(WorkflowRun run, final FlowNode node, PipelineNodeGraphBuilder.NodeRunStatus status, List<FlowNode> children) {
public PipelineNodeImpl(WorkflowRun run, final FlowNode node, PipelineNodeGraphBuilder.NodeRunStatus status, PipelineNodeGraphBuilder nodeGraphBuilder) {
this.run = run;
this.node = node;
this.children = children;
this.children = nodeGraphBuilder.getChildren(node);
this.edges = buildEdges();
this.status = status;
if(getStateObj() == BlueRun.BlueRunState.FINISHED){
this.durationInMillis = nodeGraphBuilder.getDurationInMillis(node);
}else if(getStateObj() == BlueRun.BlueRunState.RUNNING){
this.durationInMillis = System.currentTimeMillis()-TimingAction.getStartTime(node);
}else{
this.durationInMillis = null;
}
}
@Override
@ -77,6 +84,11 @@ public class PipelineNodeImpl extends BluePipelineNode {
return edges;
}
@Override
public Long getDurationInMillis() {
return durationInMillis;
}
@Override
public Object getLog() {
FlowGraphTable nodeGraphTable = new FlowGraphTable(run.getExecution());
@ -140,21 +152,6 @@ public class PipelineNodeImpl extends BluePipelineNode {
public String getId() {
return edge.getId();
}
@Override
public long getDurationInMillis() {
if(node instanceof PipelineNodeGraphBuilder.InactiveFlowNodeWrapper){
return -1;
}
TimingAction t = node.getAction(TimingAction.class);
TimingAction c = edge.getAction(TimingAction.class);
if(t!= null){
if(c != null){
return c.getStartTime() - t.getStartTime();
}
}
return -1;
}
}
private List<Edge> buildEdges(){

View File

@ -13,19 +13,15 @@ import hudson.model.Result;
import hudson.model.Run;
import hudson.tasks.ArtifactArchiver;
import hudson.tasks.Shell;
import io.jenkins.blueocean.service.embedded.rest.PipelineNodeUtil;
import org.jenkinsci.plugins.workflow.cps.CpsFlowDefinition;
import org.jenkinsci.plugins.workflow.graph.FlowNode;
import org.jenkinsci.plugins.workflow.job.WorkflowJob;
import org.jenkinsci.plugins.workflow.job.WorkflowRun;
import org.jenkinsci.plugins.workflow.support.visualization.table.FlowGraphTable;
import org.junit.Assert;
import org.junit.Test;
import org.jvnet.hudson.test.MockFolder;
import org.jvnet.hudson.test.TestBuilder;
import java.io.IOException;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.Stack;
@ -236,517 +232,6 @@ public class PipelineApiTest extends BaseTest {
validateRun(b1, resp);
}
@Test
public void nodesTest() throws Exception {
WorkflowJob job1 = j.jenkins.createProject(WorkflowJob.class, "pipeline1");
job1.setDefinition(new CpsFlowDefinition("stage \"Build\"\n" +
" node {\n" +
" sh \"echo here\"\n" +
" }\n" +
"\n" +
"stage \"Test\"\n" +
" parallel (\n" +
" \"Firefox\" : {\n" +
" node {\n" +
" sh \"echo ffox\"\n" +
" }\n" +
" },\n" +
" \"Chrome\" : {\n" +
" node {\n" +
" sh \"echo chrome\"\n" +
" }\n" +
" }\n" +
" )\n" +
"\n" +
"stage \"CrashyMcgee\"\n" +
" parallel (\n" +
" \"SlowButSuccess\" : {\n" +
" node {\n" +
" echo 'This is time well spent.'\n" +
" }\n" +
" },\n" +
" \"DelayThenFail\" : {\n" +
" node {\n" +
" echo 'Not yet.'\n" +
" }\n" +
" },\n" +
" )\n" +
"\n" +
"\n" +
"stage \"Deploy\"\n" +
" node {\n" +
" sh \"echo deploying\"\n" +
" }"));
WorkflowRun b1 = job1.scheduleBuild2(0).get();
j.assertBuildStatusSuccess(b1);
get("/organizations/jenkins/pipelines/pipeline1/runs/1/nodes/", List.class);
job1.setDefinition(new CpsFlowDefinition("stage \"Build\"\n" +
" node {\n" +
" sh \"echo here\"\n" +
" }\n" +
"\n" +
"stage \"Test\"\n" +
" parallel (\n" +
" \"Firefox\" : {\n" +
" node {\n" +
" sh \"echo ffox\"\n" +
" }\n" +
" },\n" +
" \"Chrome\" : {\n" +
" node {\n" +
" sh \"echo chrome\"\n" +
" }\n" +
" }\n" +
" )\n" +
"\n" +
"stage \"CrashyMcgee\"\n" +
" parallel (\n" +
" \"SlowButSuccess\" : {\n" +
" node {\n" +
" echo 'This is time well spent.'\n" +
" sh 'sleep 3;'\n" +
" }\n" +
" },\n" +
" \"DelayThenFail\" : {\n" +
" node {\n" +
" echo 'Fail soon.'\n" +
" echo 'KABOOM!'\n" +
" sh '11exit 1'\n" +
" }\n" +
" },\n" +
" )\n" +
"\n" +
"\n" +
"stage \"Deploy\"\n" +
" node {\n" +
" sh \"echo deploying\"\n" +
" }"));
WorkflowRun b2 = job1.scheduleBuild2(0).get();
j.assertBuildStatus(Result.FAILURE,b2);
List<Map> resp = get("/organizations/jenkins/pipelines/pipeline1/runs/2/nodes/", List.class);
Assert.assertEquals(resp.size(), 8);
for(int i=0; i< resp.size();i++){
Map rn = resp.get(i);
List<Map> edges = (List<Map>) rn.get("edges");
if(rn.get("displayName").equals("Test")){
Assert.assertEquals(2, edges.size());
Assert.assertEquals(rn.get("result"), "SUCCESS");
Assert.assertEquals(rn.get("state"), "FINISHED");
}else if(rn.get("displayName").equals("Firefox")){
Assert.assertEquals(1, edges.size());
Assert.assertEquals(rn.get("result"), "SUCCESS");
Assert.assertEquals(rn.get("state"), "FINISHED");
}else if(rn.get("displayName").equals("Chrome")){
Assert.assertEquals(1, edges.size());
Assert.assertEquals(rn.get("result"), "SUCCESS");
Assert.assertEquals(rn.get("state"), "FINISHED");
}else if(rn.get("displayName").equals("CrashyMcgee")){
Assert.assertEquals(2, edges.size());
Assert.assertEquals(rn.get("result"), "FAILURE");
Assert.assertEquals(rn.get("state"), "FINISHED");
}else if(rn.get("displayName").equals("SlowButSuccess")){
Assert.assertEquals(1, edges.size());
Assert.assertEquals(rn.get("result"), "SUCCESS");
Assert.assertEquals(rn.get("state"), "FINISHED");
}else if(rn.get("displayName").equals("DelayThenFail")){
Assert.assertEquals(1, edges.size());
Assert.assertEquals(rn.get("result"), "FAILURE");
Assert.assertEquals(rn.get("state"), "FINISHED");
}else if(rn.get("displayName").equals("build")){
Assert.assertEquals(1, edges.size());
Assert.assertEquals(rn.get("result"), "SUCCESS");
Assert.assertEquals(rn.get("state"), "FINISHED");
}else if(rn.get("displayName").equals("Deploy")){
Assert.assertEquals(0, edges.size());
Assert.assertNull(rn.get("result"));
Assert.assertNull(rn.get("state"));
}
}
}
@Test
public void getPipelineJobRunNodesTest() throws Exception {
WorkflowJob job1 = j.jenkins.createProject(WorkflowJob.class, "pipeline1");
job1.setDefinition(new CpsFlowDefinition("stage 'build'\n" +
"node{\n" +
" echo \"Building...\"\n" +
"}\n" +
"\n" +
"stage 'test'\n" +
"parallel 'unit':{\n" +
" node{\n" +
" echo \"Unit testing...\"\n" +
" }\n" +
"},'integration':{\n" +
" node{\n" +
" echo \"Integration testing...\"\n" +
" }\n" +
"}, 'ui':{\n" +
" node{\n" +
" echo \"UI testing...\"\n" +
" }\n" +
"}\n" +
"\n" +
"stage 'deploy'\n" +
"node{\n" +
" echo \"Deploying\"\n" +
"}" +
"\n" +
"stage 'deployToProd'\n" +
"node{\n" +
" echo \"Deploying to production\"\n" +
"}"
));
WorkflowRun b1 = job1.scheduleBuild2(0).get();
j.assertBuildStatusSuccess(b1);
FlowGraphTable nodeGraphTable = new FlowGraphTable(b1.getExecution());
nodeGraphTable.build();
List<FlowNode> nodes = getStages(nodeGraphTable);
List<FlowNode> parallelNodes = getParallelNodes(nodeGraphTable);
Assert.assertEquals(7, nodes.size());
Assert.assertEquals(3, parallelNodes.size());
List<Map> resp = get("/organizations/jenkins/pipelines/pipeline1/runs/1/nodes/", List.class);
Assert.assertEquals(nodes.size(), resp.size());
for(int i=0; i< nodes.size();i++){
FlowNode n = nodes.get(i);
Map rn = resp.get(i);
Assert.assertEquals(n.getId(), rn.get("id"));
Assert.assertEquals(getNodeName(n), rn.get("displayName"));
Assert.assertEquals("SUCCESS", rn.get("result"));
List<Map> edges = (List<Map>) rn.get("edges");
if(n.getDisplayName().equals("test")){
Assert.assertEquals(parallelNodes.size(), edges.size());
Assert.assertEquals(edges.get(i).get("id"), parallelNodes.get(i).getId());
}else if(n.getDisplayName().equals("build")){
Assert.assertEquals(1, edges.size());
Assert.assertEquals(edges.get(i).get("id"), nodes.get(i+1).getId());
}else if(n.getDisplayName().equals("deploy")){
Assert.assertEquals(1, edges.size());
}else if(n.getDisplayName().equals("deployToProd")){
Assert.assertEquals(0, edges.size());
}else{
Assert.assertEquals(1, edges.size());
Assert.assertEquals(edges.get(0).get("id"), nodes.get(nodes.size() - 2).getId());
}
}
}
@Test
public void getPipelineJobRunNodesTestWithFuture() throws Exception {
WorkflowJob job1 = j.jenkins.createProject(WorkflowJob.class, "pipeline1");
job1.setDefinition(new CpsFlowDefinition("stage 'build'\n" +
"node{\n" +
" echo \"Building...\"\n" +
"}\n" +
"\n" +
"stage 'test'\n" +
"parallel 'unit':{\n" +
" node{\n" +
" echo \"Unit testing...\"\n" +
" }\n" +
"},'integration':{\n" +
" node{\n" +
" echo \"Integration testing...\"\n" +
" }\n" +
"}, 'ui':{\n" +
" node{\n" +
" echo \"UI testing...\"\n" +
" }\n" +
"}\n" +
"\n" +
"stage 'deploy'\n" +
"node{\n" +
" echo \"Deploying\"\n" +
"}" +
"\n" +
"stage 'deployToProd'\n" +
"node{\n" +
" echo \"Deploying to production\"\n" +
"}"
));
WorkflowRun b1 = job1.scheduleBuild2(0).get();
j.assertBuildStatusSuccess(b1);
FlowGraphTable nodeGraphTable = new FlowGraphTable(b1.getExecution());
nodeGraphTable.build();
List<FlowNode> nodes = getStages(nodeGraphTable);
List<FlowNode> parallelNodes = getParallelNodes(nodeGraphTable);
Assert.assertEquals(7, nodes.size());
Assert.assertEquals(3, parallelNodes.size());
List<Map> resp = get("/organizations/jenkins/pipelines/pipeline1/runs/1/nodes/", List.class);
Assert.assertEquals(nodes.size(), resp.size());
for(int i=0; i< nodes.size();i++){
FlowNode n = nodes.get(i);
Map rn = resp.get(i);
Assert.assertEquals(n.getId(), rn.get("id"));
Assert.assertEquals(getNodeName(n), rn.get("displayName"));
Assert.assertEquals("SUCCESS", rn.get("result"));
List<Map> edges = (List<Map>) rn.get("edges");
if(n.getDisplayName().equals("test")){
Assert.assertEquals(parallelNodes.size(), edges.size());
Assert.assertEquals(edges.get(i).get("id"), parallelNodes.get(i).getId());
}else if(n.getDisplayName().equals("build")){
Assert.assertEquals(1, edges.size());
Assert.assertEquals(edges.get(i).get("id"), nodes.get(i+1).getId());
}else if(n.getDisplayName().equals("deploy")){
Assert.assertEquals(1, edges.size());
}else if(n.getDisplayName().equals("deployToProd")){
Assert.assertEquals(0, edges.size());
}else{
Assert.assertEquals(1, edges.size());
Assert.assertEquals(edges.get(0).get("id"), nodes.get(nodes.size() - 2).getId());
}
}
job1.setDefinition(new CpsFlowDefinition("stage 'build'\n" +
"node{\n" +
" echo \"Building...\"\n" +
"}\n" +
"\n" +
"stage 'test'\n" +
"parallel 'unit':{\n" +
" node{\n" +
" echo \"Unit testing...\"\n" +
" sh \"`fail-the-build`\"\n" + //fail the build intentionally
" }\n" +
"},'integration':{\n" +
" node{\n" +
" echo \"Integration testing...\"\n" +
" }\n" +
"}, 'ui':{\n" +
" node{\n" +
" echo \"UI testing...\"\n" +
" }\n" +
"}\n" +
"\n" +
"stage 'deploy'\n" +
"node{\n" +
" echo \"Deploying\"\n" +
"}" +
"\n" +
"stage 'deployToProd'\n" +
"node{\n" +
" echo \"Deploying to production\"\n" +
"}"
));
b1 = job1.scheduleBuild2(0).get();
j.assertBuildStatus(Result.FAILURE,b1);
resp = get(String.format("/organizations/jenkins/pipelines/pipeline1/runs/%s/nodes/",b1.getId()), List.class);
Assert.assertEquals(nodes.size(), resp.size());
for(int i=0; i< nodes.size();i++){
FlowNode n = nodes.get(i);
Map rn = resp.get(i);
Assert.assertEquals(n.getId(), rn.get("id"));
Assert.assertEquals(getNodeName(n), rn.get("displayName"));
List<Map> edges = (List<Map>) rn.get("edges");
if(n.getDisplayName().equals("build")){
Assert.assertEquals(1, edges.size());
Assert.assertEquals(edges.get(i).get("id"), nodes.get(i+1).getId());
Assert.assertEquals("SUCCESS", rn.get("result"));
Assert.assertEquals("FINISHED", rn.get("state"));
}else if (n.getDisplayName().equals("test")){
Assert.assertEquals(parallelNodes.size(), edges.size());
Assert.assertEquals(edges.get(i).get("id"), parallelNodes.get(i).getId());
Assert.assertEquals("FAILURE", rn.get("result"));
Assert.assertEquals("FINISHED", rn.get("state"));
}else if(PipelineNodeUtil.getDisplayName(n).equals("unit")){
Assert.assertEquals(1, edges.size());
Assert.assertEquals(edges.get(0).get("id"), nodes.get(nodes.size() - 2).getId());
Assert.assertEquals(edges.get(0).get("durationInMillis"), -1);
Assert.assertEquals("FAILURE", rn.get("result"));
Assert.assertEquals("FINISHED", rn.get("state"));
}else if(n.getDisplayName().equals("deploy")){
Assert.assertEquals(1, edges.size());
Assert.assertNull(rn.get("result"));
Assert.assertNull(rn.get("state"));
Assert.assertNull(rn.get("startTime"));
Assert.assertEquals(1, edges.size());
Assert.assertEquals(edges.get(0).get("id"), nodes.get(nodes.size() - 1).getId());
Assert.assertEquals(edges.get(0).get("durationInMillis"), -1);
}else if(n.getDisplayName().equals("deployToProd")){
Assert.assertEquals(0, edges.size());
Assert.assertNull(rn.get("result"));
Assert.assertNull(rn.get("state"));
Assert.assertNull(rn.get("startTime"));
Assert.assertEquals(0, edges.size());
}else{
Assert.assertEquals(1, edges.size());
Assert.assertEquals(edges.get(0).get("id"), nodes.get(nodes.size() - 2).getId());
Assert.assertEquals(edges.get(0).get("durationInMillis"), -1);
Assert.assertEquals("SUCCESS", rn.get("result"));
Assert.assertEquals("FINISHED", rn.get("state"));
}
}
}
@Test
public void getPipelineJobRunNodesWithFailureTest() throws Exception {
WorkflowJob job1 = j.jenkins.createProject(WorkflowJob.class, "pipeline1");
job1.setDefinition(new CpsFlowDefinition("stage 'build'\n" +
"node{\n" +
" echo \"Building...\"\n" +
"}\n" +
"\n" +
"stage 'test'\n" +
"parallel 'unit':{\n" +
" node{\n" +
" echo \"Unit testing...\"\n" +
" sh \"`fail-the-build`\"\n" + //fail the build intentionally
" }\n" +
"},'integration':{\n" +
" node{\n" +
" echo \"Integration testing...\"\n" +
" }\n" +
"}, 'ui':{\n" +
" node{\n" +
" echo \"UI testing...\"\n" +
" }\n" +
"}\n" +
"\n" +
"stage 'deploy'\n" +
"node{\n" +
" echo \"Deploying\"\n" +
"}"
));
WorkflowRun b1 = job1.scheduleBuild2(0).get();
j.assertBuildStatus(Result.FAILURE, b1);
FlowGraphTable nodeGraphTable = new FlowGraphTable(b1.getExecution());
nodeGraphTable.build();
List<FlowNode> nodes = getStages(nodeGraphTable);
List<FlowNode> parallelNodes = getParallelNodes(nodeGraphTable);
Assert.assertEquals(5, nodes.size());
Assert.assertEquals(3, parallelNodes.size());
List<Map> resp = get("/organizations/jenkins/pipelines/pipeline1/runs/1/nodes/", List.class);
Assert.assertEquals(nodes.size(), resp.size());
for(int i=0; i< nodes.size();i++){
FlowNode n = nodes.get(i);
Map rn = resp.get(i);
Assert.assertEquals(n.getId(), rn.get("id"));
Assert.assertEquals(getNodeName(n), rn.get("displayName"));
List<Map> edges = (List<Map>) rn.get("edges");
if(n.getDisplayName().equals("test")){
Assert.assertEquals(parallelNodes.size(), edges.size());
Assert.assertEquals(edges.get(i).get("id"), parallelNodes.get(i).getId());
Assert.assertEquals("FAILURE", rn.get("result"));
}else if(n.getDisplayName().equals("build")){
Assert.assertEquals(1, edges.size());
Assert.assertEquals(edges.get(i).get("id"), nodes.get(i+1).getId());
Assert.assertEquals("SUCCESS", rn.get("result"));
}else if(n.getDisplayName().equals("Branch: unit")){
Assert.assertEquals(0, edges.size());
Assert.assertEquals("FAILURE", rn.get("result"));
}else{
Assert.assertEquals(0, edges.size());
Assert.assertEquals("SUCCESS", rn.get("result"));
}
}
}
@Test
public void getPipelineJobRunNodeTest() throws Exception {
WorkflowJob job1 = j.jenkins.createProject(WorkflowJob.class, "pipeline1");
job1.setDefinition(new CpsFlowDefinition("stage 'build'\n" +
"node{\n" +
" echo \"Building...\"\n" +
"}\n" +
"\n" +
"stage 'test'\n" +
"parallel 'unit':{\n" +
" node{\n" +
" echo \"Unit testing...\"\n" +
" }\n" +
"},'integration':{\n" +
" node{\n" +
" echo \"Integration testing...\"\n" +
" }\n" +
"}, 'ui':{\n" +
" node{\n" +
" echo \"UI testing...\"\n" +
" }\n" +
"}\n" +
"\n" +
"stage 'deploy'\n" +
"node{\n" +
" echo \"Deploying\"\n" +
"}"));
WorkflowRun b1 = job1.scheduleBuild2(0).get();
j.assertBuildStatusSuccess(b1);
FlowGraphTable nodeGraphTable = new FlowGraphTable(b1.getExecution());
nodeGraphTable.build();
List<FlowNode> nodes = getStages(nodeGraphTable);
List<FlowNode> parallelNodes = getParallelNodes(nodeGraphTable);
Assert.assertEquals(6, nodes.size());
Assert.assertEquals(3, parallelNodes.size());
// get all nodes for pipeline1
List<Map> resp = get("/organizations/jenkins/pipelines/pipeline1/runs/1/nodes/", List.class);
Assert.assertEquals(nodes.size(), resp.size());
//Get a node detail
FlowNode n = nodes.get(0);
Map node = get("/organizations/jenkins/pipelines/pipeline1/runs/1/nodes/"+n.getId());
List<Map> edges = (List<Map>) node.get("edges");
Assert.assertEquals(n.getId(), node.get("id"));
Assert.assertEquals(getNodeName(n), node.get("displayName"));
Assert.assertEquals("SUCCESS", node.get("result"));
Assert.assertEquals(1, edges.size());
Assert.assertEquals(nodes.get(1).getId(), edges.get(0).get("id"));
//Get a parllel node detail
node = get("/organizations/jenkins/pipelines/pipeline1/runs/1/nodes/"+parallelNodes.get(0).getId());
n = parallelNodes.get(0);
edges = (List<Map>) node.get("edges");
Assert.assertEquals(n.getId(), node.get("id"));
Assert.assertEquals(getNodeName(n), node.get("displayName"));
Assert.assertEquals("SUCCESS", node.get("result"));
Assert.assertEquals(1, edges.size());
Assert.assertEquals(nodes.get(nodes.size()-1).getId(), edges.get(0).get("id"));
}
@Test
public void getPipelineJobAbortTest() throws Exception {
WorkflowJob job1 = j.jenkins.createProject(WorkflowJob.class, "pipeline1");
@ -774,61 +259,6 @@ public class PipelineApiTest extends BaseTest {
validateRun(b1, r);
}
@Test
public void getPipelineJobRunNodeLogTest() throws Exception {
WorkflowJob job1 = j.jenkins.createProject(WorkflowJob.class, "pipeline1");
job1.setDefinition(new CpsFlowDefinition("stage 'build'\n" +
"node{\n" +
" echo \"Building...\"\n" +
"}\n" +
"\n" +
"stage 'test'\n" +
"parallel 'unit':{\n" +
" node{\n" +
" echo \"Unit testing...\"\n" +
" }\n" +
"},'integration':{\n" +
" node{\n" +
" echo \"Integration testing...\"\n" +
" }\n" +
"}, 'ui':{\n" +
" node{\n" +
" echo \"UI testing...\"\n" +
" }\n" +
"}\n" +
"\n" +
"stage 'deploy'\n" +
"node{\n" +
" echo \"Deploying\"\n" +
"}"));
WorkflowRun b1 = job1.scheduleBuild2(0).get();
j.assertBuildStatusSuccess(b1);
FlowGraphTable nodeGraphTable = new FlowGraphTable(b1.getExecution());
nodeGraphTable.build();
List<FlowNode> nodes = getStages(nodeGraphTable);
List<FlowNode> parallelNodes = getParallelNodes(nodeGraphTable);
Assert.assertEquals(6, nodes.size());
Assert.assertEquals(3, parallelNodes.size());
String output = get("/organizations/jenkins/pipelines/pipeline1/runs/1/log", String.class);
Assert.assertNotNull(output);
System.out.println(output);
output = get("/organizations/jenkins/pipelines/pipeline1/runs/1/nodes/"+nodes.get(0).getId()+"/log", String.class);
Assert.assertNotNull(output);
System.out.println(output);
output = get("/organizations/jenkins/pipelines/pipeline1/runs/1/nodes/"+parallelNodes.get(0).getId()+"/log", String.class);
Assert.assertNotNull(output);
System.out.println(output);
}
@Test
public void getPipelineJobRunsTest() throws Exception {
WorkflowJob job1 = j.jenkins.createProject(WorkflowJob.class, "pipeline1");
@ -929,28 +359,6 @@ public class PipelineApiTest extends BaseTest {
}
}
private List<FlowNode> getStages(FlowGraphTable nodeGraphTable){
List<FlowNode> nodes = new ArrayList<>();
for(FlowGraphTable.Row row: nodeGraphTable.getRows()){
if(PipelineNodeUtil.isStage(row.getNode()) ||
PipelineNodeUtil.isParallelBranch(row.getNode())){
nodes.add(row.getNode());
}
}
return nodes;
}
private List<FlowNode> getParallelNodes(FlowGraphTable nodeGraphTable){
List<FlowNode> parallelNodes = new ArrayList<>();
for(FlowGraphTable.Row row: nodeGraphTable.getRows()){
if(PipelineNodeUtil.isParallelBranch(row.getNode())){
parallelNodes.add(row.getNode());
}
}
return parallelNodes;
}
@Test
public void testArtifactsRunApi() throws Exception {
FreeStyleProject p = j.createFreeStyleProject("pipeline1");

View File

@ -0,0 +1,606 @@
package io.jenkins.blueocean.service.embedded;
import hudson.model.Result;
import io.jenkins.blueocean.service.embedded.rest.PipelineNodeUtil;
import org.jenkinsci.plugins.workflow.cps.CpsFlowDefinition;
import org.jenkinsci.plugins.workflow.graph.FlowNode;
import org.jenkinsci.plugins.workflow.job.WorkflowJob;
import org.jenkinsci.plugins.workflow.job.WorkflowRun;
import org.jenkinsci.plugins.workflow.support.visualization.table.FlowGraphTable;
import org.junit.Assert;
import org.junit.Test;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
/**
* @author Vivek Pandey
*/
public class PipelineNodeTest extends BaseTest {
@Test
public void nodesTest() throws Exception {
WorkflowJob job1 = j.jenkins.createProject(WorkflowJob.class, "pipeline1");
job1.setDefinition(new CpsFlowDefinition("stage \"Build\"\n" +
" node {\n" +
" sh \"echo here\"\n" +
" }\n" +
"\n" +
"stage \"Test\"\n" +
" parallel (\n" +
" \"Firefox\" : {\n" +
" node {\n" +
" sh \"echo ffox\"\n" +
" }\n" +
" },\n" +
" \"Chrome\" : {\n" +
" node {\n" +
" sh \"echo chrome\"\n" +
" }\n" +
" }\n" +
" )\n" +
"\n" +
"stage \"CrashyMcgee\"\n" +
" parallel (\n" +
" \"SlowButSuccess\" : {\n" +
" node {\n" +
" echo 'This is time well spent.'\n" +
" }\n" +
" },\n" +
" \"DelayThenFail\" : {\n" +
" node {\n" +
" echo 'Not yet.'\n" +
" }\n" +
" }\n" +
" )\n" +
"\n" +
"\n" +
"stage \"Deploy\"\n" +
" node {\n" +
" sh \"echo deploying\"\n" +
" }"));
WorkflowRun b1 = job1.scheduleBuild2(0).get();
j.assertBuildStatusSuccess(b1);
get("/organizations/jenkins/pipelines/pipeline1/runs/1/nodes/", List.class);
job1.setDefinition(new CpsFlowDefinition("stage \"Build\"\n" +
" node {\n" +
" sh \"echo here\"\n" +
" }\n" +
"\n" +
"stage \"Test\"\n" +
" parallel (\n" +
" \"Firefox\" : {\n" +
" node {\n" +
" sh \"echo ffox\"\n" +
" }\n" +
" },\n" +
" \"Chrome\" : {\n" +
" node {\n" +
" sh \"echo chrome\"\n" +
" }\n" +
" }\n" +
" )\n" +
"\n" +
"stage \"CrashyMcgee\"\n" +
" parallel (\n" +
" \"SlowButSuccess\" : {\n" +
" node {\n" +
" echo 'This is time well spent.'\n" +
" sh 'sleep 3;'\n" +
" }\n" +
" },\n" +
" \"DelayThenFail\" : {\n" +
" node {\n" +
" echo 'Fail soon.'\n" +
" echo 'KABOOM!'\n" +
" sh '11exit 1'\n" +
" }\n" +
" }\n" +
" )\n" +
"\n" +
"\n" +
"stage \"Deploy\"\n" +
" node {\n" +
" sh \"echo deploying\"\n" +
" }"));
WorkflowRun b2 = job1.scheduleBuild2(0).get();
j.assertBuildStatus(Result.FAILURE,b2);
List<Map> resp = get("/organizations/jenkins/pipelines/pipeline1/runs/2/nodes/", List.class);
Assert.assertEquals(resp.size(), 8);
for(int i=0; i< resp.size();i++){
Map rn = resp.get(i);
List<Map> edges = (List<Map>) rn.get("edges");
if(rn.get("displayName").equals("Test")){
Assert.assertEquals(2, edges.size());
Assert.assertEquals(rn.get("result"), "SUCCESS");
Assert.assertEquals(rn.get("state"), "FINISHED");
}else if(rn.get("displayName").equals("Firefox")){
Assert.assertEquals(1, edges.size());
Assert.assertEquals(rn.get("result"), "SUCCESS");
Assert.assertEquals(rn.get("state"), "FINISHED");
}else if(rn.get("displayName").equals("Chrome")){
Assert.assertEquals(1, edges.size());
Assert.assertEquals(rn.get("result"), "SUCCESS");
Assert.assertEquals(rn.get("state"), "FINISHED");
}else if(rn.get("displayName").equals("CrashyMcgee")){
Assert.assertEquals(2, edges.size());
Assert.assertEquals(rn.get("result"), "FAILURE");
Assert.assertEquals(rn.get("state"), "FINISHED");
}else if(rn.get("displayName").equals("SlowButSuccess")){
Assert.assertEquals(1, edges.size());
Assert.assertEquals(rn.get("result"), "SUCCESS");
Assert.assertEquals(rn.get("state"), "FINISHED");
}else if(rn.get("displayName").equals("DelayThenFail")){
Assert.assertEquals(1, edges.size());
Assert.assertEquals(rn.get("result"), "FAILURE");
Assert.assertEquals(rn.get("state"), "FINISHED");
}else if(rn.get("displayName").equals("build")){
Assert.assertEquals(1, edges.size());
Assert.assertEquals(rn.get("result"), "SUCCESS");
Assert.assertEquals(rn.get("state"), "FINISHED");
}else if(rn.get("displayName").equals("Deploy")){
Assert.assertEquals(0, edges.size());
Assert.assertNull(rn.get("result"));
Assert.assertNull(rn.get("state"));
}
}
}
@Test
public void getPipelineJobRunNodesTest() throws Exception {
WorkflowJob job1 = j.jenkins.createProject(WorkflowJob.class, "pipeline1");
job1.setDefinition(new CpsFlowDefinition("stage 'build'\n" +
"node{\n" +
" echo \"Building...\"\n" +
"}\n" +
"\n" +
"stage 'test'\n" +
"parallel 'unit':{\n" +
" node{\n" +
" echo \"Unit testing...\"\n" +
" }\n" +
"},'integration':{\n" +
" node{\n" +
" echo \"Integration testing...\"\n" +
" }\n" +
"}, 'ui':{\n" +
" node{\n" +
" echo \"UI testing...\"\n" +
" }\n" +
"}\n" +
"\n" +
"stage 'deploy'\n" +
"node{\n" +
" echo \"Deploying\"\n" +
"}" +
"\n" +
"stage 'deployToProd'\n" +
"node{\n" +
" echo \"Deploying to production\"\n" +
"}"
));
WorkflowRun b1 = job1.scheduleBuild2(0).get();
j.assertBuildStatusSuccess(b1);
FlowGraphTable nodeGraphTable = new FlowGraphTable(b1.getExecution());
nodeGraphTable.build();
List<FlowNode> nodes = getStages(nodeGraphTable);
List<FlowNode> parallelNodes = getParallelNodes(nodeGraphTable);
Assert.assertEquals(7, nodes.size());
Assert.assertEquals(3, parallelNodes.size());
List<Map> resp = get("/organizations/jenkins/pipelines/pipeline1/runs/1/nodes/", List.class);
Assert.assertEquals(nodes.size(), resp.size());
for(int i=0; i< nodes.size();i++){
FlowNode n = nodes.get(i);
Map rn = resp.get(i);
Assert.assertEquals(n.getId(), rn.get("id"));
Assert.assertEquals(getNodeName(n), rn.get("displayName"));
Assert.assertEquals("SUCCESS", rn.get("result"));
List<Map> edges = (List<Map>) rn.get("edges");
Assert.assertTrue((int)rn.get("durationInMillis") > 0);
if(n.getDisplayName().equals("test")){
Assert.assertEquals(parallelNodes.size(), edges.size());
Assert.assertEquals(edges.get(i).get("id"), parallelNodes.get(i).getId());
}else if(n.getDisplayName().equals("build")){
Assert.assertEquals(1, edges.size());
Assert.assertEquals(edges.get(i).get("id"), nodes.get(i+1).getId());
}else if(n.getDisplayName().equals("deploy")){
Assert.assertEquals(1, edges.size());
}else if(n.getDisplayName().equals("deployToProd")){
Assert.assertEquals(0, edges.size());
}else{
Assert.assertEquals(1, edges.size());
Assert.assertEquals(edges.get(0).get("id"), nodes.get(nodes.size() - 2).getId());
}
}
}
@Test
public void getPipelineJobRunNodesTestWithFuture() throws Exception {
WorkflowJob job1 = j.jenkins.createProject(WorkflowJob.class, "pipeline1");
job1.setDefinition(new CpsFlowDefinition("stage 'build'\n" +
"node{\n" +
" echo \"Building...\"\n" +
"}\n" +
"\n" +
"stage 'test'\n" +
"parallel 'unit':{\n" +
" node{\n" +
" echo \"Unit testing...\"\n" +
" }\n" +
"},'integration':{\n" +
" node{\n" +
" echo \"Integration testing...\"\n" +
" }\n" +
"}, 'ui':{\n" +
" node{\n" +
" echo \"UI testing...\"\n" +
" }\n" +
"}\n" +
"\n" +
"stage 'deploy'\n" +
"node{\n" +
" echo \"Deploying\"\n" +
"}" +
"\n" +
"stage 'deployToProd'\n" +
"node{\n" +
" echo \"Deploying to production\"\n" +
"}"
));
WorkflowRun b1 = job1.scheduleBuild2(0).get();
j.assertBuildStatusSuccess(b1);
FlowGraphTable nodeGraphTable = new FlowGraphTable(b1.getExecution());
nodeGraphTable.build();
List<FlowNode> nodes = getStages(nodeGraphTable);
List<FlowNode> parallelNodes = getParallelNodes(nodeGraphTable);
Assert.assertEquals(7, nodes.size());
Assert.assertEquals(3, parallelNodes.size());
List<Map> resp = get("/organizations/jenkins/pipelines/pipeline1/runs/1/nodes/", List.class);
Assert.assertEquals(nodes.size(), resp.size());
for(int i=0; i< nodes.size();i++){
FlowNode n = nodes.get(i);
Map rn = resp.get(i);
Assert.assertEquals(n.getId(), rn.get("id"));
Assert.assertEquals(getNodeName(n), rn.get("displayName"));
Assert.assertEquals("SUCCESS", rn.get("result"));
List<Map> edges = (List<Map>) rn.get("edges");
if(n.getDisplayName().equals("test")){
Assert.assertEquals(parallelNodes.size(), edges.size());
Assert.assertEquals(edges.get(i).get("id"), parallelNodes.get(i).getId());
}else if(n.getDisplayName().equals("build")){
Assert.assertEquals(1, edges.size());
Assert.assertEquals(edges.get(i).get("id"), nodes.get(i+1).getId());
}else if(n.getDisplayName().equals("deploy")){
Assert.assertEquals(1, edges.size());
}else if(n.getDisplayName().equals("deployToProd")){
Assert.assertEquals(0, edges.size());
}else{
Assert.assertEquals(1, edges.size());
Assert.assertEquals(edges.get(0).get("id"), nodes.get(nodes.size() - 2).getId());
}
}
job1.setDefinition(new CpsFlowDefinition("stage 'build'\n" +
"node{\n" +
" echo \"Building...\"\n" +
"}\n" +
"\n" +
"stage 'test'\n" +
"parallel 'unit':{\n" +
" node{\n" +
" echo \"Unit testing...\"\n" +
" sh \"`fail-the-build`\"\n" + //fail the build intentionally
" }\n" +
"},'integration':{\n" +
" node{\n" +
" echo \"Integration testing...\"\n" +
" }\n" +
"}, 'ui':{\n" +
" node{\n" +
" echo \"UI testing...\"\n" +
" }\n" +
"}\n" +
"\n" +
"stage 'deploy'\n" +
"node{\n" +
" echo \"Deploying\"\n" +
"}" +
"\n" +
"stage 'deployToProd'\n" +
"node{\n" +
" echo \"Deploying to production\"\n" +
"}"
));
b1 = job1.scheduleBuild2(0).get();
j.assertBuildStatus(Result.FAILURE,b1);
resp = get(String.format("/organizations/jenkins/pipelines/pipeline1/runs/%s/nodes/",b1.getId()), List.class);
Assert.assertEquals(nodes.size(), resp.size());
for(int i=0; i< nodes.size();i++){
FlowNode n = nodes.get(i);
Map rn = resp.get(i);
Assert.assertEquals(n.getId(), rn.get("id"));
Assert.assertEquals(getNodeName(n), rn.get("displayName"));
List<Map> edges = (List<Map>) rn.get("edges");
if(n.getDisplayName().equals("build")){
Assert.assertEquals(1, edges.size());
Assert.assertEquals(edges.get(i).get("id"), nodes.get(i+1).getId());
Assert.assertEquals("SUCCESS", rn.get("result"));
Assert.assertEquals("FINISHED", rn.get("state"));
}else if (n.getDisplayName().equals("test")){
Assert.assertEquals(parallelNodes.size(), edges.size());
Assert.assertEquals(edges.get(i).get("id"), parallelNodes.get(i).getId());
Assert.assertEquals("FAILURE", rn.get("result"));
Assert.assertEquals("FINISHED", rn.get("state"));
}else if(PipelineNodeUtil.getDisplayName(n).equals("unit")){
Assert.assertEquals(1, edges.size());
Assert.assertEquals(edges.get(0).get("id"), nodes.get(nodes.size() - 2).getId());
Assert.assertEquals("FAILURE", rn.get("result"));
Assert.assertEquals("FINISHED", rn.get("state"));
}else if(n.getDisplayName().equals("deploy")){
Assert.assertEquals(1, edges.size());
Assert.assertNull(rn.get("result"));
Assert.assertNull(rn.get("state"));
Assert.assertNull(rn.get("startTime"));
Assert.assertEquals(1, edges.size());
Assert.assertEquals(edges.get(0).get("id"), nodes.get(nodes.size() - 1).getId());
}else if(n.getDisplayName().equals("deployToProd")){
Assert.assertEquals(0, edges.size());
Assert.assertNull(rn.get("result"));
Assert.assertNull(rn.get("state"));
Assert.assertNull(rn.get("startTime"));
Assert.assertEquals(0, edges.size());
}else{
Assert.assertEquals(1, edges.size());
Assert.assertEquals(edges.get(0).get("id"), nodes.get(nodes.size() - 2).getId());
Assert.assertEquals("SUCCESS", rn.get("result"));
Assert.assertEquals("FINISHED", rn.get("state"));
}
}
}
@Test
public void getPipelineJobRunNodesWithFailureTest() throws Exception {
WorkflowJob job1 = j.jenkins.createProject(WorkflowJob.class, "pipeline1");
job1.setDefinition(new CpsFlowDefinition("stage 'build'\n" +
"node{\n" +
" echo \"Building...\"\n" +
"}\n" +
"\n" +
"stage 'test'\n" +
"parallel 'unit':{\n" +
" node{\n" +
" echo \"Unit testing...\"\n" +
" sh \"`fail-the-build`\"\n" + //fail the build intentionally
" }\n" +
"},'integration':{\n" +
" node{\n" +
" echo \"Integration testing...\"\n" +
" }\n" +
"}, 'ui':{\n" +
" node{\n" +
" echo \"UI testing...\"\n" +
" }\n" +
"}\n" +
"\n" +
"stage 'deploy'\n" +
"node{\n" +
" echo \"Deploying\"\n" +
"}"
));
WorkflowRun b1 = job1.scheduleBuild2(0).get();
j.assertBuildStatus(Result.FAILURE, b1);
FlowGraphTable nodeGraphTable = new FlowGraphTable(b1.getExecution());
nodeGraphTable.build();
List<FlowNode> nodes = getStages(nodeGraphTable);
List<FlowNode> parallelNodes = getParallelNodes(nodeGraphTable);
Assert.assertEquals(5, nodes.size());
Assert.assertEquals(3, parallelNodes.size());
List<Map> resp = get("/organizations/jenkins/pipelines/pipeline1/runs/1/nodes/", List.class);
Assert.assertEquals(nodes.size(), resp.size());
for(int i=0; i< nodes.size();i++){
FlowNode n = nodes.get(i);
Map rn = resp.get(i);
Assert.assertEquals(n.getId(), rn.get("id"));
Assert.assertEquals(getNodeName(n), rn.get("displayName"));
List<Map> edges = (List<Map>) rn.get("edges");
if(n.getDisplayName().equals("test")){
Assert.assertEquals(parallelNodes.size(), edges.size());
Assert.assertEquals(edges.get(i).get("id"), parallelNodes.get(i).getId());
Assert.assertEquals("FAILURE", rn.get("result"));
}else if(n.getDisplayName().equals("build")){
Assert.assertEquals(1, edges.size());
Assert.assertEquals(edges.get(i).get("id"), nodes.get(i+1).getId());
Assert.assertEquals("SUCCESS", rn.get("result"));
}else if(n.getDisplayName().equals("Branch: unit")){
Assert.assertEquals(0, edges.size());
Assert.assertEquals("FAILURE", rn.get("result"));
}else{
Assert.assertEquals(0, edges.size());
Assert.assertEquals("SUCCESS", rn.get("result"));
}
}
}
@Test
public void getPipelineJobRunNodeTest() throws Exception {
WorkflowJob job1 = j.jenkins.createProject(WorkflowJob.class, "pipeline1");
job1.setDefinition(new CpsFlowDefinition("stage 'build'\n" +
"node{\n" +
" echo \"Building...\"\n" +
"}\n" +
"\n" +
"stage 'test'\n" +
"parallel 'unit':{\n" +
" node{\n" +
" echo \"Unit testing...\"\n" +
" }\n" +
"},'integration':{\n" +
" node{\n" +
" echo \"Integration testing...\"\n" +
" }\n" +
"}, 'ui':{\n" +
" node{\n" +
" echo \"UI testing...\"\n" +
" }\n" +
"}\n" +
"\n" +
"stage 'deploy'\n" +
"node{\n" +
" echo \"Deploying\"\n" +
"}"));
WorkflowRun b1 = job1.scheduleBuild2(0).get();
j.assertBuildStatusSuccess(b1);
FlowGraphTable nodeGraphTable = new FlowGraphTable(b1.getExecution());
nodeGraphTable.build();
List<FlowNode> nodes = getStages(nodeGraphTable);
List<FlowNode> parallelNodes = getParallelNodes(nodeGraphTable);
Assert.assertEquals(6, nodes.size());
Assert.assertEquals(3, parallelNodes.size());
// get all nodes for pipeline1
List<Map> resp = get("/organizations/jenkins/pipelines/pipeline1/runs/1/nodes/", List.class);
Assert.assertEquals(nodes.size(), resp.size());
//Get a node detail
FlowNode n = nodes.get(0);
Map node = get("/organizations/jenkins/pipelines/pipeline1/runs/1/nodes/"+n.getId());
List<Map> edges = (List<Map>) node.get("edges");
Assert.assertEquals(n.getId(), node.get("id"));
Assert.assertEquals(getNodeName(n), node.get("displayName"));
Assert.assertEquals("SUCCESS", node.get("result"));
Assert.assertEquals(1, edges.size());
Assert.assertEquals(nodes.get(1).getId(), edges.get(0).get("id"));
//Get a parllel node detail
node = get("/organizations/jenkins/pipelines/pipeline1/runs/1/nodes/"+parallelNodes.get(0).getId());
n = parallelNodes.get(0);
edges = (List<Map>) node.get("edges");
Assert.assertEquals(n.getId(), node.get("id"));
Assert.assertEquals(getNodeName(n), node.get("displayName"));
Assert.assertEquals("SUCCESS", node.get("result"));
Assert.assertEquals(1, edges.size());
Assert.assertEquals(nodes.get(nodes.size()-1).getId(), edges.get(0).get("id"));
}
@Test
public void getPipelineJobRunNodeLogTest() throws Exception {
WorkflowJob job1 = j.jenkins.createProject(WorkflowJob.class, "pipeline1");
job1.setDefinition(new CpsFlowDefinition("stage 'build'\n" +
"node{\n" +
" echo \"Building...\"\n" +
"}\n" +
"\n" +
"stage 'test'\n" +
"parallel 'unit':{\n" +
" node{\n" +
" echo \"Unit testing...\"\n" +
" }\n" +
"},'integration':{\n" +
" node{\n" +
" echo \"Integration testing...\"\n" +
" }\n" +
"}, 'ui':{\n" +
" node{\n" +
" echo \"UI testing...\"\n" +
" }\n" +
"}\n" +
"\n" +
"stage 'deploy'\n" +
"node{\n" +
" echo \"Deploying\"\n" +
"}"));
WorkflowRun b1 = job1.scheduleBuild2(0).get();
j.assertBuildStatusSuccess(b1);
FlowGraphTable nodeGraphTable = new FlowGraphTable(b1.getExecution());
nodeGraphTable.build();
List<FlowNode> nodes = getStages(nodeGraphTable);
List<FlowNode> parallelNodes = getParallelNodes(nodeGraphTable);
Assert.assertEquals(6, nodes.size());
Assert.assertEquals(3, parallelNodes.size());
String output = get("/organizations/jenkins/pipelines/pipeline1/runs/1/log", String.class);
Assert.assertNotNull(output);
System.out.println(output);
output = get("/organizations/jenkins/pipelines/pipeline1/runs/1/nodes/"+nodes.get(0).getId()+"/log", String.class);
Assert.assertNotNull(output);
System.out.println(output);
output = get("/organizations/jenkins/pipelines/pipeline1/runs/1/nodes/"+parallelNodes.get(0).getId()+"/log", String.class);
Assert.assertNotNull(output);
System.out.println(output);
}
private List<FlowNode> getStages(FlowGraphTable nodeGraphTable){
List<FlowNode> nodes = new ArrayList<>();
for(FlowGraphTable.Row row: nodeGraphTable.getRows()){
if(PipelineNodeUtil.isStage(row.getNode()) ||
PipelineNodeUtil.isParallelBranch(row.getNode())){
nodes.add(row.getNode());
}
}
return nodes;
}
private List<FlowNode> getParallelNodes(FlowGraphTable nodeGraphTable){
List<FlowNode> parallelNodes = new ArrayList<>();
for(FlowGraphTable.Row row: nodeGraphTable.getRows()){
if(PipelineNodeUtil.isParallelBranch(row.getNode())){
parallelNodes.add(row.getNode());
}
}
return parallelNodes;
}
}

View File

@ -485,156 +485,136 @@ Each branch in the repo with Jenkins file will appear as a branch in this pipeli
# Get Pipeline run nodes
curl -v http://localhost:8080/jenkins/blue/rest/organizations/jenkins/pipelines/pipeline1/runs/1/nodes/
[
{
"displayName": "build",
"edges": [
{
"durationInMillis": 234,
"id": "9"
}
],
"id": "3",
"startTime": "2016-03-11T00:32:52.273-0800",
"status": "SUCCESS",
"state": "FINISHED"
},
{
"displayName": "test",
"edges": [
{
"durationInMillis": 4,
"id": "13"
},
{
"durationInMillis": 6,
"id": "14"
},
{
"durationInMillis": 9,
"id": "15"
}
],
"id": "9",
"startTime": "2016-03-11T00:32:52.507-0800",
"status": "SUCCESS",
"state": "FINISHED"
},
{
"displayName": "unit",
"edges": [
{
"durationInMillis": 161,
"id": "35"
}
],
"id": "13",
"startTime": "2016-03-11T00:32:52.511-0800",
"status": "SUCCESS",
"state": "FINISHED"
},
{
"displayName": "deploy",
"edges": [],
"id": "35",
"startTime": "2016-03-11T00:32:52.672-0800",
"status": "SUCCESS",
"state": "FINISHED"
},
{
"displayName": "integration",
"edges": [
{
"durationInMillis": 159,
"id": "35"
}
],
"id": "14",
"startTime": "2016-03-11T00:32:52.513-0800",
"status": "SUCCESS",
"state": "FINISHED"
},
{
"displayName": "ui",
"edges": [
{
"durationInMillis": 156,
"id": "35"
}
],
"id": "15",
"startTime": "2016-03-11T00:32:52.516-0800",
"status": "SUCCESS",
"state": "FINISHED"
}
]
[ {
"displayName" : "build",
"durationInMillis" : 219,
"edges" : [ {
"id" : "9"
} ],
"id" : "3",
"result" : "SUCCESS",
"startTime" : "2016-05-06T15:15:08.719-0700",
"state" : "FINISHED"
}, {
"displayName" : "test",
"durationInMillis" : 158,
"edges" : [ {
"id" : "13"
}, {
"id" : "14"
}, {
"id" : "15"
} ],
"id" : "9",
"result" : "SUCCESS",
"startTime" : "2016-05-06T15:15:08.938-0700",
"state" : "FINISHED"
}, {
"displayName" : "unit",
"durationInMillis" : 127,
"edges" : [ {
"id" : "35"
} ],
"id" : "13",
"result" : "SUCCESS",
"startTime" : "2016-05-06T15:15:08.942-0700",
"state" : "FINISHED"
}, {
"displayName" : "integration",
"durationInMillis" : 126,
"edges" : [ {
"id" : "35"
} ],
"id" : "14",
"result" : "SUCCESS",
"startTime" : "2016-05-06T15:15:08.944-0700",
"state" : "FINISHED"
}, {
"displayName" : "ui",
"durationInMillis" : 137,
"edges" : [ {
"id" : "35"
} ],
"id" : "15",
"result" : "SUCCESS",
"startTime" : "2016-05-06T15:15:08.945-0700",
"state" : "FINISHED"
}, {
"displayName" : "deploy",
"durationInMillis" : 47,
"edges" : [ ],
"id" : "35",
"result" : "SUCCESS",
"startTime" : "2016-05-06T15:15:09.096-0700",
"state" : "FINISHED"
} ]
> In case pipeline run fails in one of the parallel branch, enclosing stage node will appear failed as well.
> In case if the pipeline is in progress or failed in the middle, the response may include future nodes if there was
last successful pipeline build. The returned future nodes will have startTime, result and state as null.
Also the last node's edges will be patched to point to the future node.
From the above example, if build failed at parallel node *unit* then the response will be
From the above example, if build failed at parallel node *unit* then the response will be:
[ {
"displayName" : "build",
"durationInMillis" : 51,
"edges" : [ {
"durationInMillis" : 54,
"id" : "9"
} ],
"id" : "3",
"result" : "SUCCESS",
"startTime" : "2016-04-22T17:45:18.499-0700",
"startTime" : "2016-05-06T15:39:18.569-0700",
"state" : "FINISHED"
}, {
"displayName" : "test",
"durationInMillis" : 344,
"edges" : [ {
"durationInMillis" : 2,
"id" : "13"
}, {
"durationInMillis" : 3,
"id" : "14"
}, {
"durationInMillis" : 4,
"id" : "15"
} ],
"id" : "9",
"result" : "UNSTABLE",
"startTime" : "2016-04-22T17:45:18.553-0700",
"result" : "FAILURE",
"startTime" : "2016-05-06T15:39:18.620-0700",
"state" : "FINISHED"
}, {
"displayName" : "unit",
"durationInMillis" : 329,
"edges" : [ {
"durationInMillis" : -1,
"id" : "35"
} ],
"id" : "13",
"result" : "FAILURE",
"startTime" : "2016-04-22T17:45:18.555-0700",
"startTime" : "2016-05-06T15:39:18.622-0700",
"state" : "FINISHED"
}, {
"displayName" : "integration",
"durationInMillis" : 97,
"edges" : [ {
"durationInMillis" : -1,
"id" : "35"
} ],
"id" : "14",
"result" : "SUCCESS",
"startTime" : "2016-04-22T17:45:18.556-0700",
"startTime" : "2016-05-06T15:39:18.623-0700",
"state" : "FINISHED"
}, {
"displayName" : "ui",
"durationInMillis" : 107,
"edges" : [ {
"durationInMillis" : -1,
"id" : "35"
} ],
"id" : "15",
"result" : "SUCCESS",
"startTime" : "2016-04-22T17:45:18.557-0700",
"startTime" : "2016-05-06T15:39:18.623-0700",
"state" : "FINISHED"
}, {
"displayName" : "deploy",
"durationInMillis" : null,
"edges" : [ {
"durationInMillis" : -1,
"id" : "41"
} ],
"id" : "35",
@ -643,13 +623,14 @@ From the above example, if build failed at parallel node *unit* then the respons
"state" : null
}, {
"displayName" : "deployToProd",
"durationInMillis" : null,
"edges" : [ ],
"id" : "41",
"result" : null,
"startTime" : null,
"state" : null
} ]
# Get a Pipeline run node's detail
curl -v http://localhost:8080/jenkins/blue/rest/organizations/jenkins/pipelines/pipeline1/runs/1/nodes/3
@ -658,7 +639,6 @@ From the above example, if build failed at parallel node *unit* then the respons
"displayName": "build",
"edges": [
{
"durationInMillis": 234,
"id": "9"
}
],

View File

@ -61,6 +61,7 @@ public abstract class BluePipelineNode extends Resource{
public static final String START_TIME="startTime";
public static final String ID = "id";
public static final String EDGES = "edges";
public static final String DURATION_IN_MILLIS="durationInMillis";
@Exported(name = ID)
public abstract String getId();
@ -87,6 +88,9 @@ public abstract class BluePipelineNode extends Resource{
return new SimpleDateFormat(BlueRun.DATE_FORMAT_STRING).format(getStartTime());
}
@Exported(name= DURATION_IN_MILLIS)
public abstract Long getDurationInMillis();
/**
* @return Gives logs associated with this node
*/
@ -96,9 +100,6 @@ public abstract class BluePipelineNode extends Resource{
public abstract static class Edge{
@Exported
public abstract String getId();
@Exported
public abstract long getDurationInMillis();
}
}