Skip to content
Permalink
Browse files
[JENKINS-27395] Record flow node and enclosing stage/branch for tests
Downstream of jenkinsci/junit-plugin#76. This
records the `FlowNode#id` for the step that's actually recording the
test results and the enclosing stage(s)/branch(es) of that `FlowNode`
with each suite, along with the names of the enclosing
stage(s)/branch(es) on each `CaseResult` for display purposes.

This is accomplished by getting the `FlowNode` via
`context.get(FlowNode.class)`, and then passing the configured
`JUnitResultArchiver`, the node's ID, the enclosing stage/branch IDs,
and the run (which is used to get the `Run#getExternalizableId()` for
internal purposes) to the new `JUnitResultArchiver#parseAndAttach`
static method. That method does the rest of the work.

Once this is all released, the classic test results pages will display
the test name with the enclosing stage/branch names prepended (if
there are test results from multiple stages/branches in the full test
result - i.e., only if relevant). Blue Ocean has a PR to do the same
that's pending.
  • Loading branch information
abayer committed Jan 4, 2018
1 parent 9238916 commit aeb7d81775305282afcaa0464c4bf72c1faf3ca9
@@ -76,6 +76,7 @@
<jenkins.version>2.46.3</jenkins.version>
<scm-api-plugin.version>2.1.1</scm-api-plugin.version>
<git-plugin.version>3.3.0</git-plugin.version>
<junit-plugin.version>1.22-20170815.171655-1</junit-plugin.version><!-- TODO: Switch to release once https://github.com/jenkinsci/junit-plugin/pull/76 is merged and released -->
</properties>
<dependencies>
<dependency>
@@ -91,7 +92,7 @@
<dependency>
<groupId>org.jenkins-ci.plugins.workflow</groupId>
<artifactId>workflow-job</artifactId>
<version>2.11</version>
<version>2.11.1</version>
<optional>true</optional>
</dependency>
<dependency>
@@ -114,12 +115,12 @@
<dependency>
<groupId>org.jenkins-ci.plugins.workflow</groupId>
<artifactId>workflow-step-api</artifactId>
<version>2.9</version>
<version>2.12</version>
</dependency>
<dependency>
<groupId>org.jenkins-ci.plugins.workflow</groupId>
<artifactId>workflow-api</artifactId>
<version>2.13</version>
<version>2.19</version>
</dependency>
<dependency>
<groupId>org.jenkins-ci.plugins</groupId>
@@ -144,10 +145,17 @@
<dependency>
<groupId>org.jenkins-ci.plugins</groupId>
<artifactId>junit</artifactId>
<version>1.20</version>
<version>${junit-plugin.version}</version>
<scope>compile</scope>
<optional>true</optional>
</dependency>
<dependency>
<groupId>org.jenkins-ci.plugins</groupId>
<artifactId>junit</artifactId>
<version>${junit-plugin.version}</version>
<classifier>tests</classifier>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.jenkins-ci.plugins</groupId>
<artifactId>junit-attachments</artifactId>
@@ -208,7 +216,7 @@
<dependency>
<groupId>org.jenkins-ci.plugins.workflow</groupId>
<artifactId>workflow-cps</artifactId>
<version>2.30</version>
<version>2.37</version>
<scope>test</scope>
</dependency>
<dependency>
@@ -233,14 +241,20 @@
<dependency>
<groupId>org.jenkins-ci.plugins</groupId>
<artifactId>structs</artifactId>
<version>1.6</version>
<version>1.7</version>
</dependency>
<dependency>
<groupId>org.jenkins-ci.plugins.workflow</groupId>
<artifactId>workflow-scm-step</artifactId>
<version>2.4</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.jenkins-ci.plugins</groupId>
<artifactId>pipeline-stage-step</artifactId>
<version>2.2</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.jenkins-ci.plugins</groupId>
<artifactId>matrix-project</artifactId>
@@ -308,7 +322,7 @@
<dependency>
<groupId>org.jenkins-ci.plugins</groupId>
<artifactId>script-security</artifactId>
<version>1.26</version>
<version>1.33</version>
</dependency>
<dependency>
<groupId>org.jenkins-ci.plugins</groupId>
@@ -27,15 +27,18 @@
import hudson.Extension;
import hudson.FilePath;
import hudson.Launcher;
import hudson.model.Result;
import hudson.model.Run;
import hudson.model.StreamBuildListener;
import hudson.model.TaskListener;
import hudson.tasks.junit.JUnitResultArchiver;
import hudson.tasks.junit.TestDataPublisher;
import hudson.tasks.junit.TestResultAction;
import org.jenkinsci.Symbol;
import org.jenkinsci.plugins.pipeline.maven.MavenSpyLogProcessor;
import org.jenkinsci.plugins.pipeline.maven.MavenPublisher;
import org.jenkinsci.plugins.pipeline.maven.util.XmlUtils;
import org.jenkinsci.plugins.workflow.graph.FlowNode;
import org.jenkinsci.plugins.workflow.steps.StepContext;
import org.kohsuke.stapler.DataBoundConstructor;
import org.kohsuke.stapler.DataBoundSetter;
@@ -53,6 +56,8 @@
import javax.annotation.Nonnull;
import javax.annotation.Nullable;

