Browse Source

[junitlauncher] Allow JUnit libraries to be part of the task's classpath instead of mandating it to be part of Ant's runtime classpath

master
Jaikiran Pai 6 years ago
parent
commit
0cb9d22b77
20 changed files with 500 additions and 288 deletions
  1. +1
    -1
      src/main/org/apache/tools/ant/taskdefs/defaults.properties
  2. +0
    -54
      src/main/org/apache/tools/ant/taskdefs/optional/junitlauncher/Constants.java
  3. +50
    -0
      src/main/org/apache/tools/ant/taskdefs/optional/junitlauncher/InVMExecution.java
  4. +94
    -10
      src/main/org/apache/tools/ant/taskdefs/optional/junitlauncher/LauncherSupport.java
  5. +14
    -18
      src/main/org/apache/tools/ant/taskdefs/optional/junitlauncher/StandaloneLauncher.java
  6. +1
    -0
      src/main/org/apache/tools/ant/taskdefs/optional/junitlauncher/TestExecutionContext.java
  7. +2
    -0
      src/main/org/apache/tools/ant/taskdefs/optional/junitlauncher/TestRequest.java
  8. +54
    -0
      src/main/org/apache/tools/ant/taskdefs/optional/junitlauncher/confined/Constants.java
  9. +13
    -39
      src/main/org/apache/tools/ant/taskdefs/optional/junitlauncher/confined/ForkDefinition.java
  10. +76
    -0
      src/main/org/apache/tools/ant/taskdefs/optional/junitlauncher/confined/JUnitLauncherClassPathUtil.java
  11. +96
    -36
      src/main/org/apache/tools/ant/taskdefs/optional/junitlauncher/confined/JUnitLauncherTask.java
  12. +1
    -12
      src/main/org/apache/tools/ant/taskdefs/optional/junitlauncher/confined/LaunchDefinition.java
  13. +13
    -13
      src/main/org/apache/tools/ant/taskdefs/optional/junitlauncher/confined/ListenerDefinition.java
  14. +1
    -1
      src/main/org/apache/tools/ant/taskdefs/optional/junitlauncher/confined/NamedTest.java
  15. +10
    -27
      src/main/org/apache/tools/ant/taskdefs/optional/junitlauncher/confined/SingleTestClass.java
  16. +10
    -24
      src/main/org/apache/tools/ant/taskdefs/optional/junitlauncher/confined/TestClasses.java
  17. +8
    -53
      src/main/org/apache/tools/ant/taskdefs/optional/junitlauncher/confined/TestDefinition.java
  18. +27
    -0
      src/main/org/apache/tools/ant/taskdefs/optional/junitlauncher/confined/package-info.java
  19. +28
    -0
      src/main/org/apache/tools/ant/taskdefs/optional/junitlauncher/package-info.java
  20. +1
    -0
      src/tests/junit/org/apache/tools/ant/taskdefs/optional/junitlauncher/JUnitLauncherTaskTest.java

+ 1
- 1
src/main/org/apache/tools/ant/taskdefs/defaults.properties View File

@@ -161,7 +161,7 @@ jjdoc=org.apache.tools.ant.taskdefs.optional.javacc.JJDoc
jjtree=org.apache.tools.ant.taskdefs.optional.javacc.JJTree jjtree=org.apache.tools.ant.taskdefs.optional.javacc.JJTree
junit=org.apache.tools.ant.taskdefs.optional.junit.JUnitTask junit=org.apache.tools.ant.taskdefs.optional.junit.JUnitTask
junitreport=org.apache.tools.ant.taskdefs.optional.junit.XMLResultAggregator junitreport=org.apache.tools.ant.taskdefs.optional.junit.XMLResultAggregator
junitlauncher=org.apache.tools.ant.taskdefs.optional.junitlauncher.JUnitLauncherTask
junitlauncher=org.apache.tools.ant.taskdefs.optional.junitlauncher.confined.JUnitLauncherTask
native2ascii=org.apache.tools.ant.taskdefs.optional.Native2Ascii native2ascii=org.apache.tools.ant.taskdefs.optional.Native2Ascii
netrexxc=org.apache.tools.ant.taskdefs.optional.NetRexxC netrexxc=org.apache.tools.ant.taskdefs.optional.NetRexxC
propertyfile=org.apache.tools.ant.taskdefs.optional.PropertyFile propertyfile=org.apache.tools.ant.taskdefs.optional.PropertyFile


+ 0
- 54
src/main/org/apache/tools/ant/taskdefs/optional/junitlauncher/Constants.java View File

@@ -1,54 +0,0 @@
/*
* 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.apache.tools.ant.taskdefs.optional.junitlauncher;

/**
* Constants used within the junitlauncher task
*/
final class Constants {

static final int FORK_EXIT_CODE_SUCCESS = 0;
static final int FORK_EXIT_CODE_EXCEPTION = 1;
static final int FORK_EXIT_CODE_TESTS_FAILED = 2;
static final int FORK_EXIT_CODE_TIMED_OUT = 3;

static final String ARG_PROPERTIES = "--properties";
static final String ARG_LAUNCH_DEFINITION = "--launch-definition";


static final String LD_XML_ELM_LAUNCH_DEF = "launch-definition";
static final String LD_XML_ELM_TEST = "test";
static final String LD_XML_ELM_TEST_CLASSES = "test-classes";
static final String LD_XML_ATTR_HALT_ON_FAILURE = "haltOnFailure";
static final String LD_XML_ATTR_OUTPUT_DIRECTORY = "outDir";
static final String LD_XML_ATTR_INCLUDE_ENGINES = "includeEngines";
static final String LD_XML_ATTR_EXCLUDE_ENGINES = "excludeEngines";
static final String LD_XML_ATTR_CLASS_NAME = "classname";
static final String LD_XML_ATTR_METHODS = "methods";
static final String LD_XML_ATTR_PRINT_SUMMARY = "printSummary";
static final String LD_XML_ELM_LISTENER = "listener";
static final String LD_XML_ATTR_SEND_SYS_ERR = "sendSysErr";
static final String LD_XML_ATTR_SEND_SYS_OUT = "sendSysOut";
static final String LD_XML_ATTR_LISTENER_RESULT_FILE = "resultFile";


private Constants() {

}
}

+ 50
- 0
src/main/org/apache/tools/ant/taskdefs/optional/junitlauncher/InVMExecution.java View File

@@ -0,0 +1,50 @@
/*
* 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.apache.tools.ant.taskdefs.optional.junitlauncher;

import org.apache.tools.ant.Project;
import org.apache.tools.ant.taskdefs.optional.junitlauncher.confined.JUnitLauncherTask;

import java.util.Optional;
import java.util.Properties;

/**
* Used during in-vm (non-forked mode) launching of tests
*/
public class InVMExecution implements TestExecutionContext {

private final JUnitLauncherTask task;
private final Properties props;

public InVMExecution(final JUnitLauncherTask task) {
this.task = task;
this.props = new Properties();
this.props.putAll(task.getProject().getProperties());
}

@Override
public Properties getProperties() {
return this.props;
}

@Override
public Optional<Project> getProject() {
return Optional.of(this.task.getProject());
}
}

+ 94
- 10
src/main/org/apache/tools/ant/taskdefs/optional/junitlauncher/LauncherSupport.java View File

