Initial commit
This commit is contained in:
commit
da53dbf3d6
75 changed files with 2776 additions and 0 deletions
74
src/bld/java/rife/bld/extension/TestNgOperationBuild.java
Normal file
74
src/bld/java/rife/bld/extension/TestNgOperationBuild.java
Normal file
|
@ -0,0 +1,74 @@
|
|||
package rife.bld.extension;
|
||||
|
||||
import rife.bld.BuildCommand;
|
||||
import rife.bld.Project;
|
||||
import rife.bld.publish.PublishDeveloper;
|
||||
import rife.bld.publish.PublishLicense;
|
||||
import rife.bld.publish.PublishScm;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
import static rife.bld.dependencies.Repository.MAVEN_CENTRAL;
|
||||
import static rife.bld.dependencies.Repository.RIFE2_RELEASES;
|
||||
import static rife.bld.dependencies.Scope.*;
|
||||
import static rife.bld.operations.JavadocOptions.DocLinkOption.NO_MISSING;
|
||||
|
||||
public class TestNgOperationBuild extends Project {
|
||||
public TestNgOperationBuild() {
|
||||
pkg = "rife.bld.extension";
|
||||
name = "bld-testng";
|
||||
version = version(0, 9, 0, "SNAPSHOT");
|
||||
|
||||
javaRelease = 17;
|
||||
downloadSources = true;
|
||||
autoDownloadPurge = true;
|
||||
repositories = List.of(MAVEN_CENTRAL, RIFE2_RELEASES);
|
||||
|
||||
var rife2 = version(1, 7, 0);
|
||||
scope(compile)
|
||||
.include(dependency("com.uwyn.rife2", "rife2", rife2))
|
||||
.include(dependency("com.uwyn.rife2", "bld", rife2));
|
||||
|
||||
scope(test)
|
||||
.include(dependency("org.testng", "testng", version(7, 8, 0)))
|
||||
.include(dependency("org.junit.jupiter", "junit-jupiter", version(5, 10, 0)))
|
||||
.include(dependency("org.junit.platform", "junit-platform-console-standalone", version(1, 10, 0)))
|
||||
.include(dependency("org.assertj:assertj-joda-time:2.2.0"));
|
||||
|
||||
javadocOperation()
|
||||
.javadocOptions()
|
||||
.docLint(NO_MISSING)
|
||||
.link("https://rife2.github.io/rife2/");
|
||||
|
||||
publishOperation()
|
||||
// .repository(MAVEN_LOCAL)
|
||||
.repository(version.isSnapshot() ? repository("rife2-snapshot") : repository("rife2"))
|
||||
.info()
|
||||
.groupId("com.uwyn.rife2")
|
||||
.artifactId("bld-testng")
|
||||
.description("bld Extension to execute tests with TestNG")
|
||||
.url("https://github.com/rife2/bld-testng")
|
||||
.developer(new PublishDeveloper().id("ethauvin").name("Erik C. Thauvin").email("erik@thauvin.net")
|
||||
.url("https://erik.thauvin.net/"))
|
||||
.license(new PublishLicense().name("The Apache License, Version 2.0")
|
||||
.url("http://www.apache.org/licenses/LICENSE-2.0.txt"))
|
||||
.scm(new PublishScm().connection("scm:git:https://github.com/rife2/bld-testng.git")
|
||||
.developerConnection("scm:git:git@github.com:rife2/bld-testng.git")
|
||||
.url("https://github.com/rife2/bld-testng"))
|
||||
.signKey(property("sign.key"))
|
||||
.signPassphrase(property("sign.passphrase"));
|
||||
}
|
||||
|
||||
public static void main(String[] args) {
|
||||
new TestNgOperationBuild().start(args);
|
||||
}
|
||||
|
||||
@BuildCommand(summary = "Runs PMD analysis")
|
||||
public void pmd() throws Exception {
|
||||
new PmdOperation()
|
||||
.fromProject(this)
|
||||
.failOnViolation(true)
|
||||
.ruleSets("config/pmd.xml")
|
||||
.execute();
|
||||
}
|
||||
}
|
278
src/main/java/rife/bld/extension/TestNgOperation.java
Normal file
278
src/main/java/rife/bld/extension/TestNgOperation.java
Normal file
|
@ -0,0 +1,278 @@
|
|||
package rife.bld.extension;
|
||||
|
||||
import rife.bld.BaseProject;
|
||||
import rife.bld.operations.AbstractProcessOperation;
|
||||
|
||||
import java.io.File;
|
||||
import java.nio.file.Files;
|
||||
import java.io.IOException;
|
||||
import java.nio.file.Path;
|
||||
import java.nio.file.Paths;
|
||||
import java.util.*;
|
||||
import java.util.concurrent.ConcurrentHashMap;
|
||||
import java.util.logging.Level;
|
||||
import java.util.logging.Logger;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
/**
|
||||
* Run tests with <a href="https;//testng.org/">TestNG</a>.
|
||||
*
|
||||
* @author <a href="https://erik.thauvin.net/">Erik C. Thauvin</a>
|
||||
* @since 1.0
|
||||
*/
|
||||
@SuppressWarnings("PMD.TestClassWithoutTestCases")
|
||||
public class TestNgOperation extends AbstractProcessOperation<TestNgOperation> {
|
||||
private static final Logger LOGGER = Logger.getLogger(TestNgOperation.class.getName());
|
||||
private final List<String> args = new ArrayList<>();
|
||||
private final Map<String, String> options = new ConcurrentHashMap<>();
|
||||
private final List<String> packages = new ArrayList<>();
|
||||
private final List<String> suites = new ArrayList<>();
|
||||
private BaseProject project;
|
||||
|
||||
/**
|
||||
* This sets the default maximum number of threads to use for data providers when running tests in parallel.
|
||||
* It will only take effect if the parallel mode has been selected (for example, with the parallel option).
|
||||
* This can be overridden in the suite definition.
|
||||
*/
|
||||
public TestNgOperation dataProviderThreadCount(int count) {
|
||||
options.put("-dataproviderthreadcount", String.valueOf(count));
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* The directory where the reports will be generated (defaults to {@code build/test-output}).
|
||||
*/
|
||||
public TestNgOperation directory(String directoryPath) {
|
||||
options.put("-d", directoryPath);
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* The list of groups you want to be excluded from this run.
|
||||
*/
|
||||
public TestNgOperation excludeGroups(String... group) {
|
||||
options.put("-excludegroups", String.join(",", group));
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Part of the {@link #execute} operation, constructs the command list
|
||||
* to use for building the process.
|
||||
*
|
||||
* @since 1.5
|
||||
*/
|
||||
@Override
|
||||
protected List<String> executeConstructProcessCommandList() {
|
||||
if (project == null) {
|
||||
LOGGER.severe("A project must be specified.");
|
||||
} else if (packages.isEmpty() && suites.isEmpty()) {
|
||||
LOGGER.severe("At least one suite or package is required.");
|
||||
}
|
||||
|
||||
if (!options.containsKey("-d")) {
|
||||
options.put("d", Path.of(project.buildDirectory().getPath(), "test-output").toString());
|
||||
}
|
||||
|
||||
args.clear();
|
||||
args.add(javaTool());
|
||||
args.add("-cp");
|
||||
args.add(String.format("%s:%s:%s", Path.of(project.libTestDirectory().getPath(), "*"),
|
||||
project.buildMainDirectory(), project.buildTestDirectory()));
|
||||
args.add("org.testng.TestNG");
|
||||
|
||||
options.forEach((k, v) -> {
|
||||
args.add(k);
|
||||
args.add(v);
|
||||
});
|
||||
|
||||
if (!options.containsKey("-testClass")) {
|
||||
try {
|
||||
var temp = tempFile();
|
||||
try (var bufWriter = Files.newBufferedWriter(Paths.get(temp.getPath()))) {
|
||||
bufWriter.write("<suite name=\"bld Default Suite\" verbose=\"2\"><test name=\"All Packages\"><packages>");
|
||||
for (var p : packages) {
|
||||
bufWriter.write(String.format("<package name=\"%s\"/>", p));
|
||||
}
|
||||
bufWriter.write("</packages></test></suite>");
|
||||
args.add(temp.getPath());
|
||||
}
|
||||
} catch (IOException ioe) {
|
||||
LOGGER.log(Level.SEVERE, "An IO error occurred while accessing the default testng.xml file", ioe);
|
||||
}
|
||||
}
|
||||
|
||||
if (LOGGER.isLoggable(Level.INFO)) {
|
||||
LOGGER.info(String.join(" ", args));
|
||||
}
|
||||
|
||||
return args;
|
||||
}
|
||||
|
||||
/**
|
||||
* Configures a PMD operation from a {@link BaseProject}.
|
||||
*/
|
||||
@Override
|
||||
public TestNgOperation fromProject(BaseProject project) {
|
||||
this.project = project;
|
||||
directory(Path.of(project.buildDirectory().getPath(), "test-output").toString());
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Whether TestNG should continue to execute the remaining tests in the suite or skip them if an @Before* method
|
||||
*/
|
||||
public TestNgOperation failurePolicy(FailurePolicy policy) {
|
||||
options.put("-configfailurepolicy", policy.name().toLowerCase(Locale.getDefault()));
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* The list of groups you want to run (e.g. "{@code "windows", "linux", "regression}").
|
||||
*/
|
||||
public TestNgOperation groups(String... group) {
|
||||
options.put("-groups", String.join(",", group));
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Lets you specify method selectors on the command line.
|
||||
* For example: {@code "com.example.Selector1:3", "com.example.Selector2:2"}
|
||||
*/
|
||||
public TestNgOperation methodSelectors(String... detector) {
|
||||
options.put("-methodselectors", String.join(",", detector));
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Lets you specify individual methods to run.
|
||||
* For example: {@code "com.example.Foo.f1", "com.example.Bar.f2"}
|
||||
*/
|
||||
public TestNgOperation methods(String... method) {
|
||||
options.put("-methods", String.join(",", method));
|
||||
return this;
|
||||
}
|
||||
|
||||
protected Map<String, String> options() {
|
||||
return options;
|
||||
}
|
||||
|
||||
/**
|
||||
* The list of packages to include in this test. For example: {@code "com.example", "test.sample.*"}
|
||||
* If the package name ends with .* then subpackages are included too.
|
||||
*/
|
||||
public TestNgOperation packages(String... name) {
|
||||
packages.addAll(Arrays.stream(name).toList());
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* If specified, sets the default mechanism used to determine how to use parallel threads when running tests.
|
||||
* If not set, default mechanism is not to use parallel threads at all.
|
||||
* This can be overridden in the suite definition.
|
||||
*/
|
||||
|
||||
public TestNgOperation parallel(Parallel mechanism) {
|
||||
options.put("-parallel", mechanism.name().toLowerCase(Locale.getDefault()));
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* The directories where your javadoc annotated test sources are. This option is only necessary
|
||||
* if you are using javadoc type annotations. (e.g. {@code "src/test"} or
|
||||
* {@code "src/test/org/testng/eclipse-plugin", "src/test/org/testng/testng"}).
|
||||
*/
|
||||
public TestNgOperation sourceDir(String... directory) {
|
||||
options.put("-sourcedir", String.join(";", directory));
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* This specifies the suite name for a test suite defined on the command line. This option is ignored if the
|
||||
* suite.xml file or the source code specifies a different suite name.
|
||||
*/
|
||||
public TestNgOperation suiteName(String name) {
|
||||
options.put("-suitename", '"' + name + '"');
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Specifies the suites to run. For example: {@code "testng.xml", "testng2.xml"}
|
||||
*/
|
||||
public void suites(String... suite) {
|
||||
suites.addAll(Arrays.stream(suite).toList());
|
||||
}
|
||||
|
||||
private File tempFile() throws IOException {
|
||||
var temp = File.createTempFile("testng", ".xml");
|
||||
temp.deleteOnExit();
|
||||
return temp;
|
||||
}
|
||||
|
||||
/**
|
||||
* A list of class files separated by commas (e.g. {@code "org.foo.Test1","org.foo.test2"}).
|
||||
*/
|
||||
public TestNgOperation testClass(String... aClass) {
|
||||
options.put("-testclass", String.join(",", aClass));
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Specifies a jar file that contains test classes. If a testng.xml file is found at the root of that jar file,
|
||||
* it will be used, otherwise, all the test classes found in this jar file will be considered test classes.
|
||||
*/
|
||||
public TestNgOperation testJar(String jar) {
|
||||
options.put("-testjar", jar);
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* This specifies the name for a test defined on the command line. This option is ignored if the suite.xml file or
|
||||
* the source code specifies a different test name.
|
||||
*/
|
||||
public TestNgOperation testName(String name) {
|
||||
options.put("-testname", '"' + name + '"');
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Only tests defined in a {@code <test>} tag matching one of these names will be run.
|
||||
*/
|
||||
public TestNgOperation testNames(String... name) {
|
||||
options.put("-testnames", Arrays.stream(name).map(s -> '"' + s + '"').collect(Collectors.joining(",")));
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* This sets the default maximum number of threads to use for running tests in parallel. It will only take effect
|
||||
* if the parallel mode has been selected (for example, with the -parallel option). This can be overridden in the
|
||||
* suite definition.
|
||||
*/
|
||||
public TestNgOperation threadCount(int count) {
|
||||
options.put("-threadcount", String.valueOf(count));
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* This attribute should contain the path to a valid XML file inside the test jar
|
||||
* (e.g. {@code "resources/testng.xml"|). The default is {@code testng.xml}, which means a file called
|
||||
* {@code testng.xml} at the root of the jar file. This option will be ignored unless a test jar is specified.
|
||||
*/
|
||||
public TestNgOperation xmlPathInJar(String path) {
|
||||
options.put("-xmlpathinjar", path);
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Parallel Mechanisms
|
||||
*/
|
||||
public enum Parallel {
|
||||
METHODS, TESTS, CLASSES
|
||||
}
|
||||
|
||||
/**
|
||||
* Failure Policies
|
||||
*/
|
||||
public enum FailurePolicy {
|
||||
SKIP, CONTINUE
|
||||
}
|
||||
}
|
132
src/test/java/rife/bld/extension/TestNgOperationTest.java
Normal file
132
src/test/java/rife/bld/extension/TestNgOperationTest.java
Normal file
|
@ -0,0 +1,132 @@
|
|||
package rife.bld.extension;
|
||||
|
||||
import org.junit.jupiter.api.Test;
|
||||
import rife.bld.Project;
|
||||
import rife.bld.operations.exceptions.ExitStatusException;
|
||||
|
||||
import static org.assertj.core.api.Assertions.assertThat;
|
||||
import static org.assertj.core.api.Assertions.assertThatThrownBy;
|
||||
|
||||
/**
|
||||
* Implements the TestNgOperationTest class.
|
||||
*
|
||||
* @author <a href="https://erik.thauvin.net/">Erik C. Thauvin</a>
|
||||
* @since 1.0
|
||||
*/
|
||||
@SuppressWarnings("PMD.AvoidDuplicateLiterals")
|
||||
class TestNgOperationTest {
|
||||
private static final String BAR = "bar";
|
||||
private static final String FOO = "foo";
|
||||
|
||||
@Test
|
||||
void testClass() {
|
||||
var op = new TestNgOperation().testClass(FOO, BAR);
|
||||
assertThat(op.options().get("-testclass")).isEqualTo(String.format("%s,%s", FOO, BAR));
|
||||
}
|
||||
|
||||
@Test
|
||||
void testDataProviderThreadCount() {
|
||||
var op = new TestNgOperation().dataProviderThreadCount(1);
|
||||
assertThat(op.options().get("-dataproviderthreadcount")).isEqualTo("1");
|
||||
}
|
||||
|
||||
@Test
|
||||
void testDirectory() {
|
||||
var op = new TestNgOperation().directory(FOO);
|
||||
assertThat(op.options().get("-d")).isEqualTo(FOO);
|
||||
}
|
||||
|
||||
@Test
|
||||
void testExcludeGroups() {
|
||||
var op = new TestNgOperation().excludeGroups(FOO, BAR);
|
||||
assertThat(op.options().get("-excludegroups")).isEqualTo(String.format("%s,%s", FOO, BAR));
|
||||
}
|
||||
|
||||
@Test
|
||||
void testExecute() {
|
||||
assertThatThrownBy(() ->
|
||||
new TestNgOperation().fromProject(new Project()).packages("com.example.*").execute())
|
||||
.isInstanceOf(ExitStatusException.class);
|
||||
}
|
||||
|
||||
@Test
|
||||
void testFailurePolicy() {
|
||||
var op = new TestNgOperation().failurePolicy(TestNgOperation.FailurePolicy.CONTINUE);
|
||||
assertThat(op.options().get("-configfailurepolicy")).isEqualTo("continue");
|
||||
|
||||
op = new TestNgOperation().failurePolicy(TestNgOperation.FailurePolicy.SKIP);
|
||||
assertThat(op.options().get("-configfailurepolicy")).isEqualTo("skip");
|
||||
}
|
||||
|
||||
@Test
|
||||
void testGroups() {
|
||||
var op = new TestNgOperation().groups(FOO, BAR);
|
||||
assertThat(op.options().get("-groups")).isEqualTo(String.format("%s,%s", FOO, BAR));
|
||||
}
|
||||
|
||||
@Test
|
||||
void testJar() {
|
||||
var op = new TestNgOperation().testJar(FOO);
|
||||
assertThat(op.options().get("-testjar")).isEqualTo(FOO);
|
||||
}
|
||||
|
||||
@Test
|
||||
void testMethodDetectors() {
|
||||
var op = new TestNgOperation().methodSelectors(FOO, BAR);
|
||||
assertThat(op.options().get("-methodselectors")).isEqualTo(String.format("%s,%s", FOO, BAR));
|
||||
}
|
||||
|
||||
@Test
|
||||
void testMethods() {
|
||||
var op = new TestNgOperation().methods(FOO, BAR);
|
||||
assertThat(op.options().get("-methods")).isEqualTo(String.format("%s,%s", FOO, BAR));
|
||||
}
|
||||
|
||||
@Test
|
||||
void testName() {
|
||||
var op = new TestNgOperation().testName(FOO);
|
||||
assertThat(op.options().get("-testname")).isEqualTo("\"" + FOO + '\"');
|
||||
}
|
||||
|
||||
@Test
|
||||
void testNames() {
|
||||
var ops = new TestNgOperation().testNames(FOO, BAR);
|
||||
assertThat(ops.options().get("-testnames")).isEqualTo(String.format("\"%s\",\"%s\"", FOO, BAR));
|
||||
}
|
||||
|
||||
@Test
|
||||
void testParallel() {
|
||||
var op = new TestNgOperation().parallel(TestNgOperation.Parallel.TESTS);
|
||||
assertThat(op.options().get("-parallel")).isEqualTo("tests");
|
||||
|
||||
op = new TestNgOperation().parallel(TestNgOperation.Parallel.METHODS);
|
||||
assertThat(op.options().get("-parallel")).isEqualTo("methods");
|
||||
|
||||
op = new TestNgOperation().parallel(TestNgOperation.Parallel.CLASSES);
|
||||
assertThat(op.options().get("-parallel")).isEqualTo("classes");
|
||||
}
|
||||
|
||||
@Test
|
||||
void testSourceDir() {
|
||||
var op = new TestNgOperation().sourceDir(FOO, BAR);
|
||||
assertThat(op.options().get("-sourcedir")).isEqualTo(String.format("%s;%s", FOO, BAR));
|
||||
}
|
||||
|
||||
@Test
|
||||
void testSuiteName() {
|
||||
var op = new TestNgOperation().suiteName(FOO);
|
||||
assertThat(op.options().get("-suitename")).isEqualTo("\"" + FOO + '\"');
|
||||
}
|
||||
|
||||
@Test
|
||||
void testThreadCount() {
|
||||
var op = new TestNgOperation().threadCount(1);
|
||||
assertThat(op.options().get("-threadcount")).isEqualTo("1");
|
||||
}
|
||||
|
||||
@Test
|
||||
void testXmlPathInJar() {
|
||||
var op = new TestNgOperation().xmlPathInJar(FOO);
|
||||
assertThat(op.options().get("-xmlpathinjar")).isEqualTo(FOO);
|
||||
}
|
||||
}
|
Loading…
Add table
Add a link
Reference in a new issue