44 | * All the exceptions are forwarded to the caller.
45 | *
46 | * @param ws {@link File} that represents the local file that {@link FilePath} has represented.
47 | * @param channel The "back pointer" of the {@link Channel} that represents the communication
48 | * with the node from where the code was sent.
49 | */
50 | public Boolean invoke(File ws, VirtualChannel channel) throws IOException {
51 | MsTestLogger logger = new MsTestLogger(listener);
52 |
53 | if (msTestFiles.length == 0) {
54 | if (!failOnError) {
55 | logger.warn("No MSTest TRX test report files were found. Ignoring.");
56 | return Boolean.TRUE;
57 | }
58 | throw new AbortException(MsTestLogger
59 | .format("No MSTest TRX test report files were found. Configuration error?"));
60 | }
61 |
62 | File junitOutputPath = new File(ws, JUNIT_REPORTS_PATH);
63 | boolean success = FileOperator.safeCreateFolder(junitOutputPath, logger);
64 | if (!success) {
65 | return Boolean.FALSE;
66 | }
67 |
68 | for (String mstestFile : msTestFiles) {
69 | logger.info("processing report file: " + mstestFile);
70 | try {
71 | new ContentCorrector(mstestFile).fix();
72 | unitReportTransformer.transform(mstestFile, junitOutputPath);
73 | } catch (TransformerException | SAXException te) {
74 | throw new IOException(
75 | MsTestLogger.format(
76 | "Unable to transform the MSTest report. Please report this issue to the plugin author"),
77 | te);
78 | } catch (ParserConfigurationException pce) {
79 | throw new IOException(
80 | MsTestLogger.format(
81 | "Unable to initalize the XML parser. Please report this issue to the plugin author"),
82 | pce);
83 | }
84 | }
85 |
86 | return Boolean.TRUE;
87 | }
88 | }
89 |
--------------------------------------------------------------------------------
/src/test/resources/hudson/plugins/mstest/mstest_vs_2012.trx:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | These are default test settings for a local test run.
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
27 |
28 |
29 |
30 |
31 |
32 |
33 |
34 |
35 |
36 |
37 |
38 |
45 |
46 |
47 |
--------------------------------------------------------------------------------
/src/test/resources/hudson/plugins/mstest/mstest_vs_2012_timeout.trx:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | These are default test settings for a local test run.
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
27 |
28 |
29 |
30 |
31 |
32 |
33 |
34 |
35 |
36 |
37 |
38 |
45 |
46 |
47 |
--------------------------------------------------------------------------------
/src/test/resources/hudson/plugins/mstest/mstest_2_tests_from_different_assemblies.trx:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | This is a default test run configuration for a local test run.
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
27 |
28 |
29 |
30 |
31 |
32 |
33 |
34 |
35 |
36 |
37 |
38 |
39 |
40 |
47 |
48 |
49 |
51 |
52 |
53 |
54 |
--------------------------------------------------------------------------------
/src/test/resources/hudson/plugins/mstest/mstest_2_tests_1_class.trx:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | This is a default test run configuration for a local test run.
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
27 |
28 |
29 |
30 |
31 |
32 |
33 |
34 |
35 |
36 |
37 |
38 |
39 |
40 |
41 |
42 |
44 |
45 |
46 |
53 |
54 |
55 |
--------------------------------------------------------------------------------
/src/test/resources/hudson/plugins/mstest/mstest_more_than_one_minute_test.trx:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | This is a default test run configuration for a local test run.
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
27 |
28 |
29 |
30 |
31 |
32 |
33 |
34 |
35 |
36 |
37 |
38 |
39 |
40 |
41 |
42 |
44 |
45 |
46 |
53 |
54 |
55 |
--------------------------------------------------------------------------------
/src/test/resources/hudson/plugins/mstest/mstest_vs_2010.trx:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | These are default test settings for a local test run.
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
27 |
28 |
29 |
30 |
31 |
32 |
33 |
34 |
35 |
36 |
37 |
38 |
45 |
46 |
47 |
--------------------------------------------------------------------------------
/src/test/resources/hudson/plugins/mstest/JENKINS-23531-xmlentities-forged.trx:
--------------------------------------------------------------------------------
1 |
2 |
4 |
5 | This is a default test run configuration for a local test run.
6 |
7 |
8 |
9 |
10 |
11 |
12 |
15 |
16 |
18 |
19 |
21 |
22 |
23 |
24 |
25 |
26 |
29 |
30 |
31 |
32 |
33 |
34 |
35 |
36 |
38 |
39 |
40 |
46 |
66 |
67 |
68 |
--------------------------------------------------------------------------------
/src/test/resources/hudson/plugins/mstest/JENKINS-23531-charset.trx:
--------------------------------------------------------------------------------
1 |
2 |
4 |
5 | This is a default test run configuration for a local test run.
6 |
7 |
8 |
9 |
10 |
11 |
12 |
15 |
16 |
18 |
19 |
21 |
22 |
23 |
24 |
25 |
26 |
29 |
30 |
31 |
32 |
33 |
34 |
35 |
36 |
38 |
39 |
40 |
46 |
67 |
68 |
69 |
--------------------------------------------------------------------------------
/pom.xml:
--------------------------------------------------------------------------------
1 |
2 | 4.0.0
3 |
4 | org.jenkins-ci.plugins
5 | plugin
6 | 4.74
7 |
8 |
9 |
10 | 1.0.6
11 | -SNAPSHOT
12 | 2.401.3
13 |
14 | org.jvnet.hudson.plugins
15 | mstest
16 | hpi
17 | MSTest plugin
18 | Generates test reports for MSTest.
19 | ${revision}${changelist}
20 | http://wiki.jenkins-ci.org/display/JENKINS/MSTest+Plugin
21 |
22 | scm:git:https://github.com:jenkinsci/mstest-plugin.git
23 | scm:git:git@github.com:jenkinsci/mstest-plugin.git
24 | https://github.com/jenkinsci/mstest-plugin
25 | ${scmTag}
26 |
27 |
28 |
29 | nilleb
30 | Ivo Bellin Salarin
31 | me@nilleb.com
32 |
33 |
34 | casz
35 | Joseph Petersen
36 | https://github.com/casz/ama
37 |
38 |
39 |
40 |
41 | org.jenkins-ci.plugins
42 | junit
43 |
44 |
45 |
46 |
47 | xmlunit
48 | xmlunit
49 | 1.6
50 | test
51 |
52 |
53 | junit
54 | junit
55 | test
56 |
57 |
58 | org.jmock
59 | jmock-junit4
60 | 2.6.0
61 | test
62 |
63 |
64 | org.jmock
65 | jmock-legacy
66 | 2.6.0
67 | test
68 |
69 |
70 | cglib
71 | cglib
72 | 2.2.2
73 | test
74 |
75 |
76 | org.jenkins-ci.plugins.workflow
77 | workflow-job
78 | test
79 |
80 |
81 | org.jenkins-ci.plugins.workflow
82 | workflow-cps
83 | test
84 |
85 |
86 | org.jenkins-ci.plugins.workflow
87 | workflow-basic-steps
88 | test
89 |
90 |
91 |
92 |
93 |
94 | io.jenkins.tools.bom
95 | bom-2.401.x
96 | 2516.v113cb_3d00317
97 | import
98 | pom
99 |
100 |
101 | org.hamcrest
102 | hamcrest-core
103 | 2.1
104 |
105 |
106 |
107 |
108 |
109 | repo.jenkins-ci.org
110 | https://repo.jenkins-ci.org/public/
111 |
112 |
113 |
114 |
115 | repo.jenkins-ci.org
116 | https://repo.jenkins-ci.org/public/
117 |
118 |
119 |
120 |
--------------------------------------------------------------------------------
/src/test/java/hudson/plugins/mstest/MSTestTransformerAndConverterTest.java:
--------------------------------------------------------------------------------
1 | package hudson.plugins.mstest;
2 |
3 | import hudson.FilePath;
4 | import hudson.model.TaskListener;
5 | import hudson.remoting.VirtualChannel;
6 | import java.io.ByteArrayOutputStream;
7 | import java.io.File;
8 | import java.io.FileOutputStream;
9 | import java.io.InputStream;
10 | import java.io.PrintStream;
11 | import java.nio.file.Files;
12 | import org.jmock.Expectations;
13 | import org.jmock.Mockery;
14 | import org.junit.After;
15 | import org.junit.Assert;
16 | import org.junit.Before;
17 | import org.junit.Test;
18 | import org.springframework.util.FileCopyUtils;
19 | /* Java 1.7+
20 | import java.nio.file.Files;
21 | */
22 |
23 | /**
24 | * Unit tests for MSTestTransformer class
25 | *
26 | * @author Antonio Marques
27 | */
28 | public class MSTestTransformerAndConverterTest extends TestHelper {
29 |
30 |
31 | private TaskListener buildListener;
32 | private Mockery context;
33 | private Mockery classContext;
34 | private MSTestTransformer transformer;
35 | private VirtualChannel virtualChannel;
36 |
37 |
38 | @Before
39 | public void setUp() throws Exception {
40 | createWorkspace();
41 |
42 | context = getMock();
43 | classContext = getClassMock();
44 | buildListener = classContext.mock(TaskListener.class);
45 | virtualChannel = context.mock(VirtualChannel.class);
46 | }
47 |
48 | @After
49 | public void tearDown() throws Exception {
50 | deleteWorkspace();
51 | }
52 |
53 | @Test
54 | public void testInvalidXmlCharacters() throws Exception {
55 | final PrintStream logger = new PrintStream(new ByteArrayOutputStream());
56 | classContext.checking(new Expectations() {
57 | {
58 | ignoring(buildListener).getLogger();
59 | will(returnValue(logger));
60 | ignoring(buildListener);
61 | }
62 | });
63 | final String testPath = "xmlentities-forged.trx";
64 | File testFile = new File(parentFile, testPath);
65 | assert !testFile.exists() || testFile.delete();
66 | InputStream testStream = this.getClass()
67 | .getResourceAsStream("JENKINS-23531-xmlentities-forged.trx");
68 | Files.copy(testStream, testFile.toPath());
69 | MSTestReportConverter converter = new MSTestReportConverter(buildListener);
70 | transformer = new MSTestTransformer(resolve(testPath), converter, buildListener, false);
71 | transformer.invoke(parentFile, virtualChannel);
72 | FilePath[] list = workspace.list("*.trx");
73 | Assert.assertEquals(1, list.length);
74 | }
75 |
76 | @Test
77 | public void testInvalidXmlCharacters_VishalMane() throws Exception {
78 | final PrintStream logger = new PrintStream(new ByteArrayOutputStream());
79 | classContext.checking(new Expectations() {
80 | {
81 | ignoring(buildListener).getLogger();
82 | will(returnValue(logger));
83 | ignoring(buildListener);
84 | }
85 | });
86 | final String testPath = "vishalMane.trx";
87 | File testFile = new File(parentFile, testPath);
88 | assert !testFile.exists() || testFile.delete();
89 | InputStream testStream = this.getClass()
90 | .getResourceAsStream("SYSTEM_AD-JENKINS 2015-07-08 10_53_01.trx");
91 | Files.copy(testStream, testFile.toPath());
92 | MSTestReportConverter converter = new MSTestReportConverter(buildListener);
93 | transformer = new MSTestTransformer(resolve(testPath), converter, buildListener, false);
94 | transformer.invoke(parentFile, virtualChannel);
95 | FilePath[] list = workspace.list("*.trx");
96 | Assert.assertEquals(1, list.length);
97 | }
98 |
99 | @Test
100 | public void testCharset() throws Exception {
101 | final PrintStream logger = new PrintStream(new ByteArrayOutputStream());
102 | classContext.checking(new Expectations() {
103 | {
104 | ignoring(buildListener).getLogger();
105 | will(returnValue(logger));
106 | ignoring(buildListener);
107 | }
108 | });
109 | final String testPath = "charset.trx";
110 | File testFile = new File(parentFile, testPath);
111 | assert !testFile.exists() || testFile.delete();
112 | InputStream testStream = this.getClass().getResourceAsStream("JENKINS-23531-charset.trx");
113 | Files.copy(testStream, testFile.toPath());
114 | MSTestReportConverter converter = new MSTestReportConverter(buildListener);
115 | transformer = new MSTestTransformer(resolve(testPath), converter, buildListener, false);
116 | transformer.invoke(parentFile, virtualChannel);
117 | FilePath[] list = workspace.list("*.trx");
118 | Assert.assertEquals(1, list.length);
119 | }
120 | }
121 |
--------------------------------------------------------------------------------
/src/test/resources/hudson/plugins/mstest/DataDriven-no-tests-found.trx:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | These are default test settings for a local test run.
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
27 |
28 |
29 |
30 |
31 |
32 |
33 |
34 |
35 |
36 |
37 |
38 |
44 |
45 |
46 |
47 |
48 |
--------------------------------------------------------------------------------
/src/test/resources/hudson/plugins/mstest/ReportingOptions.2008.trx:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
27 |
28 |
29 |
30 |
31 |
32 |
33 |
34 |
35 |
36 |
37 |
38 |
39 |
40 |
41 |
42 |
43 |
44 |
45 |
46 |
47 |
48 |
49 |
52 |
53 |
54 |
57 |
58 |
59 |
62 |
63 |
64 |
--------------------------------------------------------------------------------
/src/test/resources/hudson/plugins/mstest/ReportingOptions.2013.trx:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
27 |
28 |
29 |
30 |
31 |
32 |
33 |
34 |
35 |
36 |
37 |
38 |
39 |
40 |
41 |
44 |
45 |
46 |
49 |
50 |
51 |
54 |
55 |
56 |
--------------------------------------------------------------------------------
/src/test/resources/hudson/plugins/mstest/JENKINS-25533+19384.trx:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
27 |
28 |
29 |
30 |
31 |
32 |
33 |
34 |
35 |
36 |
37 |
38 |
39 |
40 |
41 |
42 |
43 |
44 |
65 |
66 |
67 |
68 |
69 |
--------------------------------------------------------------------------------
/src/test/java/hudson/plugins/mstest/MSTestPublisherJenkinsRuleTest.java:
--------------------------------------------------------------------------------
1 | /*
2 | * To change this license header, choose License Headers in Project Properties.
3 | * To change this template file, choose Tools | Templates
4 | * and open the template in the editor.
5 | */
6 | package hudson.plugins.mstest;
7 |
8 | import hudson.EnvVars;
9 | import hudson.Launcher;
10 | import hudson.model.AbstractBuild;
11 | import hudson.model.BuildListener;
12 | import hudson.model.FreeStyleBuild;
13 | import hudson.model.FreeStyleProject;
14 | import hudson.slaves.EnvironmentVariablesNodeProperty;
15 | import java.io.File;
16 | import java.io.IOException;
17 | import org.apache.commons.io.FileUtils;
18 | import org.junit.Rule;
19 | import org.junit.Test;
20 | import org.jvnet.hudson.test.JenkinsRule;
21 | import org.jvnet.hudson.test.TestBuilder;
22 |
23 | import static org.junit.Assert.assertFalse;
24 | import static org.junit.Assert.assertTrue;
25 |
26 | /**
27 | * @author nilleb
28 | */
29 | public class MSTestPublisherJenkinsRuleTest {
30 |
31 | @Rule
32 | public JenkinsRule j = new JenkinsRule();
33 |
34 | private MSTestPublisher getTestedPublisher(String pattern) {
35 | MSTestPublisher publisher = new MSTestPublisher();
36 | publisher.setTestResultsFile(pattern);
37 | publisher.setFailOnError(false);
38 | publisher.setKeepLongStdio(false);
39 | return publisher;
40 | }
41 |
42 | @Test
43 | public void testResolveEnvironmentVariables() throws Exception {
44 | EnvironmentVariablesNodeProperty prop = new EnvironmentVariablesNodeProperty();
45 | EnvVars envVars = prop.getEnvVars();
46 | envVars.put("TRX", "build.trx");
47 | j.jenkins.getGlobalNodeProperties().add(prop);
48 | FreeStyleProject project = j.createFreeStyleProject();
49 | project.getPublishersList().add(getTestedPublisher("$TRX"));
50 | FreeStyleBuild build = project.scheduleBuild2(0).get();
51 |
52 | if (build != null) {
53 | String s = FileUtils.readFileToString(build.getLogFile());
54 | assertFalse(s.contains("Processing tests results in file(s) $TRX"));
55 | assertTrue(s.contains("build.trx"));
56 | }
57 | }
58 |
59 | @Test
60 | public void testResolveMultipleEnvironmentVariables() throws Exception {
61 | EnvironmentVariablesNodeProperty prop = new EnvironmentVariablesNodeProperty();
62 | EnvVars envVars = prop.getEnvVars();
63 | envVars.put("TRX", "build.trx");
64 | j.jenkins.getGlobalNodeProperties().add(prop);
65 | FreeStyleProject project = j.createFreeStyleProject();
66 | project.getPublishersList().add(getTestedPublisher("$WORKSPACE/$TRX"));
67 | FreeStyleBuild build = project.scheduleBuild2(0).get();
68 |
69 | if (build != null) {
70 | String s = FileUtils.readFileToString(build.getLogFile());
71 | assertFalse(s.contains("Processing tests results in file(s) $TRX"));
72 | assertTrue(s.contains("/build.trx"));
73 | }
74 | }
75 |
76 | @Test
77 | public void testExecuteOnRealTrx() throws Exception {
78 | EnvironmentVariablesNodeProperty prop = new EnvironmentVariablesNodeProperty();
79 | EnvVars envVars = prop.getEnvVars();
80 | envVars.put("TRX", "results-example-mstest.trx");
81 | j.jenkins.getGlobalNodeProperties().add(prop);
82 | FreeStyleProject project = j.createFreeStyleProject();
83 | project.getPublishersList().add(getTestedPublisher("$WORKSPACE/$TRX"));
84 | project.getBuildersList().add(new TestBuilder() {
85 | public boolean perform(AbstractBuild, ?> build, Launcher launcher,
86 | BuildListener listener) throws InterruptedException, IOException {
87 | File f = new File(
88 | "src/test/resources/hudson/plugins/mstest/results-example-mstest.trx");
89 | assertTrue(f.exists());
90 | File dest = new File(build.getWorkspace().getRemote());
91 | assertTrue(dest.exists());
92 | FileUtils.copyFileToDirectory(f, dest);
93 | assertTrue(build.getWorkspace().child("results-example-mstest.trx").exists());
94 | return true;
95 | }
96 | });
97 |
98 | FreeStyleBuild build = project.scheduleBuild2(0).get();
99 | if (build != null) {
100 | String s = FileUtils.readFileToString(build.getLogFile());
101 | assertTrue(s.contains(File.separator + "results-example-mstest.trx"));
102 | }
103 | }
104 |
105 | @Test
106 | public void testExecuteOnRealTrx_usingAntFileSet() throws Exception {
107 | FreeStyleProject project = j.createFreeStyleProject();
108 | project.getPublishersList().add(getTestedPublisher("**/*.trx"));
109 | assertTrue(project.getBuildersList().add(new TestBuilder() {
110 | public boolean perform(AbstractBuild, ?> build, Launcher launcher,
111 | BuildListener listener) throws InterruptedException, IOException {
112 | File f = new File(
113 | "src/test/resources/hudson/plugins/mstest/results-example-mstest.trx");
114 | assertTrue(f.exists());
115 | File dest = new File(build.getWorkspace().getRemote(),
116 | "TestResults_51310ef0-5d36-47cc-a1a9-b21d6f3e2072");
117 | assertTrue(dest.mkdir());
118 | FileUtils.copyFileToDirectory(f, dest);
119 | assertTrue(build.getWorkspace().child(
120 | "TestResults_51310ef0-5d36-47cc-a1a9-b21d6f3e2072/results-example-mstest.trx")
121 | .exists());
122 | return true;
123 | }
124 | }));
125 |
126 | FreeStyleBuild build = project.scheduleBuild2(0).get();
127 | if (build != null) {
128 | String s = FileUtils.readFileToString(build.getLogFile());
129 | assertTrue(s == null || s.contains(File.separator + "results-example-mstest.trx"));
130 | }
131 | }
132 | }
133 |
--------------------------------------------------------------------------------
/src/test/resources/hudson/plugins/mstest/kozl-unit-tests-missing.trx:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | These are default test settings for a local test run.
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
27 |
28 |
29 |
30 |
31 |
32 |
33 |
34 |
35 |
36 |
37 |
38 |
39 |
40 |
41 |
42 |
43 |
44 |
45 |
46 |
47 |
48 |
49 |
54 |
55 |
56 |
61 |
62 |
63 |
68 |
69 |
70 |
--------------------------------------------------------------------------------
/src/test/resources/hudson/plugins/mstest/webTestResult.trx:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | These are default test settings for a local test run.
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
27 |
28 |
29 |
30 |
31 |
32 |
33 |
34 |
35 |
36 |
37 |
38 |
39 |
40 |
41 |
42 |
43 |
44 |
45 |
46 |
47 |
48 |
49 |
50 |
51 |
52 |
53 |
54 | These are default test settings for a local test run.
55 |
56 |
57 |
58 |
59 |
60 |
61 |
62 |
63 |
64 |
65 |
66 |
67 |
68 |
69 |
70 |
71 |
72 |
73 |
74 |
75 |
76 |
77 |
78 |
79 |
80 |
81 |
82 | xxxxxxxxxxxxxxxxxx\Login - Sucess.webtestResult
83 |
84 |
85 |
--------------------------------------------------------------------------------
/src/test/resources/hudson/plugins/mstest/mstest_4_tests_2_classes.trx:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | This is a default test run configuration for a local test run.
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
27 |
28 |
29 |
30 |
31 |
32 |
33 |
34 |
35 |
36 |
37 |
38 |
39 |
40 |
41 |
42 |
43 |
44 |
45 |
46 |
47 |
48 |
49 |
50 |
51 |
52 |
53 |
54 |
55 |
56 |
57 |
58 |
59 |
60 |
62 |
63 |
64 |
71 |
72 |
73 |
75 |
76 |
77 |
84 |
85 |
86 |
--------------------------------------------------------------------------------
/src/main/resources/hudson/plugins/mstest/vstest.console2codecoverage.xsl:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
27 |
28 |
29 |
30 |
31 |
32 |
33 |
34 |
35 |
36 |
37 |
38 |
39 |
40 |
41 |
42 |
43 |
44 |
45 |
46 |
47 |
48 |
49 |
50 |
51 |
52 |
53 |
54 |
55 |
56 |
57 |
58 |
59 |
60 |
61 |
62 |
63 |
64 |
65 |
66 |
67 |
68 |
69 |
70 |
71 |
72 |
73 |
74 |
75 | yes
76 | partial
77 | no
78 |
79 |
80 |
81 |
82 |
83 |
84 |
85 |
86 |
87 |
88 |
89 |
90 |
91 |
92 |
93 |
94 |
95 |
96 |
97 |
98 |
99 |
100 |
101 |
102 |
103 |
104 |
105 |
106 |
107 |
108 |
109 |
110 |
111 |
112 |
113 |
114 |
115 |
116 |
117 |
--------------------------------------------------------------------------------
/src/main/webapp/help.html:
--------------------------------------------------------------------------------
1 |
2 |
3 | The MSTest plugin can convert TRX format test reports into JUnit XML format so it can be recorded
4 | by Hudson.
5 |
6 |
7 |
General Usage
8 |
To enable the MSTest plugin features you need to set up your build to run MSTest.exe (or VSTest.Console.exe) first. Example:
9 |
"%PROGRAMFILES%\Microsoft Visual Studio 9.0\Common7\IDE\MSTest.exe" /runconfig:MyTestProject\LocalTestRun.testrunconfig /testcontainer:MyTestProject\bin\Release\MyTestProject.dll /resultsfile:TestResults\testResults.trx
10 |
11 |
12 | and then specify the path to the MSTest TRX file,
TestResults/testResults.trx in the above example.
13 |
14 |
15 | When using VSTest.Console.exe, you can't specify the path to the resulting TRX file. Thus, you can specify a pattern like TestResults/*/*.trx (/ or \, either will work).
16 |
17 |
18 | If you use the vstestrunner-plugin, the full path to the TRX file is exposed by an environment variable. So, you can also use an environment variable,
19 | like $VSTEST_RESULT_TRX or ${VSTEST_RESULT_TRX}.
20 |
21 |
Test Reporting Options
22 |
23 | Test authors can control how each test appears in Hudson/Jenkins by writing specially formatted text to stdout (the console) at the beginning of the test method. The following options are available:
24 |
- Append text to the test name (useful for identifying individual data-driven test instances)
25 | - Omit a test from Hudson/Jenkins (useful for some data-driven test scenarios)
26 | - Change the test's display name from the name of the test method to an alternate name (useful when reporting results to non-developers)
27 |
28 | In all cases, the specially formatted text must be the first text to appear in the individual test's stdout.
29 |
30 |
Appending to a test's display name (naming each data-driven test instance)
31 |
32 | You may want a test to appear in Jenkins with additional text appended to the usual name of the test method. This is
33 | particularly useful for data-driven tests, allowing you to give each individual test case an identifying suffix. To change a test's
34 | display name, write the following line as the first text written to stdout during the test's execution:
35 |
36 |
test-instance-name:{test instance name}:
37 |
38 | Replace "{test instance name}" with whatever text you want to have appended to the test name in test reports. For example, if a
39 | test method is named
MyTestMethod, and the first line of a particular execution of that test method is
40 |
test-instance-name:Test Case A:, that instance of the test will be displayed in Jenkins as
MyTestMethod.Test Case A.
41 | Colons are used to delimit the test instance name, so the instance name itself must not contain a colon.
42 |
43 |
44 | This option is particularly useful if you store the test case name as part of each data row in the data source. You can then refer to
45 | the name in the test itself:
46 |
47 |
Console.WriteLine(String.Format("test-instance-name:{0}:", data_row("TestCaseName")))
48 |
49 | You could also use the values of the input parameters themselves as the test instance name:
50 |
51 |
Console.WriteLine(String.Format("test-instance-name:{0}, {1}:", data_row("param1"), data_row("param2")))
52 |
53 | Note that if you don't specify a
test-instance-name, then data driven tests are automatically given a suffix based on
54 | the data row ID (such as "row 3"), similar to what is displayed in Visual Studio.
55 |
56 |
57 | Be aware that TRX files generated by vstest.console.exe differ slightly from those generated by mstest, and these differences
58 | affect how data-driven test names appear in test reports. Specifically, data-driven tests appear with their data
59 | row number, even if you append a test instance name. For example, an instance of the test MyTestMethod with the instance
60 | name Test Case A will be displayed as MyTestMethod.Test Case A if the TRX file was generated by mstest, and
61 | as MyTestMethod (Data Row 0).Test Case A if the TRX file was generated by vstest.console.exe.
62 |
63 |
64 |
Omitting a test from the test report
65 |
66 | You may want a test to be removed from the test report. This is useful in some data-driven test scenarios. For example, consider a
67 | set of input parameters in a data source, each of which will be provided to multiple tests. Some inputs may not apply to certain tests.
68 | The testing framework will run each test against every available data row, even if the input doesn't apply to a particular test. Removing
69 | irrelevant test cases from the test report is cleaner and gives more accurate statistics. The syntax to omit a test is similar to other
70 | reporting options:
71 |
72 |
73 |
74 | Like the other reporting options, this must be the first line of text written to stdout during the execution of the test you want to filter
75 | from the test report.
76 |
77 |
Example
78 |
79 | Here is an example of how this capability might be used. Consider a data source with the following data:
80 |
81 |
82 | | TestCaseName | Param1 | ExpectedResult1 | ExpectedResult2 |
83 | | Case A | "Input1" | 3.1 | 1.7 |
84 | | Case B | "Input2" | 0.9 | 1.0 |
85 | | Case C | "Input3" | 4.2 | |
86 |
87 |
88 | In this example, Test1 applies to all 3 data rows, with the expected result specified as ExpectedResult1. Test2, however, only applies
89 | to the first 2 data rows; the test does not apply to Case C, as indicated by the blank ExpectedResult2 for that data row. The Test2 test
90 | method will need to recognize which test cases to ignore, and write reporting instructions accordingly:
91 |
92 |
93 | [DataSource("blah blah blah")]
94 | [TestMethod()]
95 | public void Test2()
96 | {
97 | if (testContext.DataRow("ExpectedResult2") == null) {
98 | Console.WriteLine("omit-from-jenkins:true");
99 | return;
100 | }
101 |
102 | Console.WriteLine(String.Format("test-instance-name:{0}:", testContext.DataRow("TestCaseName")));
103 | // do test logic
104 | ...
105 | }
106 |
107 |
108 |
109 |
Renaming a test
110 |
111 | You may want a test to appear in Jenkins with a different name than the name of the test method, possibly to provide a more
112 | readable name than the name of the test method. To change a test's display name, write the following line as the first text
113 | written to stdout during the test's execution:
114 |
115 |
test-alternate-name:{alternate name}:
116 |
117 | Replace "{alternate name}" with whatever text you want to use as the name of the test in Jenkins reports. For example,
118 |
test-alternate-name:My Test: will be displayed in Jenkins as
My Test, regardless of the name
119 | of the test's test method. Colons are used to delimit the alternate test name, so the alternate name itself must not contain
120 | a colon.
121 |
122 |
123 | The test-alternate-name option may not be combined with any other reporting option. If you want to rename a
124 | test and append a suffix, include the suffix in the name supplied to the test-alternate-name directive.
125 |
126 |
127 |
128 |
129 |
130 |
--------------------------------------------------------------------------------
/src/test/java/hudson/plugins/mstest/MSTestPublisherTest.java:
--------------------------------------------------------------------------------
1 | package hudson.plugins.mstest;
2 |
3 | import hudson.EnvVars;
4 | import hudson.FilePath;
5 | import hudson.Launcher;
6 | import hudson.model.AbstractProject;
7 | import hudson.model.Action;
8 | import hudson.model.Result;
9 | import hudson.model.Run;
10 | import hudson.model.TaskListener;
11 | import hudson.tasks.junit.TestResult;
12 | import hudson.tasks.junit.TestResultAction;
13 | import hudson.tasks.test.TestResultProjectAction;
14 |
15 | import static org.junit.jupiter.api.Assertions.assertEquals;
16 | import static org.junit.jupiter.api.Assertions.assertNotNull;
17 |
18 | import java.io.ByteArrayOutputStream;
19 | import java.io.File;
20 | import java.io.FileOutputStream;
21 | import java.io.InputStream;
22 | import java.io.PrintStream;
23 | import java.util.GregorianCalendar;
24 |
25 | import org.jenkinsci.plugins.workflow.cps.CpsFlowDefinition;
26 | import org.jenkinsci.plugins.workflow.job.WorkflowJob;
27 | import org.jenkinsci.plugins.workflow.job.WorkflowRun;
28 | import org.jmock.Expectations;
29 | import org.jmock.Mockery;
30 | import org.junit.After;
31 | import org.junit.Assert;
32 | import org.junit.Before;
33 | import org.junit.Ignore;
34 | import org.junit.Rule;
35 | import org.junit.Test;
36 | import org.jvnet.hudson.test.JenkinsRule;
37 | import org.springframework.util.FileCopyUtils;
38 |
39 | /**
40 | * Unit tests for MSTestPublisher class
41 | *
42 | * @author Antonio Marques
43 | */
44 | public class MSTestPublisherTest extends TestHelper {
45 |
46 | @Rule
47 | public JenkinsRule j = new JenkinsRule();
48 |
49 | private Mockery classContext;
50 | private AbstractProject project;
51 | private TaskListener buildListener;
52 | private Run, ?> run;
53 |
54 | @Before
55 | public void setUp() throws Exception {
56 | createWorkspace();
57 | classContext = getClassMock();
58 | project = classContext.mock(AbstractProject.class);
59 | buildListener = classContext.mock(TaskListener.class);
60 | run = classContext.mock(Run.class);
61 | }
62 |
63 | @After
64 | public void tearDown() throws Exception {
65 | deleteWorkspace();
66 | }
67 |
68 | private MSTestPublisher getTestedPublisher(String pattern) {
69 | MSTestPublisher publisher = new MSTestPublisher();
70 | publisher.setTestResultsFile(pattern);
71 | publisher.setFailOnError(false);
72 | publisher.setKeepLongStdio(false);
73 | return publisher;
74 | }
75 |
76 | @Test
77 | public void testGetProjectActionProjectReusing() {
78 | classContext.checking(new Expectations() {
79 | {
80 | oneOf(project).getAction(with(equal(TestResultProjectAction.class)));
81 | will(returnValue(new TestResultProjectAction(project)));
82 | }
83 | });
84 | MSTestPublisher publisher = getTestedPublisher("build.trx");
85 | Action projectAction = publisher.getProjectAction(project);
86 | Assert.assertNull("The action was not null", projectAction);
87 | }
88 |
89 | @Test
90 | public void testGetProjectActionProject() {
91 | classContext.checking(new Expectations() {
92 | {
93 | oneOf(project).getAction(with(equal(TestResultProjectAction.class)));
94 | will(returnValue(null));
95 | }
96 | });
97 | MSTestPublisher publisher = getTestedPublisher("build.trx");
98 | Action projectAction = publisher.getProjectAction(project);
99 | Assert.assertNotNull("The action was null", projectAction);
100 | Assert.assertEquals("The action type is incorrect", TestResultProjectAction.class,
101 | projectAction.getClass());
102 | }
103 |
104 | @Test
105 | public void testNoFileMatchingPattern() throws Exception {
106 | classContext.checking(new Expectations() {
107 | {
108 | oneOf(run).getEnvironment(with(equal(buildListener)));
109 | will(returnValue(new EnvVars()));
110 | }
111 | });
112 | classContext.checking(new Expectations() {
113 | {
114 | ignoring(buildListener).getLogger();
115 | will(returnValue(new PrintStream(new ByteArrayOutputStream())));
116 | oneOf(buildListener).fatalError(with(any(String.class)));
117 | }
118 | });
119 | File subfolder = new File(parentFile, "subfolder");
120 | assert subfolder.exists() || subfolder.mkdirs();
121 | File testFile = new File(subfolder, "xmlentities-forged.trx");
122 | assert !testFile.exists() || testFile.delete();
123 | InputStream testStream = this.getClass()
124 | .getResourceAsStream("JENKINS-23531-xmlentities-forged.trx");
125 | FileCopyUtils.copy(testStream, new FileOutputStream(testFile));
126 | String[] results = MSTestPublisher
127 | .resolveTestReports("*.trx", run, workspace, buildListener);
128 | Assert.assertEquals(0, results.length);
129 | }
130 |
131 | @Ignore
132 | @Test
133 | public void testComplete() throws Exception {
134 | classContext.checking(new Expectations() {
135 | {
136 | ignoring(run).getEnvironment(with(equal(buildListener)));
137 | will(returnValue(new EnvVars()));
138 | }
139 | });
140 | classContext.checking(new Expectations() {
141 | {
142 | ignoring(run).getTimestamp();
143 | GregorianCalendar c = new GregorianCalendar();
144 | c.setTimeInMillis(0L);
145 | will(returnValue(c));
146 | }
147 | });
148 | classContext.checking(new Expectations() {
149 | {
150 | ignoring(buildListener).getLogger();
151 | will(returnValue(new PrintStream(new ByteArrayOutputStream())));
152 | oneOf(buildListener).fatalError(with(any(String.class)));
153 | }
154 | });
155 | classContext.checking(new Expectations() {
156 | {
157 | oneOf(run).getAction(with(equal(TestResultAction.class)));
158 | will(returnValue(null));
159 | }
160 | });
161 | classContext.checking(new Expectations() {
162 | {
163 | oneOf(run).getPreviousBuild();
164 | will(returnValue(null));
165 | }
166 | });
167 | classContext.checking(new Expectations() {
168 | {
169 | oneOf(run).getNumber();
170 | will(returnValue(1));
171 | }
172 | });
173 | classContext.checking(new Expectations() {
174 | {
175 | new TestResultAction(with(run), with(new TestResult()), with(buildListener));
176 | will(returnValue(new TestResultAction(run, null, buildListener)));
177 | }
178 | });
179 |
180 | File subfolder = new File(parentFile, "subfolder");
181 | assert subfolder.exists() || subfolder.mkdirs();
182 | File testFile = new File(subfolder, "xmlentities-forged.trx");
183 | assert !testFile.exists() || testFile.delete();
184 | InputStream testStream = this.getClass()
185 | .getResourceAsStream("JENKINS-23531-xmlentities-forged.trx");
186 | FileCopyUtils.copy(testStream, new FileOutputStream(testFile));
187 | MSTestPublisher publisher = getTestedPublisher("**/*.trx");
188 | Launcher launcher = classContext.mock(Launcher.class);
189 | publisher.perform(run, workspace, launcher, buildListener);
190 | }
191 |
192 | @Test
193 | public void simplePipelinePublishing() throws Exception {
194 | WorkflowJob job = j.createProject(WorkflowJob.class, "simplePipelinePublishing");
195 | FilePath ws = j.jenkins.getWorkspaceFor(job);
196 |
197 | FilePath testFile = ws.child("build.trx");
198 | testFile.copyFrom(this.getClass().getResourceAsStream("webTestResult.trx"));
199 |
200 | job.setDefinition(new CpsFlowDefinition("node {\n" +
201 | " mstest(testResultsFile: 'build.trx')" +
202 | "}\n", true
203 | ));
204 | WorkflowRun r = j.waitForCompletion(job.scheduleBuild2(0).waitForStart());
205 | j.assertBuildStatus(Result.SUCCESS, r);
206 |
207 | // Asser action
208 | TestResultAction action = r.getAction(TestResultAction.class);
209 | assertNotNull(action);
210 | assertEquals(1, action.getTotalCount());
211 | assertEquals(0, action.getSkipCount());
212 | assertEquals(0, action.getFailCount());
213 | }
214 |
215 | }
216 |
--------------------------------------------------------------------------------
/src/main/resources/hudson/plugins/mstest/mstest-to-junit.xsl:
--------------------------------------------------------------------------------
1 |
2 |