@@ -21,12 +21,22 @@ package org.apache.tools.ant.taskdefs.optional.junitlauncher;
import org.apache.tools.ant.BuildException; import org.apache.tools.ant.BuildException;
import org.apache.tools.ant.MagicNames; import org.apache.tools.ant.MagicNames;
import org.apache.tools.ant.Project; import org.apache.tools.ant.Project;
import org.apache.tools.ant.taskdefs.optional.junitlauncher.confined.LaunchDefinition;
import org.apache.tools.ant.taskdefs.optional.junitlauncher.confined.ListenerDefinition;
import org.apache.tools.ant.taskdefs.optional.junitlauncher.confined.NamedTest;
import org.apache.tools.ant.taskdefs.optional.junitlauncher.confined.SingleTestClass;
import org.apache.tools.ant.taskdefs.optional.junitlauncher.confined.TestClasses;
import org.apache.tools.ant.taskdefs.optional.junitlauncher.confined.TestDefinition;
import org.apache.tools.ant.util.FileUtils; import org.apache.tools.ant.util.FileUtils;
import org.apache.tools.ant.util.KeepAliveOutputStream; import org.apache.tools.ant.util.KeepAliveOutputStream;
import org.junit.platform.engine.Filter;
import org.junit.platform.engine.discovery.DiscoverySelectors;
import org.junit.platform.launcher.EngineFilter;
import org.junit.platform.launcher.Launcher; import org.junit.platform.launcher.Launcher;
import org.junit.platform.launcher.LauncherDiscoveryRequest; import org.junit.platform.launcher.LauncherDiscoveryRequest;
import org.junit.platform.launcher.TestExecutionListener; import org.junit.platform.launcher.TestExecutionListener;
import org.junit.platform.launcher.TestPlan; import org.junit.platform.launcher.TestPlan;
import org.junit.platform.launcher.core.LauncherDiscoveryRequestBuilder;
import org.junit.platform.launcher.core.LauncherFactory; import org.junit.platform.launcher.core.LauncherFactory;
import org.junit.platform.launcher.listeners.SummaryGeneratingListener; import org.junit.platform.launcher.listeners.SummaryGeneratingListener;
import org.junit.platform.launcher.listeners.TestExecutionSummary; import org.junit.platform.launcher.listeners.TestExecutionSummary;
@@ -67,23 +77,33 @@ import java.util.concurrent.TimeUnit;
* <p> * <p>
* This class is not thread-safe and isn't expected to be used for launching from * This class is not thread-safe and isn't expected to be used for launching from
* multiple different threads simultaneously. * multiple different threads simultaneously.
* <p>This class is an internal implementation detail of the Ant project and although
* it's a public class, it isn't meant to be used outside of this project. This class
* can be changed, across releases, without any backward compatible guarantees and hence
* shouldn't be used or relied upon outside of this project.
*/ */
class LauncherSupport {
public class LauncherSupport {


private final LaunchDefinition launchDefinition; private final LaunchDefinition launchDefinition;
private final TestExecutionContext testExecutionContext;


private boolean testsFailed; private boolean testsFailed;


/** /**
* Create a {@link LauncherSupport} for the passed {@link LaunchDefinition} * Create a {@link LauncherSupport} for the passed {@link LaunchDefinition}
* *
* @param definition The launch definition which will be used for launching the tests
* @param definition The launch definition which will be used for launching the tests
* @param testExecutionContext The {@link TestExecutionContext} to use for the tests
*/ */
LauncherSupport(final LaunchDefinition definition) {
public LauncherSupport(final LaunchDefinition definition, final TestExecutionContext testExecutionContext) {
if (definition == null) { if (definition == null) {
throw new IllegalArgumentException("Launch definition cannot be null"); throw new IllegalArgumentException("Launch definition cannot be null");
} }
if (testExecutionContext == null) {
throw new IllegalArgumentException("Test execution context cannot be null");
}
this.launchDefinition = definition; this.launchDefinition = definition;
this.testExecutionContext = testExecutionContext;
} }


/** /**
@@ -93,7 +113,7 @@ class LauncherSupport {
* an exception, or if any other exception occurred before or after launching * an exception, or if any other exception occurred before or after launching
* the tests * the tests
*/ */
void launch() throws BuildException {
public void launch() throws BuildException {
final ClassLoader previousClassLoader = Thread.currentThread().getContextClassLoader(); final ClassLoader previousClassLoader = Thread.currentThread().getContextClassLoader();
try { try {
Thread.currentThread().setContextClassLoader(this.launchDefinition.getClassLoader()); Thread.currentThread().setContextClassLoader(this.launchDefinition.getClassLoader());
@@ -162,7 +182,14 @@ class LauncherSupport {
} }
final List<TestRequest> requests = new ArrayList<>(); final List<TestRequest> requests = new ArrayList<>();
for (final TestDefinition test : tests) { for (final TestDefinition test : tests) {
final List<TestRequest> testRequests = test.createTestRequests();
final List<TestRequest> testRequests;
if (test instanceof SingleTestClass) {
testRequests = createTestRequests((SingleTestClass) test);
} else if (test instanceof TestClasses) {
testRequests = createTestRequests((TestClasses) test);
} else {
throw new BuildException("Unexpected test definition type " + test.getClass().getName());
}
if (testRequests == null || testRequests.isEmpty()) { if (testRequests == null || testRequests.isEmpty()) {
continue; continue;
} }
@@ -176,7 +203,7 @@ class LauncherSupport {
final List<ListenerDefinition> applicableListenerElements = test.getListeners().isEmpty() final List<ListenerDefinition> applicableListenerElements = test.getListeners().isEmpty()
? this.launchDefinition.getListeners() : test.getListeners(); ? this.launchDefinition.getListeners() : test.getListeners();
final List<TestExecutionListener> listeners = new ArrayList<>(); final List<TestExecutionListener> listeners = new ArrayList<>();
final Optional<Project> project = this.launchDefinition.getTestExecutionContext().getProject();
final Optional<Project> project = this.testExecutionContext.getProject();
for (final ListenerDefinition applicableListener : applicableListenerElements) { for (final ListenerDefinition applicableListener : applicableListenerElements) {
if (project.isPresent() && !applicableListener.shouldUse(project.get())) { if (project.isPresent() && !applicableListener.shouldUse(project.get())) {
log("Excluding listener " + applicableListener.getClassName() + " since it's not applicable" + log("Excluding listener " + applicableListener.getClassName() + " since it's not applicable" +
@@ -198,7 +225,7 @@ class LauncherSupport {


testRequest.closeUponCompletion(resultFormatter); testRequest.closeUponCompletion(resultFormatter);
// set the execution context // set the execution context
resultFormatter.setContext(this.launchDefinition.getTestExecutionContext());
resultFormatter.setContext(this.testExecutionContext);
// set the destination output stream for writing out the formatted result // set the destination output stream for writing out the formatted result
final java.nio.file.Path resultOutputFile = getListenerOutputFile(testRequest, formatterDefinition); final java.nio.file.Path resultOutputFile = getListenerOutputFile(testRequest, formatterDefinition);
try { try {
@@ -230,7 +257,7 @@ class LauncherSupport {
return Paths.get(test.getOutputDir(), filename); return Paths.get(test.getOutputDir(), filename);
} }
// neither listener nor the test define a output dir, so use basedir of the project // neither listener nor the test define a output dir, so use basedir of the project
final TestExecutionContext testExecutionContext = this.launchDefinition.getTestExecutionContext();
final TestExecutionContext testExecutionContext = this.testExecutionContext;
final String baseDir = testExecutionContext.getProperties().getProperty(MagicNames.PROJECT_BASEDIR); final String baseDir = testExecutionContext.getProperties().getProperty(MagicNames.PROJECT_BASEDIR);
return Paths.get(baseDir, filename); return Paths.get(baseDir, filename);
} }
@@ -270,7 +297,7 @@ class LauncherSupport {
if (hasTestFailures && test.getFailureProperty() != null) { if (hasTestFailures && test.getFailureProperty() != null) {
// if there are test failures and the test is configured to set a property in case // if there are test failures and the test is configured to set a property in case
// of failure, then set the property to true // of failure, then set the property to true
final TestExecutionContext testExecutionContext = this.launchDefinition.getTestExecutionContext();
final TestExecutionContext testExecutionContext = this.testExecutionContext;
if (testExecutionContext.getProject().isPresent()) { if (testExecutionContext.getProject().isPresent()) {
final Project project = testExecutionContext.getProject().get(); final Project project = testExecutionContext.getProject().get();
project.setNewProperty(test.getFailureProperty(), "true"); project.setNewProperty(test.getFailureProperty(), "true");
@@ -351,7 +378,7 @@ class LauncherSupport {
} }


private void log(final String message, final Throwable t, final int level) { private void log(final String message, final Throwable t, final int level) {
final TestExecutionContext testExecutionContext = this.launchDefinition.getTestExecutionContext();
final TestExecutionContext testExecutionContext = this.testExecutionContext;
if (testExecutionContext.getProject().isPresent()) { if (testExecutionContext.getProject().isPresent()) {
testExecutionContext.getProject().get().log(message, t, level); testExecutionContext.getProject().get().log(message, t, level);
return; return;
@@ -364,6 +391,63 @@ class LauncherSupport {
} }
} }



private List<TestRequest> createTestRequests(final TestDefinition test) {
// create a TestRequest and add necessary selectors, filters to it
final LauncherDiscoveryRequestBuilder requestBuilder = LauncherDiscoveryRequestBuilder.request();
final TestRequest request = new TestRequest(test, requestBuilder);
addDiscoverySelectors(request);
addFilters(request);
return Collections.singletonList(request);
}

private void addDiscoverySelectors(final TestRequest testRequest) {
final TestDefinition test = testRequest.getOwner();
final LauncherDiscoveryRequestBuilder requestBuilder = testRequest.getDiscoveryRequest();
if (test instanceof SingleTestClass) {
final SingleTestClass singleTestClass = (SingleTestClass) test;
final String[] methods = singleTestClass.getMethods();
if (methods == null) {
requestBuilder.selectors(DiscoverySelectors.selectClass(singleTestClass.getName()));
} else {
// add specific methods
for (final String method : methods) {
requestBuilder.selectors(DiscoverySelectors.selectMethod(singleTestClass.getName(), method));
}
}
return;
}
if (test instanceof TestClasses) {
final TestClasses testClasses = (TestClasses) test;
final List<String> testClassNames = testClasses.getTestClassNames();
if (testClassNames.isEmpty()) {
return;
}
for (final String testClass : testClassNames) {
requestBuilder.selectors(DiscoverySelectors.selectClass(testClass));
}
return;
}
}

/**
* Add necessary {@link Filter JUnit filters} to the {@code testRequest}
*
* @param testRequest The test request
*/
private void addFilters(final TestRequest testRequest) {
final LauncherDiscoveryRequestBuilder requestBuilder = testRequest.getDiscoveryRequest();
// add any engine filters
final String[] enginesToInclude = testRequest.getOwner().getIncludeEngines();
if (enginesToInclude != null && enginesToInclude.length > 0) {
requestBuilder.filters(EngineFilter.includeEngines(enginesToInclude));
}
final String[] enginesToExclude = testRequest.getOwner().getExcludeEngines();
if (enginesToExclude != null && enginesToExclude.length > 0) {
requestBuilder.filters(EngineFilter.excludeEngines(enginesToExclude));
}
}

private enum StreamType { private enum StreamType {
SYS_OUT, SYS_OUT,
SYS_ERR SYS_ERR


+ 14
- 18
src/main/org/apache/tools/ant/taskdefs/optional/junitlauncher/StandaloneLauncher.java View File

@@ -20,6 +20,13 @@ package org.apache.tools.ant.taskdefs.optional.junitlauncher;


import org.apache.tools.ant.BuildException; import org.apache.tools.ant.BuildException;
import org.apache.tools.ant.Project; import org.apache.tools.ant.Project;
import org.apache.tools.ant.taskdefs.optional.junitlauncher.confined.Constants;
import org.apache.tools.ant.taskdefs.optional.junitlauncher.confined.JUnitLauncherTask;
import org.apache.tools.ant.taskdefs.optional.junitlauncher.confined.LaunchDefinition;
import org.apache.tools.ant.taskdefs.optional.junitlauncher.confined.ListenerDefinition;
import org.apache.tools.ant.taskdefs.optional.junitlauncher.confined.SingleTestClass;
import org.apache.tools.ant.taskdefs.optional.junitlauncher.confined.TestClasses;
import org.apache.tools.ant.taskdefs.optional.junitlauncher.confined.TestDefinition;


import javax.xml.stream.XMLInputFactory; import javax.xml.stream.XMLInputFactory;
import javax.xml.stream.XMLStreamReader; import javax.xml.stream.XMLStreamReader;
@@ -37,12 +44,12 @@ import static javax.xml.stream.XMLStreamConstants.END_DOCUMENT;
import static javax.xml.stream.XMLStreamConstants.END_ELEMENT; import static javax.xml.stream.XMLStreamConstants.END_ELEMENT;
import static javax.xml.stream.XMLStreamConstants.START_DOCUMENT; import static javax.xml.stream.XMLStreamConstants.START_DOCUMENT;
import static javax.xml.stream.XMLStreamConstants.START_ELEMENT; import static javax.xml.stream.XMLStreamConstants.START_ELEMENT;
import static org.apache.tools.ant.taskdefs.optional.junitlauncher.Constants.LD_XML_ATTR_HALT_ON_FAILURE;
import static org.apache.tools.ant.taskdefs.optional.junitlauncher.Constants.LD_XML_ATTR_PRINT_SUMMARY;
import static org.apache.tools.ant.taskdefs.optional.junitlauncher.Constants.LD_XML_ELM_LAUNCH_DEF;
import static org.apache.tools.ant.taskdefs.optional.junitlauncher.Constants.LD_XML_ELM_LISTENER;
import static org.apache.tools.ant.taskdefs.optional.junitlauncher.Constants.LD_XML_ELM_TEST;
import static org.apache.tools.ant.taskdefs.optional.junitlauncher.Constants.LD_XML_ELM_TEST_CLASSES;
import static org.apache.tools.ant.taskdefs.optional.junitlauncher.confined.Constants.LD_XML_ATTR_HALT_ON_FAILURE;
import static org.apache.tools.ant.taskdefs.optional.junitlauncher.confined.Constants.LD_XML_ATTR_PRINT_SUMMARY;
import static org.apache.tools.ant.taskdefs.optional.junitlauncher.confined.Constants.LD_XML_ELM_LAUNCH_DEF;
import static org.apache.tools.ant.taskdefs.optional.junitlauncher.confined.Constants.LD_XML_ELM_LISTENER;
import static org.apache.tools.ant.taskdefs.optional.junitlauncher.confined.Constants.LD_XML_ELM_TEST;
import static org.apache.tools.ant.taskdefs.optional.junitlauncher.confined.Constants.LD_XML_ELM_TEST_CLASSES;


/** /**
* Used for launching forked tests from the {@link JUnitLauncherTask}. * Used for launching forked tests from the {@link JUnitLauncherTask}.
@@ -98,8 +105,7 @@ public class StandaloneLauncher {
i = i + numArgsConsumed; i = i + numArgsConsumed;
} }


launchDefinition.setTestExecutionContext(forkedExecution);
final LauncherSupport launcherSupport = new LauncherSupport(launchDefinition);
final LauncherSupport launcherSupport = new LauncherSupport(launchDefinition, forkedExecution);
try { try {
launcherSupport.launch(); launcherSupport.launch();
} catch (Throwable t) { } catch (Throwable t) {
@@ -240,19 +246,9 @@ public class StandaloneLauncher {
return this; return this;
} }


public ForkedLaunch setTestExecutionContext(final TestExecutionContext testExecutionContext) {
this.testExecutionContext = testExecutionContext;
return this;
}

@Override @Override
public ClassLoader getClassLoader() { public ClassLoader getClassLoader() {
return this.getClass().getClassLoader(); return this.getClass().getClassLoader();
} }

@Override
public TestExecutionContext getTestExecutionContext() {
return this.testExecutionContext;
}
} }
} }

+ 1
- 0
src/main/org/apache/tools/ant/taskdefs/optional/junitlauncher/TestExecutionContext.java View File

@@ -18,6 +18,7 @@
package org.apache.tools.ant.taskdefs.optional.junitlauncher; package org.apache.tools.ant.taskdefs.optional.junitlauncher;


import org.apache.tools.ant.Project; import org.apache.tools.ant.Project;
import org.apache.tools.ant.taskdefs.optional.junitlauncher.confined.JUnitLauncherTask;


import java.util.Optional; import java.util.Optional;
import java.util.Properties; import java.util.Properties;


+ 2
- 0
src/main/org/apache/tools/ant/taskdefs/optional/junitlauncher/TestRequest.java View File

@@ -17,6 +17,8 @@
*/ */
package org.apache.tools.ant.taskdefs.optional.junitlauncher; package org.apache.tools.ant.taskdefs.optional.junitlauncher;


import org.apache.tools.ant.taskdefs.optional.junitlauncher.confined.JUnitLauncherTask;
import org.apache.tools.ant.taskdefs.optional.junitlauncher.confined.TestDefinition;
import org.junit.platform.launcher.core.LauncherDiscoveryRequestBuilder; import org.junit.platform.launcher.core.LauncherDiscoveryRequestBuilder;


import java.io.Closeable; import java.io.Closeable;


+ 54
- 0
src/main/org/apache/tools/ant/taskdefs/optional/junitlauncher/confined/Constants.java View File

@@ -0,0 +1,54 @@
/*
* 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.apache.tools.ant.taskdefs.optional.junitlauncher.confined;

/**
* Constants used within the junitlauncher task
*/
public final class Constants {

public static final int FORK_EXIT_CODE_SUCCESS = 0;
public static final int FORK_EXIT_CODE_EXCEPTION = 1;
public static final int FORK_EXIT_CODE_TESTS_FAILED = 2;
public static final int FORK_EXIT_CODE_TIMED_OUT = 3;

public static final String ARG_PROPERTIES = "--properties";
public static final String ARG_LAUNCH_DEFINITION = "--launch-definition";


public static final String LD_XML_ELM_LAUNCH_DEF = "launch-definition";
public static final String LD_XML_ELM_TEST = "test";
public static final String LD_XML_ELM_TEST_CLASSES = "test-classes";
public static final String LD_XML_ATTR_HALT_ON_FAILURE = "haltOnFailure";
public static final String LD_XML_ATTR_OUTPUT_DIRECTORY = "outDir";
public static final String LD_XML_ATTR_INCLUDE_ENGINES = "includeEngines";
public static final String LD_XML_ATTR_EXCLUDE_ENGINES = "excludeEngines";
public static final String LD_XML_ATTR_CLASS_NAME = "classname";
public static final String LD_XML_ATTR_METHODS = "methods";
public static final String LD_XML_ATTR_PRINT_SUMMARY = "printSummary";
public static final String LD_XML_ELM_LISTENER = "listener";
public static final String LD_XML_ATTR_SEND_SYS_ERR = "sendSysErr";
public static final String LD_XML_ATTR_SEND_SYS_OUT = "sendSysOut";
public static final String LD_XML_ATTR_LISTENER_RESULT_FILE = "resultFile";


private Constants() {

}
}

src/main/org/apache/tools/ant/taskdefs/optional/junitlauncher/ForkDefinition.java → src/main/org/apache/tools/ant/taskdefs/optional/junitlauncher/confined/ForkDefinition.java View File

@@ -16,23 +16,16 @@
* *
*/ */


package org.apache.tools.ant.taskdefs.optional.junitlauncher;
package org.apache.tools.ant.taskdefs.optional.junitlauncher.confined;


import org.apache.tools.ant.BuildException; import org.apache.tools.ant.BuildException;
import org.apache.tools.ant.Project; import org.apache.tools.ant.Project;
import org.apache.tools.ant.Task;
import org.apache.tools.ant.launch.AntMain;
import org.apache.tools.ant.taskdefs.optional.junitlauncher.StandaloneLauncher;
import org.apache.tools.ant.types.Commandline; import org.apache.tools.ant.types.Commandline;
import org.apache.tools.ant.types.CommandlineJava; import org.apache.tools.ant.types.CommandlineJava;
import org.apache.tools.ant.types.Environment; import org.apache.tools.ant.types.Environment;
import org.apache.tools.ant.types.Path; import org.apache.tools.ant.types.Path;
import org.apache.tools.ant.types.PropertySet; import org.apache.tools.ant.types.PropertySet;
import org.apache.tools.ant.util.LoaderUtils;
import org.junit.platform.commons.annotation.Testable;
import org.junit.platform.engine.TestEngine;
import org.junit.platform.launcher.core.LauncherFactory;

import java.io.File;


/** /**
* Represents the {@code fork} element within test definitions of the * Represents the {@code fork} element within test definitions of the
@@ -124,45 +117,26 @@ public class ForkDefinition {
cmdLine.setClassname(StandaloneLauncher.class.getName()); cmdLine.setClassname(StandaloneLauncher.class.getName());
// VM arguments // VM arguments
final Project project = task.getProject(); final Project project = task.getProject();
final Path antRuntimeResourceSources = new Path(project);
final ClassLoader taskClassLoader = task.getClass().getClassLoader();
// Ant runtime classes
if (this.includeAntRuntimeLibraries) { if (this.includeAntRuntimeLibraries) {
addAntRuntimeResourceSource(antRuntimeResourceSources, task, toResourceName(AntMain.class));
addAntRuntimeResourceSource(antRuntimeResourceSources, task, toResourceName(Task.class));
addAntRuntimeResourceSource(antRuntimeResourceSources, task, toResourceName(JUnitLauncherTask.class));
final Path antRuntimeResources = new Path(project);
JUnitLauncherClassPathUtil.addAntRuntimeResourceLocations(antRuntimeResources, taskClassLoader);
final Path classPath = cmdLine.createClasspath(project);
classPath.createPath().append(antRuntimeResources);
} else { } else {
task.log("Excluding Ant runtime libraries from forked JVM classpath", Project.MSG_DEBUG); task.log("Excluding Ant runtime libraries from forked JVM classpath", Project.MSG_DEBUG);
} }
// JUnit platform classes
if (this.includeJUnitPlatformLibraries) { if (this.includeJUnitPlatformLibraries) {
// platform-engine
addAntRuntimeResourceSource(antRuntimeResourceSources, task, toResourceName(TestEngine.class));
// platform-launcher
addAntRuntimeResourceSource(antRuntimeResourceSources, task, toResourceName(LauncherFactory.class));
// platform-commons
addAntRuntimeResourceSource(antRuntimeResourceSources, task, toResourceName(Testable.class));
final Path junitPlatformResources = new Path(project);
JUnitLauncherClassPathUtil.addJUnitPlatformResourceLocations(junitPlatformResources, taskClassLoader);
final Path classPath = cmdLine.createClasspath(project);
classPath.createPath().append(junitPlatformResources);
} else { } else {
task.log("Excluding JUnit platform libraries from forked JVM classpath", Project.MSG_DEBUG); task.log("Excluding JUnit platform libraries from forked JVM classpath", Project.MSG_DEBUG);
} }
final Path classPath = cmdLine.createClasspath(project);
classPath.createPath().append(antRuntimeResourceSources);


return cmdLine; return cmdLine;
} }


private static boolean addAntRuntimeResourceSource(final Path path, final JUnitLauncherTask task, final String resource) {
final File f = LoaderUtils.getResourceSource(task.getClass().getClassLoader(), resource);
if (f == null) {
task.log("Could not locate source of resource " + resource);
return false;
}
task.log("Found source " + f + " of resource " + resource);
path.createPath().setLocation(f);
return true;
}

private static String toResourceName(final Class klass) {
final String name = klass.getName();
return name.replaceAll("\\.", "/") + ".class";
}

} }

+ 76
- 0
src/main/org/apache/tools/ant/taskdefs/optional/junitlauncher/confined/JUnitLauncherClassPathUtil.java View File

@@ -0,0 +1,76 @@
/*
* 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.apache.tools.ant.taskdefs.optional.junitlauncher.confined;

import org.apache.tools.ant.Task;
import org.apache.tools.ant.launch.AntMain;
import org.apache.tools.ant.types.Path;
import org.apache.tools.ant.util.LoaderUtils;

import java.io.File;

/**
*
*/
final class JUnitLauncherClassPathUtil {

private static final String RESOURCE_IN_PLATFORM_ENGINE = "org/junit/platform/engine/TestEngine.class";
private static final String RESOURCE_IN_PLATFORM_LAUNCHER = "org/junit/platform/launcher/core/LauncherFactory.class";
private static final String RESOURCE_IN_PLATFORM_COMMON = "org/junit/platform/commons/annotation/Testable.class";
private static final String RESOURCE_NAME_LAUNCHER_SUPPORT = "org/apache/tools/ant/taskdefs/optional/junitlauncher/LauncherSupport.class";


static void addAntRuntimeResourceLocations(final Path path, final ClassLoader classLoader) {
addResourceLocationToPath(path, classLoader, toResourceName(AntMain.class));
addResourceLocationToPath(path, classLoader, toResourceName(Task.class));
addResourceLocationToPath(path, classLoader, RESOURCE_NAME_LAUNCHER_SUPPORT);
}

static void addLauncherSupportResourceLocation(final Path path, final ClassLoader classLoader) {
addResourceLocationToPath(path, classLoader, RESOURCE_NAME_LAUNCHER_SUPPORT);
}

static void addJUnitPlatformResourceLocations(final Path path, final ClassLoader classLoader) {
// platform-engine
addResourceLocationToPath(path, classLoader, RESOURCE_IN_PLATFORM_ENGINE);
// platform-launcher
addResourceLocationToPath(path, classLoader, RESOURCE_IN_PLATFORM_LAUNCHER);
// platform-commons
addResourceLocationToPath(path, classLoader, RESOURCE_IN_PLATFORM_COMMON);
}

static boolean addResourceLocationToPath(final Path path, final ClassLoader classLoader, final String resource) {
final File f = LoaderUtils.getResourceSource(classLoader, resource);
if (f == null) {
return false;
}
path.createPath().setLocation(f);
return true;
}

static boolean hasJUnitPlatformResources(final ClassLoader cl) {
final File f = LoaderUtils.getResourceSource(cl, RESOURCE_IN_PLATFORM_ENGINE);
return f != null;
}

private static String toResourceName(final Class klass) {
final String name = klass.getName();
return name.replaceAll("\\.", "/") + ".class";
}
}

src/main/org/apache/tools/ant/taskdefs/optional/junitlauncher/JUnitLauncherTask.java → src/main/org/apache/tools/ant/taskdefs/optional/junitlauncher/confined/JUnitLauncherTask.java View File

@@ -15,7 +15,7 @@
* limitations under the License. * limitations under the License.
* *
*/ */
package org.apache.tools.ant.taskdefs.optional.junitlauncher;
package org.apache.tools.ant.taskdefs.optional.junitlauncher.confined;


import org.apache.tools.ant.AntClassLoader; import org.apache.tools.ant.AntClassLoader;
import org.apache.tools.ant.BuildException; import org.apache.tools.ant.BuildException;
@@ -40,13 +40,12 @@ import java.util.ArrayList;
import java.util.Collections; import java.util.Collections;
import java.util.Hashtable; import java.util.Hashtable;
import java.util.List; import java.util.List;
import java.util.Optional;
import java.util.Properties; import java.util.Properties;
import java.util.concurrent.TimeoutException; import java.util.concurrent.TimeoutException;


import static org.apache.tools.ant.taskdefs.optional.junitlauncher.Constants.LD_XML_ATTR_HALT_ON_FAILURE;
import static org.apache.tools.ant.taskdefs.optional.junitlauncher.Constants.LD_XML_ATTR_PRINT_SUMMARY;
import static org.apache.tools.ant.taskdefs.optional.junitlauncher.Constants.LD_XML_ELM_LAUNCH_DEF;
import static org.apache.tools.ant.taskdefs.optional.junitlauncher.confined.Constants.LD_XML_ATTR_HALT_ON_FAILURE;
import static org.apache.tools.ant.taskdefs.optional.junitlauncher.confined.Constants.LD_XML_ATTR_PRINT_SUMMARY;
import static org.apache.tools.ant.taskdefs.optional.junitlauncher.confined.Constants.LD_XML_ELM_LAUNCH_DEF;


/** /**
* An Ant {@link Task} responsible for launching the JUnit platform for running tests. * An Ant {@link Task} responsible for launching the JUnit platform for running tests.
@@ -66,6 +65,10 @@ import static org.apache.tools.ant.taskdefs.optional.junitlauncher.Constants.LD_
*/ */
public class JUnitLauncherTask extends Task { public class JUnitLauncherTask extends Task {


private static final String LAUNCHER_SUPPORT_CLASS_NAME = "org.apache.tools.ant.taskdefs.optional.junitlauncher.LauncherSupport";
private static final String IN_VM_TEST_EXECUTION_CONTEXT_CLASS_NAME = "org.apache.tools.ant.taskdefs.optional.junitlauncher.InVMExecution";
private static final String TEST_EXECUTION_CONTEXT_CLASS_NAME = "org.apache.tools.ant.taskdefs.optional.junitlauncher.TestExecutionContext";

private Path classPath; private Path classPath;
private boolean haltOnFailure; private boolean haltOnFailure;
private String failureProperty; private String failureProperty;
@@ -91,8 +94,7 @@ public class JUnitLauncherTask extends Task {
if (test.getForkDefinition() != null) { if (test.getForkDefinition() != null) {
forkTest(test); forkTest(test);
} else { } else {
final LauncherSupport launcherSupport = new LauncherSupport(new InVMLaunch(Collections.singletonList(test)));
launcherSupport.launch();
launchViaReflection(new InVMLaunch(Collections.singletonList(test)));
} }
} }
} }
@@ -165,14 +167,29 @@ public class JUnitLauncherTask extends Task {
} }
} }


private ClassLoader createClassLoaderForTestExecution() {
if (this.classPath == null) {
return this.getClass().getClassLoader();
private void launchViaReflection(final InVMLaunch launchDefinition) {
final ClassLoader cl = launchDefinition.getClassLoader();
// instantiate a new TestExecutionContext instance using the launch definition's classloader
final Class<?> testExecutionCtxClass;
final Object testExecutionCtx;
try {
testExecutionCtxClass = Class.forName(TEST_EXECUTION_CONTEXT_CLASS_NAME, false, cl);
final Class<?> klass = Class.forName(IN_VM_TEST_EXECUTION_CONTEXT_CLASS_NAME, false, cl);
testExecutionCtx = klass.getConstructor(JUnitLauncherTask.class).newInstance(this);
} catch (Exception e) {
throw new BuildException("Failed to create a test execution context for in-vm tests", e);
}
// instantiate a new LauncherSupport instance using the launch definition's ClassLoader
try {
final Class<?> klass = Class.forName(LAUNCHER_SUPPORT_CLASS_NAME, false, cl);
final Object launcherSupport = klass.getConstructor(LaunchDefinition.class, testExecutionCtxClass)
.newInstance(launchDefinition, testExecutionCtx);
klass.getMethod("launch").invoke(launcherSupport);
} catch (Exception e) {
throw new BuildException("Failed to launch in-vm tests", e);
} }
return new AntClassLoader(this.getClass().getClassLoader(), getProject(), this.classPath, true);
} }



private java.nio.file.Path dumpProjectProperties() throws IOException { private java.nio.file.Path dumpProjectProperties() throws IOException {
final java.nio.file.Path propsPath = Files.createTempFile(null, "properties"); final java.nio.file.Path propsPath = Files.createTempFile(null, "properties");
propsPath.toFile().deleteOnExit(); propsPath.toFile().deleteOnExit();
@@ -312,35 +329,14 @@ public class JUnitLauncherTask extends Task {
return xmlFilePath; return xmlFilePath;
} }


private final class InVMExecution implements TestExecutionContext {

private final Properties props;

InVMExecution() {
this.props = new Properties();
this.props.putAll(JUnitLauncherTask.this.getProject().getProperties());
}

@Override
public Properties getProperties() {
return this.props;
}

@Override
public Optional<Project> getProject() {
return Optional.of(JUnitLauncherTask.this.getProject());
}
}

private final class InVMLaunch implements LaunchDefinition { private final class InVMLaunch implements LaunchDefinition {


private final TestExecutionContext testExecutionContext = new InVMExecution();
private final List<TestDefinition> inVMTests; private final List<TestDefinition> inVMTests;
private final ClassLoader executionCL; private final ClassLoader executionCL;


private InVMLaunch(final List<TestDefinition> inVMTests) { private InVMLaunch(final List<TestDefinition> inVMTests) {
this.inVMTests = inVMTests; this.inVMTests = inVMTests;
this.executionCL = createClassLoaderForTestExecution();
this.executionCL = createInVMExecutionClassLoader();
} }


@Override @Override
@@ -368,9 +364,73 @@ public class JUnitLauncherTask extends Task {
return this.executionCL; return this.executionCL;
} }


private ClassLoader createInVMExecutionClassLoader() {
final Path taskConfiguredClassPath = JUnitLauncherTask.this.classPath;
if (taskConfiguredClassPath == null) {
// no specific classpath configured for the task, so use the classloader
// of this task
return JUnitLauncherTask.class.getClassLoader();
}
// there's a classpath configured for the task.
// we first check if the Ant runtime classpath has JUnit platform classes.
// - if it does, then we use the Ant runtime classpath plus the task's configured classpath
// with the traditional parent first loading.
// - else (i.e. Ant runtime classpath doesn't have JUnit platform classes), then we
// expect/assume the task's configured classpath to have the JUnit platform classes and we
// then create a "overriding" classloader which prefers certain resources (specifically the classes
// from org.apache.tools.ant.taskdefs.optional.junitlauncher package), from the task's
// classpath, even if the Ant's runtime classpath has those resources.
if (JUnitLauncherClassPathUtil.hasJUnitPlatformResources(JUnitLauncherTask.class.getClassLoader())) {
return new AntClassLoader(JUnitLauncherTask.class.getClassLoader(), getProject(), taskConfiguredClassPath, true);
}
final Path cp = new Path(getProject());
cp.add(taskConfiguredClassPath);
// add the Ant runtime resources to this path
JUnitLauncherClassPathUtil.addLauncherSupportResourceLocation(cp, JUnitLauncherTask.class.getClassLoader());
return new TaskConfiguredPathClassLoader(JUnitLauncherTask.class.getClassLoader(), cp, getProject());
}
}

/**
* A {@link ClassLoader}, very similar to the {@link org.apache.tools.ant.util.SplitClassLoader},
* which uses the {@link #TaskConfiguredPathClassLoader(ClassLoader, Path, Project) configured Path}
* to load a class, if the class belongs to the {@code org.apache.tools.ant.taskdefs.optional.junitlauncher}
* package.
* <p>
* While looking for classes belonging to the {@code org.apache.tools.ant.taskdefs.optional.junitlauncher}
* package, this classloader completely ignores Ant runtime classpath, even if that classpath has
* those classes. This allows the users of this classloader to use a custom location and thus more control over
* where these classes reside, when running the {@code junitlauncher} task
*/
private final class TaskConfiguredPathClassLoader extends AntClassLoader {

/**
* @param parent ClassLoader
* @param path Path
* @param project Project
*/
private TaskConfiguredPathClassLoader(ClassLoader parent, Path path, Project project) {
super(parent, project, path, true);
}

// forceLoadClass is not convenient here since it would not
// properly deal with inner classes of these classes.
@Override @Override
public TestExecutionContext getTestExecutionContext() {
return this.testExecutionContext;
protected synchronized Class<?> loadClass(String classname, boolean resolve)
throws ClassNotFoundException {
Class<?> theClass = findLoadedClass(classname);
if (theClass != null) {
return theClass;
}
final String packageName = classname.substring(0, classname.lastIndexOf('.'));
if (packageName.equals("org.apache.tools.ant.taskdefs.optional.junitlauncher")) {
theClass = findClass(classname);
if (resolve) {
resolveClass(theClass);
}
return theClass;
}
return super.loadClass(classname, resolve);
} }
} }
} }

src/main/org/apache/tools/ant/taskdefs/optional/junitlauncher/LaunchDefinition.java → src/main/org/apache/tools/ant/taskdefs/optional/junitlauncher/confined/LaunchDefinition.java View File

@@ -16,7 +16,7 @@
* *
*/ */


package org.apache.tools.ant.taskdefs.optional.junitlauncher;
package org.apache.tools.ant.taskdefs.optional.junitlauncher.confined;


import java.util.List; import java.util.List;


@@ -28,42 +28,31 @@ public interface LaunchDefinition {


/** /**
* @return Returns the {@link TestDefinition tests} that have to be launched * @return Returns the {@link TestDefinition tests} that have to be launched
*
*/ */
List<TestDefinition> getTests(); List<TestDefinition> getTests();


/** /**
* @return Returns the default {@link ListenerDefinition listeners} that will be used * @return Returns the default {@link ListenerDefinition listeners} that will be used
* for the tests, if the {@link #getTests() tests} themselves don't specify any * for the tests, if the {@link #getTests() tests} themselves don't specify any
*
*/ */
List<ListenerDefinition> getListeners(); List<ListenerDefinition> getListeners();


/** /**
* @return Returns true if a summary needs to be printed out after the execution of the * @return Returns true if a summary needs to be printed out after the execution of the
* tests. False otherwise. * tests. False otherwise.
*
*/ */
boolean isPrintSummary(); boolean isPrintSummary();


/** /**
* @return Returns true if any remaining tests launch need to be stopped if any test execution * @return Returns true if any remaining tests launch need to be stopped if any test execution
* failed. False otherwise. * failed. False otherwise.
*
*/ */
boolean isHaltOnFailure(); boolean isHaltOnFailure();


/** /**
* @return Returns the {@link ClassLoader} that has to be used for launching and execution of the * @return Returns the {@link ClassLoader} that has to be used for launching and execution of the
* tests * tests
*
*/ */
ClassLoader getClassLoader(); ClassLoader getClassLoader();


/**
* @return Returns the {@link TestExecutionContext} that will be passed to {@link TestResultFormatter#setContext(TestExecutionContext)
* result formatters} which are applicable during the execution of the tests.
*
*/
TestExecutionContext getTestExecutionContext();
} }

src/main/org/apache/tools/ant/taskdefs/optional/junitlauncher/ListenerDefinition.java → src/main/org/apache/tools/ant/taskdefs/optional/junitlauncher/confined/ListenerDefinition.java View File

@@ -15,7 +15,7 @@
* limitations under the License. * limitations under the License.
* *
*/ */
package org.apache.tools.ant.taskdefs.optional.junitlauncher;
package org.apache.tools.ant.taskdefs.optional.junitlauncher.confined;


import org.apache.tools.ant.Project; import org.apache.tools.ant.Project;
import org.apache.tools.ant.PropertyHelper; import org.apache.tools.ant.PropertyHelper;
@@ -26,11 +26,11 @@ import javax.xml.stream.XMLStreamException;
import javax.xml.stream.XMLStreamReader; import javax.xml.stream.XMLStreamReader;
import javax.xml.stream.XMLStreamWriter; import javax.xml.stream.XMLStreamWriter;


import static org.apache.tools.ant.taskdefs.optional.junitlauncher.Constants.LD_XML_ATTR_CLASS_NAME;
import static org.apache.tools.ant.taskdefs.optional.junitlauncher.Constants.LD_XML_ATTR_LISTENER_RESULT_FILE;
import static org.apache.tools.ant.taskdefs.optional.junitlauncher.Constants.LD_XML_ATTR_SEND_SYS_ERR;
import static org.apache.tools.ant.taskdefs.optional.junitlauncher.Constants.LD_XML_ATTR_SEND_SYS_OUT;
import static org.apache.tools.ant.taskdefs.optional.junitlauncher.Constants.LD_XML_ELM_LISTENER;
import static org.apache.tools.ant.taskdefs.optional.junitlauncher.confined.Constants.LD_XML_ATTR_CLASS_NAME;
import static org.apache.tools.ant.taskdefs.optional.junitlauncher.confined.Constants.LD_XML_ATTR_LISTENER_RESULT_FILE;
import static org.apache.tools.ant.taskdefs.optional.junitlauncher.confined.Constants.LD_XML_ATTR_SEND_SYS_ERR;
import static org.apache.tools.ant.taskdefs.optional.junitlauncher.confined.Constants.LD_XML_ATTR_SEND_SYS_OUT;
import static org.apache.tools.ant.taskdefs.optional.junitlauncher.confined.Constants.LD_XML_ELM_LISTENER;


/** /**
* Represents the {@code &lt;listener&gt;} element within the {@code &lt;junitlauncher&gt;} * Represents the {@code &lt;listener&gt;} element within the {@code &lt;junitlauncher&gt;}
@@ -59,7 +59,7 @@ public class ListenerDefinition {
this.className = className; this.className = className;
} }


String getClassName() {
public String getClassName() {
return this.className; return this.className;
} }


@@ -100,7 +100,7 @@ public class ListenerDefinition {
this.resultFile = filename; this.resultFile = filename;
} }


String requireResultFile(final TestDefinition test) {
public String requireResultFile(final TestDefinition test) {
if (this.resultFile != null) { if (this.resultFile != null) {
return this.resultFile; return this.resultFile;
} }
@@ -125,7 +125,7 @@ public class ListenerDefinition {
this.sendSysOut = sendSysOut; this.sendSysOut = sendSysOut;
} }


boolean shouldSendSysOut() {
public boolean shouldSendSysOut() {
return this.sendSysOut; return this.sendSysOut;
} }


@@ -133,7 +133,7 @@ public class ListenerDefinition {
this.sendSysErr = sendSysErr; this.sendSysErr = sendSysErr;
} }


boolean shouldSendSysErr() {
public boolean shouldSendSysErr() {
return this.sendSysErr; return this.sendSysErr;
} }


@@ -147,11 +147,11 @@ public class ListenerDefinition {
this.outputDir = dir; this.outputDir = dir;
} }


String getOutputDir() {
public String getOutputDir() {
return this.outputDir; return this.outputDir;
} }


protected boolean shouldUse(final Project project) {
public boolean shouldUse(final Project project) {
final PropertyHelper propertyHelper = PropertyHelper.getPropertyHelper(project); final PropertyHelper propertyHelper = PropertyHelper.getPropertyHelper(project);
return propertyHelper.testIfCondition(this.ifProperty) && propertyHelper.testUnlessCondition(this.unlessProperty); return propertyHelper.testIfCondition(this.ifProperty) && propertyHelper.testUnlessCondition(this.unlessProperty);
} }
@@ -175,7 +175,7 @@ public class ListenerDefinition {
writer.writeEndElement(); writer.writeEndElement();
} }


static ListenerDefinition fromForkedRepresentation(final XMLStreamReader reader) throws XMLStreamException {
public static ListenerDefinition fromForkedRepresentation(final XMLStreamReader reader) throws XMLStreamException {
reader.require(XMLStreamConstants.START_ELEMENT, null, LD_XML_ELM_LISTENER); reader.require(XMLStreamConstants.START_ELEMENT, null, LD_XML_ELM_LISTENER);
final ListenerDefinition listenerDef = new ListenerDefinition(); final ListenerDefinition listenerDef = new ListenerDefinition();
final String className = requireAttributeValue(reader, LD_XML_ATTR_CLASS_NAME); final String className = requireAttributeValue(reader, LD_XML_ATTR_CLASS_NAME);

src/main/org/apache/tools/ant/taskdefs/optional/junitlauncher/NamedTest.java → src/main/org/apache/tools/ant/taskdefs/optional/junitlauncher/confined/NamedTest.java View File

@@ -15,7 +15,7 @@
* limitations under the License. * limitations under the License.
* *
*/ */
package org.apache.tools.ant.taskdefs.optional.junitlauncher;
package org.apache.tools.ant.taskdefs.optional.junitlauncher.confined;


/** /**
* A test that has a name associated with it * A test that has a name associated with it

src/main/org/apache/tools/ant/taskdefs/optional/junitlauncher/SingleTestClass.java → src/main/org/apache/tools/ant/taskdefs/optional/junitlauncher/confined/SingleTestClass.java View File

@@ -15,10 +15,7 @@
* limitations under the License. * limitations under the License.
* *
*/ */
package org.apache.tools.ant.taskdefs.optional.junitlauncher;

import org.junit.platform.engine.discovery.DiscoverySelectors;
import org.junit.platform.launcher.core.LauncherDiscoveryRequestBuilder;
package org.apache.tools.ant.taskdefs.optional.junitlauncher.confined;


import javax.xml.stream.XMLStreamConstants; import javax.xml.stream.XMLStreamConstants;
import javax.xml.stream.XMLStreamException; import javax.xml.stream.XMLStreamException;
@@ -29,13 +26,13 @@ import java.util.LinkedHashSet;
import java.util.Set; import java.util.Set;
import java.util.StringTokenizer; import java.util.StringTokenizer;


import static org.apache.tools.ant.taskdefs.optional.junitlauncher.Constants.LD_XML_ATTR_CLASS_NAME;
import static org.apache.tools.ant.taskdefs.optional.junitlauncher.Constants.LD_XML_ATTR_EXCLUDE_ENGINES;
import static org.apache.tools.ant.taskdefs.optional.junitlauncher.Constants.LD_XML_ATTR_HALT_ON_FAILURE;
import static org.apache.tools.ant.taskdefs.optional.junitlauncher.Constants.LD_XML_ATTR_INCLUDE_ENGINES;
import static org.apache.tools.ant.taskdefs.optional.junitlauncher.Constants.LD_XML_ATTR_METHODS;
import static org.apache.tools.ant.taskdefs.optional.junitlauncher.Constants.LD_XML_ATTR_OUTPUT_DIRECTORY;
import static org.apache.tools.ant.taskdefs.optional.junitlauncher.Constants.LD_XML_ELM_TEST;
import static org.apache.tools.ant.taskdefs.optional.junitlauncher.confined.Constants.LD_XML_ATTR_CLASS_NAME;
import static org.apache.tools.ant.taskdefs.optional.junitlauncher.confined.Constants.LD_XML_ATTR_EXCLUDE_ENGINES;
import static org.apache.tools.ant.taskdefs.optional.junitlauncher.confined.Constants.LD_XML_ATTR_HALT_ON_FAILURE;
import static org.apache.tools.ant.taskdefs.optional.junitlauncher.confined.Constants.LD_XML_ATTR_INCLUDE_ENGINES;
import static org.apache.tools.ant.taskdefs.optional.junitlauncher.confined.Constants.LD_XML_ATTR_METHODS;
import static org.apache.tools.ant.taskdefs.optional.junitlauncher.confined.Constants.LD_XML_ATTR_OUTPUT_DIRECTORY;
import static org.apache.tools.ant.taskdefs.optional.junitlauncher.confined.Constants.LD_XML_ELM_TEST;


/** /**
* Represents the single {@code test} (class) that's configured to be launched by the {@link JUnitLauncherTask} * Represents the single {@code test} (class) that's configured to be launched by the {@link JUnitLauncherTask}
@@ -86,27 +83,13 @@ public class SingleTestClass extends TestDefinition implements NamedTest {
return this.testMethods != null && !this.testMethods.isEmpty(); return this.testMethods != null && !this.testMethods.isEmpty();
} }


String[] getMethods() {
public String[] getMethods() {
if (!hasMethodsSpecified()) { if (!hasMethodsSpecified()) {
return null; return null;
} }
return this.testMethods.toArray(new String[this.testMethods.size()]); return this.testMethods.toArray(new String[this.testMethods.size()]);
} }


@Override
void addDiscoverySelectors(final TestRequest testRequest) {
final LauncherDiscoveryRequestBuilder requestBuilder = testRequest.getDiscoveryRequest();
if (!this.hasMethodsSpecified()) {
requestBuilder.selectors(DiscoverySelectors.selectClass(this.testClass));
} else {
// add specific methods
for (final String method : this.getMethods()) {
requestBuilder.selectors(DiscoverySelectors.selectMethod(this.testClass, method));
}
}
}


@Override @Override
protected void toForkedRepresentation(final JUnitLauncherTask task, final XMLStreamWriter writer) throws XMLStreamException { protected void toForkedRepresentation(final JUnitLauncherTask task, final XMLStreamWriter writer) throws XMLStreamException {
writer.writeStartElement(LD_XML_ELM_TEST); writer.writeStartElement(LD_XML_ELM_TEST);
@@ -146,7 +129,7 @@ public class SingleTestClass extends TestDefinition implements NamedTest {
writer.writeEndElement(); writer.writeEndElement();
} }


static TestDefinition fromForkedRepresentation(final XMLStreamReader reader) throws XMLStreamException {
public static TestDefinition fromForkedRepresentation(final XMLStreamReader reader) throws XMLStreamException {
reader.require(XMLStreamConstants.START_ELEMENT, null, LD_XML_ELM_TEST); reader.require(XMLStreamConstants.START_ELEMENT, null, LD_XML_ELM_TEST);
final SingleTestClass testDefinition = new SingleTestClass(); final SingleTestClass testDefinition = new SingleTestClass();
final String testClassName = requireAttributeValue(reader, LD_XML_ATTR_CLASS_NAME); final String testClassName = requireAttributeValue(reader, LD_XML_ATTR_CLASS_NAME);

src/main/org/apache/tools/ant/taskdefs/optional/junitlauncher/TestClasses.java → src/main/org/apache/tools/ant/taskdefs/optional/junitlauncher/confined/TestClasses.java View File

@@ -15,14 +15,12 @@
* limitations under the License. * limitations under the License.
* *
*/ */
package org.apache.tools.ant.taskdefs.optional.junitlauncher;
package org.apache.tools.ant.taskdefs.optional.junitlauncher.confined;


import org.apache.tools.ant.types.Resource; import org.apache.tools.ant.types.Resource;
import org.apache.tools.ant.types.ResourceCollection; import org.apache.tools.ant.types.ResourceCollection;
import org.apache.tools.ant.types.resources.Resources; import org.apache.tools.ant.types.resources.Resources;
import org.apache.tools.ant.types.resources.StringResource; import org.apache.tools.ant.types.resources.StringResource;
import org.junit.platform.engine.discovery.DiscoverySelectors;
import org.junit.platform.launcher.core.LauncherDiscoveryRequestBuilder;


import javax.xml.stream.XMLStreamConstants; import javax.xml.stream.XMLStreamConstants;
import javax.xml.stream.XMLStreamException; import javax.xml.stream.XMLStreamException;
@@ -33,13 +31,13 @@ import java.util.ArrayList;
import java.util.Collections; import java.util.Collections;
import java.util.List; import java.util.List;


import static org.apache.tools.ant.taskdefs.optional.junitlauncher.Constants.LD_XML_ATTR_CLASS_NAME;
import static org.apache.tools.ant.taskdefs.optional.junitlauncher.Constants.LD_XML_ATTR_EXCLUDE_ENGINES;
import static org.apache.tools.ant.taskdefs.optional.junitlauncher.Constants.LD_XML_ATTR_HALT_ON_FAILURE;
import static org.apache.tools.ant.taskdefs.optional.junitlauncher.Constants.LD_XML_ATTR_INCLUDE_ENGINES;
import static org.apache.tools.ant.taskdefs.optional.junitlauncher.Constants.LD_XML_ATTR_OUTPUT_DIRECTORY;
import static org.apache.tools.ant.taskdefs.optional.junitlauncher.Constants.LD_XML_ELM_TEST;
import static org.apache.tools.ant.taskdefs.optional.junitlauncher.Constants.LD_XML_ELM_TEST_CLASSES;
import static org.apache.tools.ant.taskdefs.optional.junitlauncher.confined.Constants.LD_XML_ATTR_CLASS_NAME;
import static org.apache.tools.ant.taskdefs.optional.junitlauncher.confined.Constants.LD_XML_ATTR_EXCLUDE_ENGINES;
import static org.apache.tools.ant.taskdefs.optional.junitlauncher.confined.Constants.LD_XML_ATTR_HALT_ON_FAILURE;
import static org.apache.tools.ant.taskdefs.optional.junitlauncher.confined.Constants.LD_XML_ATTR_INCLUDE_ENGINES;
import static org.apache.tools.ant.taskdefs.optional.junitlauncher.confined.Constants.LD_XML_ATTR_OUTPUT_DIRECTORY;
import static org.apache.tools.ant.taskdefs.optional.junitlauncher.confined.Constants.LD_XML_ELM_TEST;
import static org.apache.tools.ant.taskdefs.optional.junitlauncher.confined.Constants.LD_XML_ELM_TEST_CLASSES;


/** /**
* Represents a {@code testclasses} that's configured to be launched by the {@link JUnitLauncherTask} * Represents a {@code testclasses} that's configured to be launched by the {@link JUnitLauncherTask}
@@ -56,19 +54,7 @@ public class TestClasses extends TestDefinition {
this.resources.add(resourceCollection); this.resources.add(resourceCollection);
} }


@Override
void addDiscoverySelectors(final TestRequest testRequest) {
final List<String> tests = getTestClassNames();
if (tests.isEmpty()) {
return;
}
final LauncherDiscoveryRequestBuilder requestBuilder = testRequest.getDiscoveryRequest();
for (final String test : tests) {
requestBuilder.selectors(DiscoverySelectors.selectClass(test));
}
}

private List<String> getTestClassNames() {
public List<String> getTestClassNames() {
if (this.resources.isEmpty()) { if (this.resources.isEmpty()) {
return Collections.emptyList(); return Collections.emptyList();
} }
@@ -122,7 +108,7 @@ public class TestClasses extends TestDefinition {
writer.writeEndElement(); writer.writeEndElement();
} }


static List<TestDefinition> fromForkedRepresentation(final XMLStreamReader reader) throws XMLStreamException {
public static List<TestDefinition> fromForkedRepresentation(final XMLStreamReader reader) throws XMLStreamException {
reader.require(XMLStreamConstants.START_ELEMENT, null, LD_XML_ELM_TEST_CLASSES); reader.require(XMLStreamConstants.START_ELEMENT, null, LD_XML_ELM_TEST_CLASSES);
final TestClasses testDefinition = new TestClasses(); final TestClasses testDefinition = new TestClasses();
// read out as multiple SingleTestClass representations // read out as multiple SingleTestClass representations

src/main/org/apache/tools/ant/taskdefs/optional/junitlauncher/TestDefinition.java → src/main/org/apache/tools/ant/taskdefs/optional/junitlauncher/confined/TestDefinition.java View File

@@ -15,14 +15,11 @@
* limitations under the License. * limitations under the License.
* *
*/ */
package org.apache.tools.ant.taskdefs.optional.junitlauncher;
package org.apache.tools.ant.taskdefs.optional.junitlauncher.confined;


import org.apache.tools.ant.BuildException; import org.apache.tools.ant.BuildException;
import org.apache.tools.ant.Project; import org.apache.tools.ant.Project;
import org.apache.tools.ant.PropertyHelper; import org.apache.tools.ant.PropertyHelper;
import org.junit.platform.engine.Filter;
import org.junit.platform.launcher.EngineFilter;
import org.junit.platform.launcher.core.LauncherDiscoveryRequestBuilder;


import javax.xml.stream.XMLStreamException; import javax.xml.stream.XMLStreamException;
import javax.xml.stream.XMLStreamWriter; import javax.xml.stream.XMLStreamWriter;
@@ -33,7 +30,7 @@ import java.util.List;
/** /**
* Represents the configuration details of a test that needs to be launched by the {@link JUnitLauncherTask} * Represents the configuration details of a test that needs to be launched by the {@link JUnitLauncherTask}
*/ */
abstract class TestDefinition {
public abstract class TestDefinition {


protected String ifProperty; protected String ifProperty;
protected String unlessProperty; protected String unlessProperty;
@@ -62,7 +59,7 @@ abstract class TestDefinition {
this.unlessProperty = unlessProperty; this.unlessProperty = unlessProperty;
} }


boolean isHaltOnFailure() {
public boolean isHaltOnFailure() {
return this.haltOnFailure != null && this.haltOnFailure; return this.haltOnFailure != null && this.haltOnFailure;
} }


@@ -74,7 +71,7 @@ abstract class TestDefinition {
this.haltOnFailure = haltonfailure; this.haltOnFailure = haltonfailure;
} }


String getFailureProperty() {
public String getFailureProperty() {
return failureProperty; return failureProperty;
} }


@@ -86,7 +83,7 @@ abstract class TestDefinition {
this.listeners.add(listener); this.listeners.add(listener);
} }


List<ListenerDefinition> getListeners() {
public List<ListenerDefinition> getListeners() {
return Collections.unmodifiableList(this.listeners); return Collections.unmodifiableList(this.listeners);
} }


@@ -94,7 +91,7 @@ abstract class TestDefinition {
this.outputDir = dir; this.outputDir = dir;
} }


String getOutputDir() {
public String getOutputDir() {
return this.outputDir; return this.outputDir;
} }


@@ -110,54 +107,12 @@ abstract class TestDefinition {
return this.forkDefinition; return this.forkDefinition;
} }


/**
* Create and return the {@link TestRequest TestRequests} for this test definition. This
* typically involves creating the JUnit test discovery request(s) and applying the necessary
* discovery selectors, filters and other necessary constructs.
*
* @return Returns the test requests
*/
List<TestRequest> createTestRequests() {
// create a TestRequest and add necessary selectors, filters to it
final LauncherDiscoveryRequestBuilder requestBuilder = LauncherDiscoveryRequestBuilder.request();
final TestRequest request = new TestRequest(this, requestBuilder);
addDiscoverySelectors(request);
addFilters(request);
return Collections.singletonList(request);
}

/**
* Add necessary {@link org.junit.platform.engine.DiscoverySelector JUnit discovery selectors} to
* the {@code testRequest}
*
* @param testRequest The test request
*/
abstract void addDiscoverySelectors(final TestRequest testRequest);

/**
* Add necessary {@link Filter JUnit filters} to the {@code testRequest}
*
* @param testRequest The test request
*/
void addFilters(final TestRequest testRequest) {
final LauncherDiscoveryRequestBuilder requestBuilder = testRequest.getDiscoveryRequest();
// add any engine filters
final String[] enginesToInclude = this.getIncludeEngines();
if (enginesToInclude != null && enginesToInclude.length > 0) {
requestBuilder.filters(EngineFilter.includeEngines(enginesToInclude));
}
final String[] enginesToExclude = this.getExcludeEngines();
if (enginesToExclude != null && enginesToExclude.length > 0) {
requestBuilder.filters(EngineFilter.excludeEngines(enginesToExclude));
}
}

protected boolean shouldRun(final Project project) { protected boolean shouldRun(final Project project) {
final PropertyHelper propertyHelper = PropertyHelper.getPropertyHelper(project); final PropertyHelper propertyHelper = PropertyHelper.getPropertyHelper(project);
return propertyHelper.testIfCondition(this.ifProperty) && propertyHelper.testUnlessCondition(this.unlessProperty); return propertyHelper.testIfCondition(this.ifProperty) && propertyHelper.testUnlessCondition(this.unlessProperty);
} }


String[] getIncludeEngines() {
public String[] getIncludeEngines() {
return includeEngines == null ? new String[0] : split(this.includeEngines, ","); return includeEngines == null ? new String[0] : split(this.includeEngines, ",");
} }


@@ -165,7 +120,7 @@ abstract class TestDefinition {
this.includeEngines = includeEngines; this.includeEngines = includeEngines;
} }


String[] getExcludeEngines() {
public String[] getExcludeEngines() {
return excludeEngines == null ? new String[0] : split(this.excludeEngines, ","); return excludeEngines == null ? new String[0] : split(this.excludeEngines, ",");
} }



+ 27
- 0
src/main/org/apache/tools/ant/taskdefs/optional/junitlauncher/confined/package-info.java View File

@@ -0,0 +1,27 @@
/*
* 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.
*
*/
/**
* The classes/interfaces in this package <em>must not</em>
* have any compile time dependency on any of JUnit platform or
* engine classes/interfaces. They <em>must not</em> even have any
* compile time dependency on any classes/interfaces that belong to the
* {@link org.apache.tools.ant.taskdefs.optional.junitlauncher} package.
*
* @since Ant 1.10.6
*/
package org.apache.tools.ant.taskdefs.optional.junitlauncher.confined;

+ 28
- 0
src/main/org/apache/tools/ant/taskdefs/optional/junitlauncher/package-info.java View File

@@ -0,0 +1,28 @@
/*
* 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.
*
*/
/**
* The classes/interfaces in this package are allowed
* to have compile time dependency on JUnit platform classes/interfaces.
* Furthermore classes/interfaces in this package are also
* allowed to have compile time dependency on the
* {@link org.apache.tools.ant.taskdefs.optional.junitlauncher.confined}
* package
*
* @since Ant 1.10.6
*/
package org.apache.tools.ant.taskdefs.optional.junitlauncher;

+ 1
- 0
src/tests/junit/org/apache/tools/ant/taskdefs/optional/junitlauncher/JUnitLauncherTaskTest.java View File

@@ -20,6 +20,7 @@ package org.apache.tools.ant.taskdefs.optional.junitlauncher;
import org.apache.tools.ant.BuildException; import org.apache.tools.ant.BuildException;
import org.apache.tools.ant.BuildFileRule; import org.apache.tools.ant.BuildFileRule;
import org.apache.tools.ant.Project; import org.apache.tools.ant.Project;
import org.apache.tools.ant.taskdefs.optional.junitlauncher.confined.JUnitLauncherTask;
import org.apache.tools.ant.util.LoaderUtils; import org.apache.tools.ant.util.LoaderUtils;
import org.example.junitlauncher.jupiter.JupiterSampleTest; import org.example.junitlauncher.jupiter.JupiterSampleTest;
import org.example.junitlauncher.vintage.AlwaysFailingJUnit4Test; import org.example.junitlauncher.vintage.AlwaysFailingJUnit4Test;


Loading…
Cancel
Save