Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Support Java parameterized test cases #302

Merged
merged 1 commit into from
Sep 16, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -48,11 +48,15 @@
return false;
}

public boolean useParameters() {
return false;

Check warning on line 52 in src/main/java/org/jenkinsci/plugins/parallel_test_executor/testmode/JavaClassName.java

View check run for this annotation

ci.jenkins.io / Code Coverage

Not covered line

Line 52 is not covered by tests
}

@Override
@NonNull
public Map<String, TestEntity> 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);
Expand Down Expand Up @@ -90,10 +94,14 @@

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
}

Expand Down
Original file line number Diff line number Diff line change
@@ -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.
* <p>
* Parallelize per java test case including parameters if present.
* </p>
* <p>
* It is also able to estimate tests to run from the workspace content if no historical context could be found.
* </p>
*/
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<TestMode> {
@Override
@NonNull
public String getDisplayName() {
return "By Java test cases with parameters";
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@
/**
* This mode works best with java projects.
* <p>
* Parallelize per java test case.
* Parallelize per java test case ingoring parameters if present.
* </p>
* <p>
* It is also able to estimate tests to run from the workspace content if no historical context could be found.
Expand All @@ -24,13 +24,17 @@ public boolean isSplitByCase() {
return true;
}

@Override public boolean useParameters() {
return false;
}

@Extension
@Symbol("javaTestCase")
public static class DescriptorImpl extends Descriptor<TestMode> {
@Override
@NonNull
public String getDisplayName() {
return "By Java test cases";
return "By Java test cases without parameters";
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
<div>
This mode works best with Java projects.
<p>
Parallelize per Java test case including parameters.
<p>
It is also able to estimate tests (per class) to run from the workspace content if no historical context could be found.
</div>
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
<div>
This mode works best with Java projects.
<p>
Parallelize per Java test case.
Parallelize per Java test case ignoring parameters. If parameters are present they are considered the same test.
<p>
It is also able to estimate tests (per class) to run from the workspace content if no historical context could be found.
</div>
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down Expand Up @@ -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<InclusionExclusionPattern> 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);
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
<?xml version="1.0" encoding="UTF-8"?>
<testsuite name="org.jenkinsci.plugins.parallel_test_executor.Test1" time="112.22" tests="21" errors="0" skipped="0" failures="0">
<testcase name="testCase[param1]" classname="org.jenkinsci.plugins.parallel_test_executor.Test1" time="1.00"/>
<testcase name="testCase[param2]" classname="org.jenkinsci.plugins.parallel_test_executor.Test1" time="1.00"/>
<testcase name="testCase[param3]" classname="org.jenkinsci.plugins.parallel_test_executor.Test1" time="1.00"/>
<testcase name="test1Case2" classname="org.jenkinsci.plugins.parallel_test_executor.Test1" time="2.00"/>
<testcase name="test1Case3" classname="org.jenkinsci.plugins.parallel_test_executor.Test1" time="3.00"/>
<testcase name="test1Case4" classname="org.jenkinsci.plugins.parallel_test_executor.Test1" time="4.00"/>
<testcase name="test1Case5" classname="org.jenkinsci.plugins.parallel_test_executor.Test1" time="5.00"/>
<testcase name="test1Case6" classname="org.jenkinsci.plugins.parallel_test_executor.Test1" time="6.00"/>
<testcase name="test1Case7" classname="org.jenkinsci.plugins.parallel_test_executor.Test1" time="7.00"/>
<testcase name="test1Case8" classname="org.jenkinsci.plugins.parallel_test_executor.Test1" time="8.00"/>
<testcase name="test1Case9" classname="org.jenkinsci.plugins.parallel_test_executor.Test1" time="9.00"/>
<testcase name="test1Case10" classname="org.jenkinsci.plugins.parallel_test_executor.Test1" time="10.00"/>
<testcase name="test1Case11" classname="org.jenkinsci.plugins.parallel_test_executor.Test1" time="1.00"/>
<testcase name="test1Case12" classname="org.jenkinsci.plugins.parallel_test_executor.Test1" time="2.00"/>
<testcase name="test1Case13" classname="org.jenkinsci.plugins.parallel_test_executor.Test1" time="3.00"/>
<testcase name="test1Case14" classname="org.jenkinsci.plugins.parallel_test_executor.Test1" time="4.00"/>
<testcase name="test1Case15" classname="org.jenkinsci.plugins.parallel_test_executor.Test1" time="5.00"/>
<testcase name="test1Case16" classname="org.jenkinsci.plugins.parallel_test_executor.Test1" time="6.00"/>
<testcase name="test1Case17" classname="org.jenkinsci.plugins.parallel_test_executor.Test1" time="7.00"/>
<testcase name="test1Case18" classname="org.jenkinsci.plugins.parallel_test_executor.Test1" time="8.00"/>
<testcase name="test1Case19" classname="org.jenkinsci.plugins.parallel_test_executor.Test1" time="9.00"/>
<testcase name="test1Case20" classname="org.jenkinsci.plugins.parallel_test_executor.Test1" time="10.22"/>
</testsuite>