From 4cf05862b49eaea0ba1746f17f40227b9b03f070 Mon Sep 17 00:00:00 2001 From: Stamatis Zampetakis Date: Tue, 10 Sep 2024 10:54:59 +0200 Subject: [PATCH] Support Java parameterized test cases From maven-surefire-plugin:3.0.0-M6 onwards method filtering (thus parameters) are supported in includesFile and excludesFile. Add new testmode that allows to split and run in parallel Java parameterized tests. The JavaTestCaseName mode is retained for backwards compatibility reasons. --- .../testmode/JavaClassName.java | 16 +++-- .../JavaParameterizedTestCaseName.java | 58 +++++++++++++++++++ .../testmode/JavaTestCaseName.java | 8 ++- .../JavaParameterizedTestCaseName/help.html | 7 +++ .../testmode/JavaTestCaseName/help.html | 2 +- .../ParallelTestExecutorUnitTest.java | 14 +++++ .../report-Test1.xml | 25 ++++++++ 7 files changed, 123 insertions(+), 7 deletions(-) create mode 100644 src/main/java/org/jenkinsci/plugins/parallel_test_executor/testmode/JavaParameterizedTestCaseName.java create mode 100644 src/main/resources/org/jenkinsci/plugins/parallel_test_executor/testmode/JavaParameterizedTestCaseName/help.html create mode 100644 src/test/resources/org/jenkinsci/plugins/parallel_test_executor/ParallelTestExecutorUnitTest/findTestCasesWithParametersIncluded/report-Test1.xml diff --git a/src/main/java/org/jenkinsci/plugins/parallel_test_executor/testmode/JavaClassName.java b/src/main/java/org/jenkinsci/plugins/parallel_test_executor/testmode/JavaClassName.java index 46491891..7f38158e 100644 --- a/src/main/java/org/jenkinsci/plugins/parallel_test_executor/testmode/JavaClassName.java +++ b/src/main/java/org/jenkinsci/plugins/parallel_test_executor/testmode/JavaClassName.java @@ -48,11 +48,15 @@ public boolean isSplitByCase() { return false; } + public boolean useParameters() { + return false; + } + @Override @NonNull public Map getTestEntitiesMap(@NonNull ClassResult classResult) { if (isSplitByCase()) { - return classResult.getChildren().stream().map(JavaTestCase::new).collect(Collectors.toMap(JavaTestCase::getKey, identity(), JavaTestCase::new)); + return classResult.getChildren().stream().map(cr -> new JavaTestCase(cr, useParameters())).collect(Collectors.toMap(JavaTestCase::getKey, identity(), JavaTestCase::new)); } else { TestClass testClass = new TestClass(classResult); return Map.of(testClass.getKey(), testClass); @@ -90,10 +94,14 @@ public String getWord() { private static class JavaTestCase extends TestEntity { private final String output; - private JavaTestCase(CaseResult cr) { + private JavaTestCase(CaseResult cr, boolean useParams) { // Parameterized tests use ${fqdnClassName}#${methodName}[{parametersDescription}] format - // passing parameters to surefire is not supported, so just drop them and will sum durations - this.output = cr.getClassName() + "#" + cr.getName().split("\\[")[0]; + if (useParams) { + this.output = cr.getClassName() + "#" + cr.getName(); + } else { + // Some surefire versions don't support parameters, so just drop them and will sum durations + this.output = cr.getClassName() + "#" + cr.getName().split("\\[")[0]; + } this.duration = (long)(cr.getDuration()*1000); // milliseconds is a good enough precision for us } diff --git a/src/main/java/org/jenkinsci/plugins/parallel_test_executor/testmode/JavaParameterizedTestCaseName.java b/src/main/java/org/jenkinsci/plugins/parallel_test_executor/testmode/JavaParameterizedTestCaseName.java new file mode 100644 index 00000000..b780e1d1 --- /dev/null +++ b/src/main/java/org/jenkinsci/plugins/parallel_test_executor/testmode/JavaParameterizedTestCaseName.java @@ -0,0 +1,58 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to you under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.jenkinsci.plugins.parallel_test_executor.testmode; + +import edu.umd.cs.findbugs.annotations.NonNull; +import hudson.Extension; +import hudson.model.Descriptor; +import org.jenkinsci.Symbol; +import org.kohsuke.stapler.DataBoundConstructor; + +/** + * This mode works best with java projects. + *

+ * Parallelize per java test case including parameters if present. + *

+ *

+ * It is also able to estimate tests to run from the workspace content if no historical context could be found. + *

+ */ +public class JavaParameterizedTestCaseName extends JavaClassName { + @DataBoundConstructor + public JavaParameterizedTestCaseName() { + } + + @Override + public boolean isSplitByCase() { + return true; + } + + @Override + public boolean useParameters() { + return true; + } + + @Extension + @Symbol("javaParamTestCase") + public static class DescriptorImpl extends Descriptor { + @Override + @NonNull + public String getDisplayName() { + return "By Java test cases with parameters"; + } + } +} \ No newline at end of file diff --git a/src/main/java/org/jenkinsci/plugins/parallel_test_executor/testmode/JavaTestCaseName.java b/src/main/java/org/jenkinsci/plugins/parallel_test_executor/testmode/JavaTestCaseName.java index 815f768c..1011dc1e 100644 --- a/src/main/java/org/jenkinsci/plugins/parallel_test_executor/testmode/JavaTestCaseName.java +++ b/src/main/java/org/jenkinsci/plugins/parallel_test_executor/testmode/JavaTestCaseName.java @@ -9,7 +9,7 @@ /** * This mode works best with java projects. *

- * Parallelize per java test case. + * Parallelize per java test case ingoring parameters if present. *

*

* It is also able to estimate tests to run from the workspace content if no historical context could be found. @@ -24,13 +24,17 @@ public boolean isSplitByCase() { return true; } + @Override public boolean useParameters() { + return false; + } + @Extension @Symbol("javaTestCase") public static class DescriptorImpl extends Descriptor { @Override @NonNull public String getDisplayName() { - return "By Java test cases"; + return "By Java test cases without parameters"; } } } diff --git a/src/main/resources/org/jenkinsci/plugins/parallel_test_executor/testmode/JavaParameterizedTestCaseName/help.html b/src/main/resources/org/jenkinsci/plugins/parallel_test_executor/testmode/JavaParameterizedTestCaseName/help.html new file mode 100644 index 00000000..03727b60 --- /dev/null +++ b/src/main/resources/org/jenkinsci/plugins/parallel_test_executor/testmode/JavaParameterizedTestCaseName/help.html @@ -0,0 +1,7 @@ +

+ This mode works best with Java projects. +

+ Parallelize per Java test case including parameters. +

+ It is also able to estimate tests (per class) to run from the workspace content if no historical context could be found. +

diff --git a/src/main/resources/org/jenkinsci/plugins/parallel_test_executor/testmode/JavaTestCaseName/help.html b/src/main/resources/org/jenkinsci/plugins/parallel_test_executor/testmode/JavaTestCaseName/help.html index 9e19f582..828c2f18 100644 --- a/src/main/resources/org/jenkinsci/plugins/parallel_test_executor/testmode/JavaTestCaseName/help.html +++ b/src/main/resources/org/jenkinsci/plugins/parallel_test_executor/testmode/JavaTestCaseName/help.html @@ -1,7 +1,7 @@
This mode works best with Java projects.

- Parallelize per Java test case. + Parallelize per Java test case ignoring parameters. If parameters are present they are considered the same test.

It is also able to estimate tests (per class) to run from the workspace content if no historical context could be found.

diff --git a/src/test/java/org/jenkinsci/plugins/parallel_test_executor/ParallelTestExecutorUnitTest.java b/src/test/java/org/jenkinsci/plugins/parallel_test_executor/ParallelTestExecutorUnitTest.java index d6a60c47..fe7d2189 100644 --- a/src/test/java/org/jenkinsci/plugins/parallel_test_executor/ParallelTestExecutorUnitTest.java +++ b/src/test/java/org/jenkinsci/plugins/parallel_test_executor/ParallelTestExecutorUnitTest.java @@ -11,6 +11,7 @@ import java.util.stream.Collectors; import org.apache.tools.ant.DirectoryScanner; import org.hamcrest.Matchers; +import org.jenkinsci.plugins.parallel_test_executor.testmode.JavaParameterizedTestCaseName; import org.jenkinsci.plugins.parallel_test_executor.testmode.JavaTestCaseName; import org.jenkinsci.plugins.parallel_test_executor.testmode.JavaClassName; import org.jenkinsci.plugins.parallel_test_executor.testmode.TestClassAndCaseName; @@ -152,6 +153,19 @@ public void findTestCasesWithParameters() throws Exception { assertThat(allSplits, hasItem("org.jenkinsci.plugins.parallel_test_executor.Test1#testCase")); } + @Test + public void findTestCasesWithParametersIncluded() throws Exception { + TestResult testResult = new TestResult(0L, scanner, false); + testResult.tally(); + when(action.getResult()).thenReturn(testResult); + CountDrivenParallelism parallelism = new CountDrivenParallelism(3); + List splits = Splitter.findTestSplits(parallelism, new JavaParameterizedTestCaseName(), build, listener, false, null, null); + assertEquals(3, splits.size()); + var allSplits = splits.stream().flatMap(s -> s.getList().stream()).collect(Collectors.toSet()); + assertThat(allSplits, hasSize(22)); + assertThat(allSplits, hasItem("org.jenkinsci.plugins.parallel_test_executor.Test1#testCase[param1]")); + } + @Test public void findTestSplitsInclusions() throws Exception { CountDrivenParallelism parallelism = new CountDrivenParallelism(5); diff --git a/src/test/resources/org/jenkinsci/plugins/parallel_test_executor/ParallelTestExecutorUnitTest/findTestCasesWithParametersIncluded/report-Test1.xml b/src/test/resources/org/jenkinsci/plugins/parallel_test_executor/ParallelTestExecutorUnitTest/findTestCasesWithParametersIncluded/report-Test1.xml new file mode 100644 index 00000000..cccbb2c1 --- /dev/null +++ b/src/test/resources/org/jenkinsci/plugins/parallel_test_executor/ParallelTestExecutorUnitTest/findTestCasesWithParametersIncluded/report-Test1.xml @@ -0,0 +1,25 @@ + + + + + + + + + + + + + + + + + + + + + + + + +