ant-notifications mailing list archives

Site index · List index
Message view « Date » · « Thread »
Top « Date » · « Thread »
From jaiki...@apache.org
Subject [1/2] ant git commit: Support for fork mode in junitlauncher
Date Fri, 10 Aug 2018 04:49:47 GMT
Repository: ant
Updated Branches:
  refs/heads/master 3f36f0b82 -> c9ca84fd5


http://git-wip-us.apache.org/repos/asf/ant/blob/c9ca84fd/src/main/org/apache/tools/ant/taskdefs/optional/junitlauncher/StandaloneLauncher.java
----------------------------------------------------------------------
diff --git a/src/main/org/apache/tools/ant/taskdefs/optional/junitlauncher/StandaloneLauncher.java
b/src/main/org/apache/tools/ant/taskdefs/optional/junitlauncher/StandaloneLauncher.java
new file mode 100644
index 0000000..7e342cc
--- /dev/null
+++ b/src/main/org/apache/tools/ant/taskdefs/optional/junitlauncher/StandaloneLauncher.java
@@ -0,0 +1,259 @@
+/*
+ *  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.BuildException;
+import org.apache.tools.ant.Project;
+
+import javax.xml.stream.XMLInputFactory;
+import javax.xml.stream.XMLStreamReader;
+import java.io.InputStream;
+import java.nio.file.Files;
+import java.nio.file.Path;
+import java.nio.file.Paths;
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.List;
+import java.util.Optional;
+import java.util.Properties;
+
+import static javax.xml.stream.XMLStreamConstants.END_DOCUMENT;
+import static javax.xml.stream.XMLStreamConstants.END_ELEMENT;
+import static javax.xml.stream.XMLStreamConstants.START_DOCUMENT;
+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;
+
+/**
+ * Used for launching forked tests from the {@link JUnitLauncherTask}.
+ * <p>
+ * Although this class is public, this isn't meant for external use. The contract of what
+ * program arguments {@link #main(String[]) the main method} accepts and how it interprets
it,
+ * is also an internal detail and can change across Ant releases.
+ *
+ * @since Ant 1.10.6
+ */
+public class StandaloneLauncher {
+
+    /**
+     * Entry point to launching the forked test.
+     *
+     * @param args The arguments passed to this program for launching the tests
+     * @throws Exception
+     */
+    public static void main(final String[] args) throws Exception {
+        // The main responsibility of this entry point is to create a LaunchDefinition,
+        // by parsing the passed arguments and then use the LauncherSupport to
+        // LauncherSupport#launch the tests
+        try {
+            ForkedLaunch launchDefinition = null;
+            final ForkedExecution forkedExecution = new ForkedExecution();
+            for (int i = 0; i < args.length; ) {
+                final String arg = args[i];
+                int numArgsConsumed = 1;
+                switch (arg) {
+                    case Constants.ARG_PROPERTIES: {
+                        final Path propsPath = Paths.get(args[i + 1]);
+                        if (!Files.isRegularFile(propsPath)) {
+                            throw new IllegalArgumentException(propsPath + " does not point
to a properties file");
+                        }
+                        final Properties properties = new Properties();
+                        try (final InputStream is = Files.newInputStream(propsPath)) {
+                            properties.load(is);
+                        }
+                        forkedExecution.setProperties(properties);
+                        numArgsConsumed = 2;
+                        break;
+                    }
+                    case Constants.ARG_LAUNCH_DEFINITION: {
+                        final Path launchDefXmlPath = Paths.get(args[i + 1]);
+                        if (!Files.isRegularFile(launchDefXmlPath)) {
+                            throw new IllegalArgumentException(launchDefXmlPath + " does
not point to a launch definition file");
+                        }
+                        launchDefinition = parseLaunchDefinition(launchDefXmlPath);
+                        numArgsConsumed = 2;
+                        break;
+                    }
+                }
+                i = i + numArgsConsumed;
+            }
+
+
+            launchDefinition.setTestExecutionContext(forkedExecution);
+            final LauncherSupport launcherSupport = new LauncherSupport(launchDefinition);
+            try {
+                launcherSupport.launch();
+            } catch (Throwable t) {
+                if (launcherSupport.hasTestFailures()) {
+                    System.exit(Constants.FORK_EXIT_CODE_TESTS_FAILED);
+                    throw t;
+                }
+            }
+            if (launcherSupport.hasTestFailures()) {
+                System.exit(Constants.FORK_EXIT_CODE_TESTS_FAILED);
+                return;
+            }
+            System.exit(Constants.FORK_EXIT_CODE_SUCCESS);
+            return;
+        } catch (Throwable t) {
+            t.printStackTrace();
+            throw t;
+        }
+    }
+
+    private static ForkedLaunch parseLaunchDefinition(final Path pathToLaunchDefXml) {
+        if (pathToLaunchDefXml == null || !Files.isRegularFile(pathToLaunchDefXml)) {
+            throw new IllegalArgumentException(pathToLaunchDefXml + " is not a file");
+        }
+        final ForkedLaunch forkedLaunch = new ForkedLaunch();
+        try (final InputStream is = Files.newInputStream(pathToLaunchDefXml)) {
+            final XMLStreamReader reader = XMLInputFactory.newFactory().createXMLStreamReader(is);
+            reader.require(START_DOCUMENT, null, null);
+            reader.nextTag();
+            reader.require(START_ELEMENT, null, LD_XML_ELM_LAUNCH_DEF);
+            final String haltOnfFailure = reader.getAttributeValue(null, LD_XML_ATTR_HALT_ON_FAILURE);
+            if (haltOnfFailure != null) {
+                forkedLaunch.setHaltOnFailure(Boolean.parseBoolean(haltOnfFailure));
+            }
+            final String printSummary = reader.getAttributeValue(null, LD_XML_ATTR_PRINT_SUMMARY);
+            if (printSummary != null) {
+                forkedLaunch.setPrintSummary(Boolean.parseBoolean(printSummary));
+            }
+            if (haltOnfFailure != null) {
+                forkedLaunch.setHaltOnFailure(Boolean.parseBoolean(haltOnfFailure));
+            }
+            reader.nextTag();
+            reader.require(START_ELEMENT, null, null);
+            final String elementName = reader.getLocalName();
+            switch (elementName) {
+                case LD_XML_ELM_TEST: {
+                    forkedLaunch.addTests(Collections.singletonList(SingleTestClass.fromForkedRepresentation(reader)));
+                    break;
+                }
+                case LD_XML_ELM_TEST_CLASSES: {
+                    forkedLaunch.addTests(TestClasses.fromForkedRepresentation(reader));
+                    break;
+                }
+                case LD_XML_ELM_LISTENER: {
+                    forkedLaunch.addListener(ListenerDefinition.fromForkedRepresentation(reader));
+                    break;
+                }
+            }
+            reader.nextTag();
+            reader.require(END_ELEMENT, null, LD_XML_ELM_LAUNCH_DEF);
+            reader.next();
+            reader.require(END_DOCUMENT, null, null);
+            return forkedLaunch;
+        } catch (Exception e) {
+            throw new BuildException("Failed to construct definition from forked representation",
e);
+        }
+    }
+
+
+    private static final class ForkedExecution implements TestExecutionContext {
+        private Properties properties = new Properties();
+
+        private ForkedExecution() {
+        }
+
+        private ForkedExecution setProperties(final Properties properties) {
+            this.properties = properties;
+            return this;
+        }
+
+        @Override
+        public Properties getProperties() {
+            return this.properties;
+        }
+
+        @Override
+        public Optional<Project> getProject() {
+            // forked execution won't have access to the Ant Project
+            return Optional.empty();
+        }
+    }
+
+    private static final class ForkedLaunch implements LaunchDefinition {
+
+        private boolean printSummary;
+        private boolean haltOnFailure;
+        private TestExecutionContext testExecutionContext;
+        private List<TestDefinition> tests = new ArrayList<>();
+        private List<ListenerDefinition> listeners = new ArrayList<>();
+
+        @Override
+        public List<TestDefinition> getTests() {
+            return this.tests;
+        }
+
+        ForkedLaunch addTests(final List<TestDefinition> tests) {
+            this.tests.addAll(tests);
+            return this;
+        }
+
+        @Override
+        public List<ListenerDefinition> getListeners() {
+            return this.listeners;
+        }
+
+        ForkedLaunch addListener(final ListenerDefinition listener) {
+            this.listeners.add(listener);
+            return this;
+        }
+
+        @Override
+        public boolean isPrintSummary() {
+            return this.printSummary;
+        }
+
+        private ForkedLaunch setPrintSummary(final boolean printSummary) {
+            this.printSummary = printSummary;
+            return this;
+        }
+
+        @Override
+        public boolean isHaltOnFailure() {
+            return this.haltOnFailure;
+        }
+
+        public ForkedLaunch setHaltOnFailure(final boolean haltOnFailure) {
+            this.haltOnFailure = haltOnFailure;
+            return this;
+        }
+
+        public ForkedLaunch setTestExecutionContext(final TestExecutionContext testExecutionContext)
{
+            this.testExecutionContext = testExecutionContext;
+            return this;
+        }
+
+        @Override
+        public ClassLoader getClassLoader() {
+            return this.getClass().getClassLoader();
+        }
+
+        @Override
+        public TestExecutionContext getTestExecutionContext() {
+            return this.testExecutionContext;
+        }
+    }
+}

http://git-wip-us.apache.org/repos/asf/ant/blob/c9ca84fd/src/main/org/apache/tools/ant/taskdefs/optional/junitlauncher/TestClasses.java
----------------------------------------------------------------------
diff --git a/src/main/org/apache/tools/ant/taskdefs/optional/junitlauncher/TestClasses.java
b/src/main/org/apache/tools/ant/taskdefs/optional/junitlauncher/TestClasses.java
index 45d8bf0..cbba484 100644
--- a/src/main/org/apache/tools/ant/taskdefs/optional/junitlauncher/TestClasses.java
+++ b/src/main/org/apache/tools/ant/taskdefs/optional/junitlauncher/TestClasses.java
@@ -21,11 +21,17 @@ import org.apache.tools.ant.types.Resource;
 import org.apache.tools.ant.types.ResourceCollection;
 import org.apache.tools.ant.types.resources.Resources;
 
+import javax.xml.stream.XMLStreamConstants;
+import javax.xml.stream.XMLStreamException;
+import javax.xml.stream.XMLStreamReader;
+import javax.xml.stream.XMLStreamWriter;
 import java.io.File;
 import java.util.ArrayList;
 import java.util.Collections;
 import java.util.List;
 
+import static org.apache.tools.ant.taskdefs.optional.junitlauncher.Constants.LD_XML_ELM_TEST_CLASSES;
+
 /**
  * Represents a {@code testclasses} that's configured to be launched by the {@link JUnitLauncherTask}
  */
@@ -42,14 +48,14 @@ public class TestClasses extends TestDefinition {
     }
 
     @Override
-    List<TestRequest> createTestRequests(final JUnitLauncherTask launcherTask) {
+    List<TestRequest> createTestRequests() {
         final List<SingleTestClass> tests = this.getTests();
         if (tests.isEmpty()) {
             return Collections.emptyList();
         }
         final List<TestRequest> requests = new ArrayList<>();
         for (final SingleTestClass test : tests) {
-            requests.addAll(test.createTestRequests(launcherTask));
+            requests.addAll(test.createTestRequests());
         }
         return requests;
     }
@@ -126,4 +132,26 @@ public class TestClasses extends TestDefinition {
             return TestClasses.this.getExcludeEngines();
         }
     }
+
+    @Override
+    protected void toForkedRepresentation(final JUnitLauncherTask task, final XMLStreamWriter
writer) throws XMLStreamException {
+        writer.writeStartElement(LD_XML_ELM_TEST_CLASSES);
+        // write out as multiple SingleTestClass representations
+        for (final SingleTestClass singleTestClass : getTests()) {
+            singleTestClass.toForkedRepresentation(task, writer);
+        }
+        writer.writeEndElement();
+    }
+
+    static List<TestDefinition> fromForkedRepresentation(final XMLStreamReader reader)
throws XMLStreamException {
+        reader.require(XMLStreamConstants.START_ELEMENT, null, LD_XML_ELM_TEST_CLASSES);
+        final List<TestDefinition> testDefinitions = new ArrayList<>();
+        // read out as multiple SingleTestClass representations
+        while (reader.nextTag() != XMLStreamConstants.END_ELEMENT) {
+            reader.require(XMLStreamConstants.START_ELEMENT, null, Constants.LD_XML_ELM_TEST);
+            testDefinitions.add(SingleTestClass.fromForkedRepresentation(reader));
+        }
+        reader.require(XMLStreamConstants.END_ELEMENT, null, LD_XML_ELM_TEST_CLASSES);
+        return testDefinitions;
+    }
 }

http://git-wip-us.apache.org/repos/asf/ant/blob/c9ca84fd/src/main/org/apache/tools/ant/taskdefs/optional/junitlauncher/TestDefinition.java
----------------------------------------------------------------------
diff --git a/src/main/org/apache/tools/ant/taskdefs/optional/junitlauncher/TestDefinition.java
b/src/main/org/apache/tools/ant/taskdefs/optional/junitlauncher/TestDefinition.java
index 7ca4499..9fe452f 100644
--- a/src/main/org/apache/tools/ant/taskdefs/optional/junitlauncher/TestDefinition.java
+++ b/src/main/org/apache/tools/ant/taskdefs/optional/junitlauncher/TestDefinition.java
@@ -17,9 +17,12 @@
  */
 package org.apache.tools.ant.taskdefs.optional.junitlauncher;
 
+import org.apache.tools.ant.BuildException;
 import org.apache.tools.ant.Project;
 import org.apache.tools.ant.PropertyHelper;
 
+import javax.xml.stream.XMLStreamException;
+import javax.xml.stream.XMLStreamWriter;
 import java.util.ArrayList;
 import java.util.Collections;
 import java.util.List;
@@ -28,6 +31,7 @@ import java.util.List;
  * Represents the configuration details of a test that needs to be launched by the {@link
JUnitLauncherTask}
  */
 abstract class TestDefinition {
+
     protected String ifProperty;
     protected String unlessProperty;
     protected Boolean haltOnFailure;
@@ -35,6 +39,7 @@ abstract class TestDefinition {
     protected String outputDir;
     protected String includeEngines;
     protected String excludeEngines;
+    protected ForkDefinition forkDefinition;
 
     protected List<ListenerDefinition> listeners = new ArrayList<>();
 
@@ -90,7 +95,19 @@ abstract class TestDefinition {
         return this.outputDir;
     }
 
-    abstract List<TestRequest> createTestRequests(final JUnitLauncherTask launcherTask);
+    public ForkDefinition createFork() {
+        if (this.forkDefinition != null) {
+            throw new BuildException("Test definition cannot have more than one fork elements");
+        }
+        this.forkDefinition = new ForkDefinition();
+        return this.forkDefinition;
+    }
+
+    ForkDefinition getForkDefinition() {
+        return this.forkDefinition;
+    }
+
+    abstract List<TestRequest> createTestRequests();
 
     protected boolean shouldRun(final Project project) {
         final PropertyHelper propertyHelper = PropertyHelper.getPropertyHelper(project);
@@ -127,4 +144,7 @@ abstract class TestDefinition {
         }
         return parts.toArray(new String[parts.size()]);
     }
+
+    protected abstract void toForkedRepresentation(JUnitLauncherTask task, XMLStreamWriter
writer) throws XMLStreamException;
+
 }

http://git-wip-us.apache.org/repos/asf/ant/blob/c9ca84fd/src/tests/junit/org/apache/tools/ant/taskdefs/optional/junitlauncher/JUnitLauncherTaskTest.java
----------------------------------------------------------------------
diff --git a/src/tests/junit/org/apache/tools/ant/taskdefs/optional/junitlauncher/JUnitLauncherTaskTest.java
b/src/tests/junit/org/apache/tools/ant/taskdefs/optional/junitlauncher/JUnitLauncherTaskTest.java
index 90754b5..c17ca57 100644
--- a/src/tests/junit/org/apache/tools/ant/taskdefs/optional/junitlauncher/JUnitLauncherTaskTest.java
+++ b/src/tests/junit/org/apache/tools/ant/taskdefs/optional/junitlauncher/JUnitLauncherTaskTest.java
@@ -125,4 +125,13 @@ public class JUnitLauncherTaskTest {
     public void testTestClasses() {
         buildRule.executeTarget("test-batch");
     }
+
+    /**
+     * Tests the execution of a forked test
+     */
+    @Test
+    public void testBasicFork() {
+        buildRule.executeTarget("test-basic-fork");
+
+    }
 }


Mime
View raw message