import static hudson.tasks.junit.pipeline.JUnitResultsStepExecution.getEnclosingStagesAndParallels;

/**
* @author <a href="mailto:cleclerc@cloudbees.com">Cyrille Le Clerc</a>
*/
@@ -196,6 +201,9 @@ private void executeReporter(StepContext context, TaskListener listener, List<El
return;
}

FlowNode node = context.get(FlowNode.class);
String nodeId = node.getId();

for (Element testEvent : testEvents) {
String surefireEventType = testEvent.getAttribute("type");
if (!surefireEventType.equals("MojoSucceeded") && !surefireEventType.equals("MojoFailed")) {
@@ -266,7 +274,15 @@ private void executeReporter(StepContext context, TaskListener listener, List<El
}

try {
archiver.perform(run, workspace, launcher, listener);
TestResultAction testResultAction = JUnitResultArchiver.parseAndAttach(archiver, nodeId, getEnclosingStagesAndParallels(node),
run, workspace, launcher, listener);

if (testResultAction != null) {
// TODO: Once JENKINS-43995 lands, update this to set the step status instead of the entire build.
if (testResultAction.getResult().getFailCount() > 0) {
context.setResult(Result.UNSTABLE);
}
}
} catch (Exception e) {
listener.error("[withMaven] junitPublisher - Silently ignore exception archiving JUnit results for Maven artifact " + mavenArtifact.toString() + " generated by " + pluginInvocation + ": " + e);
LOGGER.log(Level.WARNING, "Exception processing " + XmlUtils.toString(testEvent), e);
@@ -30,15 +30,11 @@
import hudson.model.Result;
import hudson.plugins.tasks.TasksResultAction;
import hudson.tasks.Fingerprinter;
import hudson.tasks.Maven;
import hudson.tasks.junit.TestResultAction;
import jenkins.mvn.DefaultGlobalSettingsProvider;
import jenkins.mvn.DefaultSettingsProvider;
import hudson.tasks.junit.pipeline.JUnitResultsStepTest;
import jenkins.mvn.FilePathGlobalSettingsProvider;
import jenkins.mvn.FilePathSettingsProvider;
import jenkins.mvn.GlobalMavenConfig;
import jenkins.plugins.git.GitSampleRepoRule;
import jenkins.scm.impl.mock.GitSampleRepoRuleUtils;
import org.apache.commons.io.FileUtils;
import org.jenkinsci.Symbol;
import org.jenkinsci.plugins.configfiles.GlobalConfigFiles;
@@ -53,19 +49,10 @@
import org.jenkinsci.plugins.workflow.cps.CpsFlowDefinition;
import org.jenkinsci.plugins.workflow.job.WorkflowJob;
import org.jenkinsci.plugins.workflow.job.WorkflowRun;
import org.junit.Before;
import org.junit.ClassRule;
import org.junit.Rule;
import org.junit.Test;
import org.jvnet.hudson.test.BuildWatcher;
import org.jvnet.hudson.test.ExtendedToolInstallations;
import org.jvnet.hudson.test.Issue;
import org.jvnet.hudson.test.JenkinsRule;

import java.io.File;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.util.Collection;
import java.util.Map;
import java.util.logging.Level;
@@ -805,4 +792,42 @@ public void maven_settings_defined_through_pipeline_attribute_and_config_file_pr
GlobalConfigFiles.get().remove(mavenSettingsConfig.id);
}
}

@Test
public void maven_build_test_results_by_stage_and_branch() throws Exception {
loadMavenJarProjectInGitRepo(this.gitRepoRule);

String pipelineScript = "stage('first') {\n" +
" parallel(a: {\n" +
" node('master') {\n" +
" git($/" + gitRepoRule.toString() + "/$)\n" +
" withMaven() {\n" +
" sh 'mvn package verify'\n" +
" }\n" +
" }\n" +
" },\n" +
" b: {\n" +
" node('master') {\n" +
" git($/" + gitRepoRule.toString() + "/$)\n" +
" withMaven() {\n" +
" sh 'mvn package verify'\n" +
" }\n" +
" }\n" +
" })\n" +
"}";

WorkflowJob pipeline = jenkinsRule.createProject(WorkflowJob.class, "build-on-master");
pipeline.setDefinition(new CpsFlowDefinition(pipelineScript, true));
WorkflowRun build = jenkinsRule.buildAndAssertSuccess(pipeline);

TestResultAction testResultAction = build.getAction(TestResultAction.class);
assertThat(testResultAction.getTotalCount(), is(6));
assertThat(testResultAction.getFailCount(), is(0));

JUnitResultsStepTest.assertStageResults(build, 4, 6, "first");

JUnitResultsStepTest.assertBranchResults(build, 2, 3, "a", "first");
JUnitResultsStepTest.assertBranchResults(build, 2, 3, "b", "first");
}

}

0 comments on commit aeb7d81

Please sign in to comment.