From 6f173003b3274f917c2ac139f4f37382179bd196 Mon Sep 17 00:00:00 2001 From: Alexey Andreev Date: Wed, 7 Oct 2015 19:16:11 +0300 Subject: [PATCH 01/16] Developing selenium JUnit test runner --- .../java/org/teavm/tooling/TeaVMTestCase.java | 46 +++++++++ .../java/org/teavm/tooling/TeaVMTestTool.java | 23 ++++- .../teavm/tooling/TeaVMTestToolListener.java | 24 +++++ pom.xml | 15 +-- tests/pom.xml | 1 + tools/maven/plugin/pom.xml | 10 ++ .../org/teavm/maven/BuildJavascriptMojo.java | 22 ++++- .../teavm/maven/BuildJavascriptTestMojo.java | 96 ++++++++++++++++++- .../main/resources/teavm-selenium-adapter.js | 48 ++++++++++ .../src/main/resources/teavm-selenium.js | 40 ++++++++ 10 files changed, 314 insertions(+), 11 deletions(-) create mode 100644 core/src/main/java/org/teavm/tooling/TeaVMTestCase.java create mode 100644 core/src/main/java/org/teavm/tooling/TeaVMTestToolListener.java create mode 100644 tools/maven/plugin/src/main/resources/teavm-selenium-adapter.js create mode 100644 tools/maven/plugin/src/main/resources/teavm-selenium.js diff --git a/core/src/main/java/org/teavm/tooling/TeaVMTestCase.java b/core/src/main/java/org/teavm/tooling/TeaVMTestCase.java new file mode 100644 index 000000000..6ab2f7713 --- /dev/null +++ b/core/src/main/java/org/teavm/tooling/TeaVMTestCase.java @@ -0,0 +1,46 @@ +/* + * Copyright 2015 Alexey Andreev. + * + * Licensed 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.teavm.tooling; + +import java.io.File; + +/** + * + * @author Alexey Andreev + */ +public class TeaVMTestCase { + private File runtimeScript; + private File testScript; + private File debugTable; + + public TeaVMTestCase(File runtimeScript, File testScript, File debugTable) { + this.runtimeScript = runtimeScript; + this.testScript = testScript; + this.debugTable = debugTable; + } + + public File getRuntimeScript() { + return runtimeScript; + } + + public File getTestScript() { + return testScript; + } + + public File getDebugTable() { + return debugTable; + } +} diff --git a/core/src/main/java/org/teavm/tooling/TeaVMTestTool.java b/core/src/main/java/org/teavm/tooling/TeaVMTestTool.java index a2895b0eb..ff57ddaf6 100644 --- a/core/src/main/java/org/teavm/tooling/TeaVMTestTool.java +++ b/core/src/main/java/org/teavm/tooling/TeaVMTestTool.java @@ -61,6 +61,7 @@ public class TeaVMTestTool { private MethodNodeCache astCache; private ProgramCache programCache; private SourceFilesCopier sourceFilesCopier; + private List listeners = new ArrayList<>(); public File getOutputDir() { return outputDir; @@ -347,6 +348,7 @@ public class TeaVMTestTool { for (ClassHolderTransformer transformer : transformers) { vm.add(transformer); } + File file = new File(outputDir, targetName); DebugInformationBuilder debugInfoBuilder = sourceMapsGenerated || debugInformationGenerated ? new DebugInformationBuilder() : null; @@ -376,12 +378,16 @@ public class TeaVMTestTool { } } } - if (sourceMapsGenerated) { + + File debugTableFile = null; + if (debugInformationGenerated) { DebugInformation debugInfo = debugInfoBuilder.getDebugInformation(); - try (OutputStream debugInfoOut = new FileOutputStream(new File(outputDir, targetName + ".teavmdbg"))) { + debugTableFile = new File(outputDir, targetName + ".teavmdbg"); + try (OutputStream debugInfoOut = new FileOutputStream(debugTableFile)) { debugInfo.write(debugInfoOut); } } + if (sourceMapsGenerated) { DebugInformation debugInfo = debugInfoBuilder.getDebugInformation(); String sourceMapsFileName = targetName + ".map"; @@ -393,6 +399,11 @@ public class TeaVMTestTool { if (sourceFilesCopied && vm.getWrittenClasses() != null) { sourceFilesCopier.addClasses(vm.getWrittenClasses()); } + + TeaVMTestCase testCase = new TeaVMTestCase(new File(outputDir, "res/runtime.js"), file, debugTableFile); + for (TeaVMTestToolListener listener : listeners) { + listener.testGenerated(testCase); + } } private void escapeString(String string, Writer writer) throws IOException { @@ -422,4 +433,12 @@ public class TeaVMTestTool { } writer.append('\"'); } + + public void addListener(TeaVMTestToolListener listener) { + listeners.add(listener); + } + + public void removeListener(TeaVMTestToolListener listener) { + listeners.remove(listener); + } } diff --git a/core/src/main/java/org/teavm/tooling/TeaVMTestToolListener.java b/core/src/main/java/org/teavm/tooling/TeaVMTestToolListener.java new file mode 100644 index 000000000..68f87a267 --- /dev/null +++ b/core/src/main/java/org/teavm/tooling/TeaVMTestToolListener.java @@ -0,0 +1,24 @@ +/* + * Copyright 2015 Alexey Andreev. + * + * Licensed 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.teavm.tooling; + +/** + * + * @author Alexey Andreev + */ +public interface TeaVMTestToolListener { + void testGenerated(TeaVMTestCase testCase); +} diff --git a/pom.xml b/pom.xml index e10fe10f4..f84f2ee34 100644 --- a/pom.xml +++ b/pom.xml @@ -69,7 +69,7 @@ 1.2 9.2.1.v20140609 1.7.7 - 1.9.3 + 2.47.2 @@ -166,13 +166,16 @@ slf4j-api ${slf4j.version} - diff --git a/tests/pom.xml b/tests/pom.xml index f7a6d202d..7614f5da9 100644 --- a/tests/pom.xml +++ b/tests/pom.xml @@ -87,6 +87,7 @@ en, en_US, en_GB, ru, ru_RU ${teavm.test.incremental} + http://127.0.0.1:4444/wd/hub diff --git a/tools/maven/plugin/pom.xml b/tools/maven/plugin/pom.xml index 143dd1213..3d3080b27 100644 --- a/tools/maven/plugin/pom.xml +++ b/tools/maven/plugin/pom.xml @@ -57,6 +57,16 @@ commons-io commons-io + + org.seleniumhq.selenium + selenium-java + 2.47.2 + + + org.seleniumhq.selenium + selenium-remote-driver + 2.47.2 + junit junit diff --git a/tools/maven/plugin/src/main/java/org/teavm/maven/BuildJavascriptMojo.java b/tools/maven/plugin/src/main/java/org/teavm/maven/BuildJavascriptMojo.java index f4c43ec6a..42c47edbf 100644 --- a/tools/maven/plugin/src/main/java/org/teavm/maven/BuildJavascriptMojo.java +++ b/tools/maven/plugin/src/main/java/org/teavm/maven/BuildJavascriptMojo.java @@ -21,7 +21,12 @@ import java.lang.reflect.InvocationTargetException; import java.net.MalformedURLException; import java.net.URL; import java.net.URLClassLoader; -import java.util.*; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.HashSet; +import java.util.List; +import java.util.Properties; +import java.util.Set; import org.apache.maven.artifact.Artifact; import org.apache.maven.artifact.repository.MavenArtifactRepository; import org.apache.maven.plugin.AbstractMojo; @@ -34,7 +39,12 @@ import org.apache.maven.plugins.annotations.ResolutionScope; import org.apache.maven.project.MavenProject; import org.apache.maven.repository.RepositorySystem; import org.teavm.model.ClassHolderTransformer; -import org.teavm.tooling.*; +import org.teavm.tooling.ClassAlias; +import org.teavm.tooling.MethodAlias; +import org.teavm.tooling.RuntimeCopyOperation; +import org.teavm.tooling.SourceFileProvider; +import org.teavm.tooling.TeaVMTool; +import org.teavm.tooling.TeaVMToolException; /** * @@ -149,6 +159,14 @@ public class BuildJavascriptMojo extends AbstractMojo { this.mainPageIncluded = mainPageIncluded; } + public void setCompileScopes(List compileScopes) { + this.compileScopes = compileScopes; + } + + public void setMainClass(String mainClass) { + this.mainClass = mainClass; + } + public String[] getTransformers() { return transformers; } diff --git a/tools/maven/plugin/src/main/java/org/teavm/maven/BuildJavascriptTestMojo.java b/tools/maven/plugin/src/main/java/org/teavm/maven/BuildJavascriptTestMojo.java index a194b57ad..34c3103d1 100644 --- a/tools/maven/plugin/src/main/java/org/teavm/maven/BuildJavascriptTestMojo.java +++ b/tools/maven/plugin/src/main/java/org/teavm/maven/BuildJavascriptTestMojo.java @@ -16,16 +16,28 @@ package org.teavm.maven; import java.io.File; +import java.io.FileInputStream; import java.io.IOException; +import java.io.InputStream; import java.lang.reflect.Constructor; import java.lang.reflect.InvocationTargetException; import java.net.MalformedURLException; import java.net.URL; import java.net.URLClassLoader; -import java.util.*; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.Enumeration; +import java.util.HashSet; +import java.util.List; +import java.util.Properties; +import java.util.Set; +import java.util.concurrent.BlockingQueue; +import java.util.concurrent.LinkedBlockingQueue; +import java.util.concurrent.TimeUnit; import java.util.jar.JarEntry; import java.util.jar.JarFile; import org.apache.commons.io.FilenameUtils; +import org.apache.commons.io.IOUtils; import org.apache.maven.artifact.Artifact; import org.apache.maven.artifact.repository.MavenArtifactRepository; import org.apache.maven.plugin.AbstractMojo; @@ -38,10 +50,16 @@ import org.apache.maven.plugins.annotations.Parameter; import org.apache.maven.plugins.annotations.ResolutionScope; import org.apache.maven.project.MavenProject; import org.apache.maven.repository.RepositorySystem; +import org.openqa.selenium.JavascriptExecutor; +import org.openqa.selenium.WebDriver; +import org.openqa.selenium.chrome.ChromeDriver; +import org.openqa.selenium.remote.DesiredCapabilities; +import org.openqa.selenium.remote.RemoteWebDriver; import org.teavm.model.ClassHolderTransformer; import org.teavm.testing.JUnitTestAdapter; import org.teavm.testing.TestAdapter; import org.teavm.tooling.SourceFileProvider; +import org.teavm.tooling.TeaVMTestCase; import org.teavm.tooling.TeaVMTestTool; import org.teavm.tooling.TeaVMToolException; @@ -119,7 +137,13 @@ public class BuildJavascriptTestMojo extends AbstractMojo { @Parameter private boolean sourceFilesCopied; + @Parameter + private URL seleniumURL; + private WebDriver webDriver; + private TeaVMTestTool tool = new TeaVMTestTool(); + private BlockingQueue seleniumTaskQueue = new LinkedBlockingQueue<>(); + private volatile boolean seleniumStopped = false; public void setProject(MavenProject project) { this.project = project; @@ -197,6 +221,10 @@ public class BuildJavascriptTestMojo extends AbstractMojo { this.sourceFilesCopied = sourceFilesCopied; } + public void setSeleniumURL(URL seleniumURL) { + this.seleniumURL = seleniumURL; + } + @Override public void execute() throws MojoExecutionException, MojoFailureException { if (System.getProperty("maven.test.skip", "false").equals("true") || @@ -204,6 +232,8 @@ public class BuildJavascriptTestMojo extends AbstractMojo { getLog().info("Tests build skipped as specified by system property"); return; } + + detectSelenium(); try { final ClassLoader classLoader = prepareClassLoader(); getLog().info("Searching for tests in the directory `" + testFiles.getAbsolutePath() + "'"); @@ -239,9 +269,13 @@ public class BuildJavascriptTestMojo extends AbstractMojo { if (additionalScripts != null) { tool.getAdditionalScripts().addAll(Arrays.asList(additionalScripts)); } + tool.addListener(testCase -> runSelenium(testCase)); tool.generate(); } catch (TeaVMToolException e) { throw new MojoFailureException("Error occured generating JavaScript files", e); + } finally { + webDriver.close(); + stopSelenium(); } } @@ -419,4 +453,64 @@ public class BuildJavascriptTestMojo extends AbstractMojo { } return transformerInstances; } + + private void detectSelenium() { + if (seleniumURL == null) { + return; + } + ChromeDriver driver = new ChromeDriver(); + webDriver = driver; + new Thread(() -> { + while (!seleniumStopped) { + Runnable task; + try { + task = seleniumTaskQueue.poll(1, TimeUnit.SECONDS); + } catch (InterruptedException e) { + break; + } + task.run(); + } + }).start(); + } + + private void addSeleniumTask(Runnable runnable) { + if (seleniumURL != null) { + seleniumTaskQueue.add(runnable); + } + } + + private void stopSelenium() { + addSeleniumTask(() -> seleniumStopped = true); + } + + private void runSelenium(TeaVMTestCase testCase) { + if (webDriver == null) { + return; + } + try { + JavascriptExecutor js = (JavascriptExecutor) webDriver; + js.executeAsyncScript( + readResource("teavm-selenium.js"), + readFile(testCase.getRuntimeScript()), + readFile(testCase.getTestScript()), + readResource("teavm-selenium-adapter.js")); + } catch (IOException e) { + getLog().error(e); + } + } + + private String readFile(File file) throws IOException { + try (InputStream input = new FileInputStream(file)) { + return IOUtils.toString(input, "UTF-8"); + } + } + + private String readResource(String resourceName) throws IOException { + try (InputStream input = BuildJavascriptTestMojo.class.getClassLoader().getResourceAsStream(resourceName)) { + if (input == null) { + return ""; + } + return IOUtils.toString(input, "UTF-8"); + } + } } diff --git a/tools/maven/plugin/src/main/resources/teavm-selenium-adapter.js b/tools/maven/plugin/src/main/resources/teavm-selenium-adapter.js new file mode 100644 index 000000000..d29744f72 --- /dev/null +++ b/tools/maven/plugin/src/main/resources/teavm-selenium-adapter.js @@ -0,0 +1,48 @@ +JUnitClient.run = function() { + var handler = window.addEventListener("message", $rt_threadStarter(function() { + var thread = $rt_nativeThread(); + var instance; + var ptr = 0; + var message; + if (thread.isResuming()) { + ptr = thread.pop(); + instance = thread.pop(); + } + loop: while (true) { switch (ptr) { + case 0: + instance = new TestClass(); + ptr = 1; + case 1: + try { + initInstance(instance); + } catch (e) { + message = {}; + JUnitClient.makeErrorMessage(message, e); + break loop; + } + if (thread.isSuspending()) { + thread.push(instance); + thread.push(ptr); + return; + } + ptr = 2; + case 2: + try { + runTest(instance); + } catch (e) { + message = {}; + JUnitClient.makeErrorMessage(message, e); + break loop; + } + if (thread.isSuspending()) { + thread.push(instance); + thread.push(ptr); + return; + } + message = {}; + message.status = "ok"; + break loop; + }} + window.parent.postMessage(JSON.stringify(message), "*"); + })); +} \ No newline at end of file diff --git a/tools/maven/plugin/src/main/resources/teavm-selenium.js b/tools/maven/plugin/src/main/resources/teavm-selenium.js new file mode 100644 index 000000000..3afcaf999 --- /dev/null +++ b/tools/maven/plugin/src/main/resources/teavm-selenium.js @@ -0,0 +1,40 @@ +var runtimeSource = arguments[0] +var testSource = arguments[1] +var adapterSource = arguments[2] + +var iframe = document.createElement("iframe") +document.appendChild(iframe) +var doc = iframe.contentDocument + +loadScripts([ runtimeSource, adapterSource, testSource ], runTest) +window.addEventListener("message", handleMessage) + +function handleMessage(event) { + window.removeEventListener("message", handleMessage) + callback(JSON.stringify(message.data)) +} + +var handler = window.addEventListener("message", function(event) { + window.removeEventListener +}) + +function loadScript(script, callback) { + var elem = doc.createElement("script") + elem.setAttribute("type", "text/javascript") + elem.appendChild(doc.createTextNode(runtimeSource)) + elem.onload = function() { + callback() + } + doc.body.appendChild(script) +} + +function loadScripts(scripts, callback, index) { + index = index || 0 + loadScript(scripts[i], function() { + if (++index == scripts.length) { + callback() + } else { + loadScripts(scripts, callback, index) + } + }) +} \ No newline at end of file From e83d4106d880acef83266832d4f84fdf3efa741f Mon Sep 17 00:00:00 2001 From: Alexey Andreev Date: Thu, 8 Oct 2015 17:56:16 +0300 Subject: [PATCH 02/16] Prototype implementation of selenium test runner --- .../java/org/teavm/tooling/TeaVMTestCase.java | 9 +- .../java/org/teavm/tooling/TeaVMTestTool.java | 3 +- tools/maven/plugin/pom.xml | 7 +- .../teavm/maven/BuildJavascriptTestMojo.java | 109 ++++------- .../org/teavm/maven/SeleniumTestRunner.java | 172 ++++++++++++++++++ .../main/java/org/teavm/maven/TestResult.java | 54 ++++++ .../main/java/org/teavm/maven/TestStatus.java | 25 +++ .../main/resources/teavm-selenium-adapter.js | 17 +- .../src/main/resources/teavm-selenium.js | 49 ++--- 9 files changed, 338 insertions(+), 107 deletions(-) create mode 100644 tools/maven/plugin/src/main/java/org/teavm/maven/SeleniumTestRunner.java create mode 100644 tools/maven/plugin/src/main/java/org/teavm/maven/TestResult.java create mode 100644 tools/maven/plugin/src/main/java/org/teavm/maven/TestStatus.java diff --git a/core/src/main/java/org/teavm/tooling/TeaVMTestCase.java b/core/src/main/java/org/teavm/tooling/TeaVMTestCase.java index 6ab2f7713..d33833c98 100644 --- a/core/src/main/java/org/teavm/tooling/TeaVMTestCase.java +++ b/core/src/main/java/org/teavm/tooling/TeaVMTestCase.java @@ -16,22 +16,29 @@ package org.teavm.tooling; import java.io.File; +import org.teavm.model.MethodReference; /** * * @author Alexey Andreev */ public class TeaVMTestCase { + private MethodReference testMethod; private File runtimeScript; private File testScript; private File debugTable; - public TeaVMTestCase(File runtimeScript, File testScript, File debugTable) { + public TeaVMTestCase(MethodReference testMethod, File runtimeScript, File testScript, File debugTable) { + this.testMethod = testMethod; this.runtimeScript = runtimeScript; this.testScript = testScript; this.debugTable = debugTable; } + public MethodReference getTestMethod() { + return testMethod; + } + public File getRuntimeScript() { return runtimeScript; } diff --git a/core/src/main/java/org/teavm/tooling/TeaVMTestTool.java b/core/src/main/java/org/teavm/tooling/TeaVMTestTool.java index ff57ddaf6..01768014b 100644 --- a/core/src/main/java/org/teavm/tooling/TeaVMTestTool.java +++ b/core/src/main/java/org/teavm/tooling/TeaVMTestTool.java @@ -400,7 +400,8 @@ public class TeaVMTestTool { sourceFilesCopier.addClasses(vm.getWrittenClasses()); } - TeaVMTestCase testCase = new TeaVMTestCase(new File(outputDir, "res/runtime.js"), file, debugTableFile); + TeaVMTestCase testCase = new TeaVMTestCase(methodRef, new File(outputDir, "res/runtime.js"), + file, debugTableFile); for (TeaVMTestToolListener listener : listeners) { listener.testGenerated(testCase); } diff --git a/tools/maven/plugin/pom.xml b/tools/maven/plugin/pom.xml index 3d3080b27..24c18e8b2 100644 --- a/tools/maven/plugin/pom.xml +++ b/tools/maven/plugin/pom.xml @@ -60,12 +60,15 @@ org.seleniumhq.selenium selenium-java - 2.47.2 org.seleniumhq.selenium selenium-remote-driver - 2.47.2 + + + com.fasterxml.jackson.core + jackson-databind + 2.6.2 junit diff --git a/tools/maven/plugin/src/main/java/org/teavm/maven/BuildJavascriptTestMojo.java b/tools/maven/plugin/src/main/java/org/teavm/maven/BuildJavascriptTestMojo.java index 34c3103d1..3f1ff546e 100644 --- a/tools/maven/plugin/src/main/java/org/teavm/maven/BuildJavascriptTestMojo.java +++ b/tools/maven/plugin/src/main/java/org/teavm/maven/BuildJavascriptTestMojo.java @@ -16,9 +16,7 @@ package org.teavm.maven; import java.io.File; -import java.io.FileInputStream; import java.io.IOException; -import java.io.InputStream; import java.lang.reflect.Constructor; import java.lang.reflect.InvocationTargetException; import java.net.MalformedURLException; @@ -31,13 +29,9 @@ import java.util.HashSet; import java.util.List; import java.util.Properties; import java.util.Set; -import java.util.concurrent.BlockingQueue; -import java.util.concurrent.LinkedBlockingQueue; -import java.util.concurrent.TimeUnit; import java.util.jar.JarEntry; import java.util.jar.JarFile; import org.apache.commons.io.FilenameUtils; -import org.apache.commons.io.IOUtils; import org.apache.maven.artifact.Artifact; import org.apache.maven.artifact.repository.MavenArtifactRepository; import org.apache.maven.plugin.AbstractMojo; @@ -50,16 +44,10 @@ import org.apache.maven.plugins.annotations.Parameter; import org.apache.maven.plugins.annotations.ResolutionScope; import org.apache.maven.project.MavenProject; import org.apache.maven.repository.RepositorySystem; -import org.openqa.selenium.JavascriptExecutor; -import org.openqa.selenium.WebDriver; -import org.openqa.selenium.chrome.ChromeDriver; -import org.openqa.selenium.remote.DesiredCapabilities; -import org.openqa.selenium.remote.RemoteWebDriver; import org.teavm.model.ClassHolderTransformer; import org.teavm.testing.JUnitTestAdapter; import org.teavm.testing.TestAdapter; import org.teavm.tooling.SourceFileProvider; -import org.teavm.tooling.TeaVMTestCase; import org.teavm.tooling.TeaVMTestTool; import org.teavm.tooling.TeaVMToolException; @@ -139,11 +127,10 @@ public class BuildJavascriptTestMojo extends AbstractMojo { @Parameter private URL seleniumURL; - private WebDriver webDriver; + + private SeleniumTestRunner seleniumRunner; private TeaVMTestTool tool = new TeaVMTestTool(); - private BlockingQueue seleniumTaskQueue = new LinkedBlockingQueue<>(); - private volatile boolean seleniumStopped = false; public void setProject(MavenProject project) { this.project = project; @@ -233,7 +220,10 @@ public class BuildJavascriptTestMojo extends AbstractMojo { return; } - detectSelenium(); + seleniumRunner = new SeleniumTestRunner(); + seleniumRunner.setUrl(seleniumURL); + seleniumRunner.setLog(getLog()); + seleniumRunner.detectSelenium(); try { final ClassLoader classLoader = prepareClassLoader(); getLog().info("Searching for tests in the directory `" + testFiles.getAbsolutePath() + "'"); @@ -269,13 +259,35 @@ public class BuildJavascriptTestMojo extends AbstractMojo { if (additionalScripts != null) { tool.getAdditionalScripts().addAll(Arrays.asList(additionalScripts)); } - tool.addListener(testCase -> runSelenium(testCase)); + tool.addListener(testCase -> seleniumRunner.run(testCase)); tool.generate(); + seleniumRunner.stopSelenium(); + seleniumRunner.waitForSelenium(); + processReport(seleniumRunner.getReport()); } catch (TeaVMToolException e) { throw new MojoFailureException("Error occured generating JavaScript files", e); } finally { - webDriver.close(); - stopSelenium(); + seleniumRunner.stopSelenium(); + } + } + + private void processReport(List report) throws MojoExecutionException { + if (report.isEmpty()) { + getLog().info("No tests ran"); + return; + } + + int failedTests = 0; + for (TestResult result : report) { + if (result.getStatus() != TestStatus.PASSED) { + failedTests++; + } + } + + if (failedTests > 0) { + throw new MojoExecutionException(failedTests + " of " + report.size() + " test(s) failed"); + } else { + getLog().info("All of " + report.size() + " tests successfully passed"); } } @@ -454,63 +466,4 @@ public class BuildJavascriptTestMojo extends AbstractMojo { return transformerInstances; } - private void detectSelenium() { - if (seleniumURL == null) { - return; - } - ChromeDriver driver = new ChromeDriver(); - webDriver = driver; - new Thread(() -> { - while (!seleniumStopped) { - Runnable task; - try { - task = seleniumTaskQueue.poll(1, TimeUnit.SECONDS); - } catch (InterruptedException e) { - break; - } - task.run(); - } - }).start(); - } - - private void addSeleniumTask(Runnable runnable) { - if (seleniumURL != null) { - seleniumTaskQueue.add(runnable); - } - } - - private void stopSelenium() { - addSeleniumTask(() -> seleniumStopped = true); - } - - private void runSelenium(TeaVMTestCase testCase) { - if (webDriver == null) { - return; - } - try { - JavascriptExecutor js = (JavascriptExecutor) webDriver; - js.executeAsyncScript( - readResource("teavm-selenium.js"), - readFile(testCase.getRuntimeScript()), - readFile(testCase.getTestScript()), - readResource("teavm-selenium-adapter.js")); - } catch (IOException e) { - getLog().error(e); - } - } - - private String readFile(File file) throws IOException { - try (InputStream input = new FileInputStream(file)) { - return IOUtils.toString(input, "UTF-8"); - } - } - - private String readResource(String resourceName) throws IOException { - try (InputStream input = BuildJavascriptTestMojo.class.getClassLoader().getResourceAsStream(resourceName)) { - if (input == null) { - return ""; - } - return IOUtils.toString(input, "UTF-8"); - } - } } diff --git a/tools/maven/plugin/src/main/java/org/teavm/maven/SeleniumTestRunner.java b/tools/maven/plugin/src/main/java/org/teavm/maven/SeleniumTestRunner.java new file mode 100644 index 000000000..bde8eef59 --- /dev/null +++ b/tools/maven/plugin/src/main/java/org/teavm/maven/SeleniumTestRunner.java @@ -0,0 +1,172 @@ +/* + * Copyright 2015 Alexey Andreev. + * + * Licensed 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.teavm.maven; + +import com.fasterxml.jackson.databind.ObjectMapper; +import com.fasterxml.jackson.databind.node.ObjectNode; +import java.io.File; +import java.io.FileInputStream; +import java.io.IOException; +import java.io.InputStream; +import java.net.URL; +import java.util.ArrayList; +import java.util.List; +import java.util.concurrent.BlockingQueue; +import java.util.concurrent.CopyOnWriteArrayList; +import java.util.concurrent.CountDownLatch; +import java.util.concurrent.LinkedBlockingQueue; +import java.util.concurrent.TimeUnit; +import org.apache.commons.io.IOUtils; +import org.apache.maven.plugin.logging.Log; +import org.openqa.selenium.JavascriptExecutor; +import org.openqa.selenium.WebDriver; +import org.openqa.selenium.WebDriverException; +import org.openqa.selenium.chrome.ChromeDriver; +import org.teavm.tooling.TeaVMTestCase; + +/** + * + * @author Alexey Andreev + */ +public class SeleniumTestRunner { + private URL url; + private WebDriver webDriver; + private BlockingQueue seleniumTaskQueue = new LinkedBlockingQueue<>(); + private CountDownLatch latch = new CountDownLatch(1); + private volatile boolean seleniumStopped = false; + private Log log; + private List report = new CopyOnWriteArrayList<>(); + private ThreadLocal> localReport = new ThreadLocal<>(); + + public URL getUrl() { + return url; + } + + public void setUrl(URL url) { + this.url = url; + } + + public void setLog(Log log) { + this.log = log; + } + + public void detectSelenium() { + if (url == null) { + return; + } + ChromeDriver driver = new ChromeDriver(); + webDriver = driver; + new Thread(() -> { + localReport.set(new ArrayList<>()); + while (!seleniumStopped) { + Runnable task; + try { + task = seleniumTaskQueue.poll(1, TimeUnit.SECONDS); + } catch (InterruptedException e) { + break; + } + if (task != null) { + task.run(); + } + } + report.addAll(localReport.get()); + localReport.remove(); + }).start(); + } + + private void addSeleniumTask(Runnable runnable) { + if (url != null) { + seleniumTaskQueue.add(runnable); + } + } + + public void stopSelenium() { + addSeleniumTask(() -> { + seleniumStopped = true; + latch.countDown(); + }); + } + + public void waitForSelenium() { + try { + latch.await(); + } catch (InterruptedException e) { + return; + } + } + + public void run(TeaVMTestCase testCase) { + addSeleniumTask(() -> runImpl(testCase)); + } + + private void runImpl(TeaVMTestCase testCase) { + if (webDriver == null) { + return; + } + webDriver.manage().timeouts().setScriptTimeout(5, TimeUnit.SECONDS); + JavascriptExecutor js = (JavascriptExecutor) webDriver; + try { + String result = (String) js.executeAsyncScript( + readResource("teavm-selenium.js"), + readFile(testCase.getRuntimeScript()), + readFile(testCase.getTestScript()), + readResource("teavm-selenium-adapter.js")); + ObjectMapper mapper = new ObjectMapper(); + ObjectNode resultObject = (ObjectNode) mapper.readTree(result); + String status = resultObject.get("status").asText(); + switch (status) { + case "ok": + log.info("Test passed: " + testCase.getTestMethod()); + localReport.get().add(TestResult.passed(testCase.getTestMethod())); + break; + case "exception": { + String stack = resultObject.get("stack").asText(); + log.info("Test failed: " + testCase.getTestMethod()); + localReport.get().add(TestResult.error(testCase.getTestMethod(), stack)); + break; + } + } + } catch (IOException e) { + log.error(e); + } catch (WebDriverException e) { + log.error("Error occured running test " + testCase.getTestMethod(), e); + @SuppressWarnings("unchecked") + List errors = (List) js.executeScript("return window.jsErrors;"); + for (Object error : errors) { + log.error(" -- additional error: " + error); + } + } + } + + private String readFile(File file) throws IOException { + try (InputStream input = new FileInputStream(file)) { + return IOUtils.toString(input, "UTF-8"); + } + } + + private String readResource(String resourceName) throws IOException { + try (InputStream input = BuildJavascriptTestMojo.class.getClassLoader().getResourceAsStream(resourceName)) { + if (input == null) { + return ""; + } + return IOUtils.toString(input, "UTF-8"); + } + } + + public List getReport() { + return new ArrayList<>(report); + } +} diff --git a/tools/maven/plugin/src/main/java/org/teavm/maven/TestResult.java b/tools/maven/plugin/src/main/java/org/teavm/maven/TestResult.java new file mode 100644 index 000000000..1151f2c85 --- /dev/null +++ b/tools/maven/plugin/src/main/java/org/teavm/maven/TestResult.java @@ -0,0 +1,54 @@ +/* + * Copyright 2015 Alexey Andreev. + * + * Licensed 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.teavm.maven; + +import org.teavm.model.MethodReference; + +/** + * + * @author Alexey Andreev + */ +public class TestResult { + private MethodReference method; + private TestStatus status; + private String stack; + + private TestResult(MethodReference method, TestStatus status, String stack) { + this.method = method; + this.status = status; + this.stack = stack; + } + + public static TestResult passed(MethodReference method) { + return new TestResult(method, TestStatus.PASSED, null); + } + + public static TestResult error(MethodReference method, String stack) { + return new TestResult(method, TestStatus.ERROR, stack); + } + + public MethodReference getMethod() { + return method; + } + + public TestStatus getStatus() { + return status; + } + + public String getStack() { + return stack; + } +} diff --git a/tools/maven/plugin/src/main/java/org/teavm/maven/TestStatus.java b/tools/maven/plugin/src/main/java/org/teavm/maven/TestStatus.java new file mode 100644 index 000000000..8bdbaecd2 --- /dev/null +++ b/tools/maven/plugin/src/main/java/org/teavm/maven/TestStatus.java @@ -0,0 +1,25 @@ +/* + * Copyright 2015 Alexey Andreev. + * + * Licensed 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.teavm.maven; + +/** + * + * @author Alexey Andreev + */ +public enum TestStatus { + PASSED, + ERROR +} diff --git a/tools/maven/plugin/src/main/resources/teavm-selenium-adapter.js b/tools/maven/plugin/src/main/resources/teavm-selenium-adapter.js index d29744f72..91cf0cf83 100644 --- a/tools/maven/plugin/src/main/resources/teavm-selenium-adapter.js +++ b/tools/maven/plugin/src/main/resources/teavm-selenium-adapter.js @@ -1,5 +1,6 @@ +var JUnitClient = {} JUnitClient.run = function() { - var handler = window.addEventListener("message", $rt_threadStarter(function() { + $rt_startThread(function() { var thread = $rt_nativeThread(); var instance; var ptr = 0; @@ -44,5 +45,17 @@ JUnitClient.run = function() { break loop; }} window.parent.postMessage(JSON.stringify(message), "*"); - })); + }) +} + +JUnitClient.makeErrorMessage = function(message, e) { + message.status = "exception"; + var stack = e.stack; + if (e.$javaException && e.$javaException.constructor.$meta) { + message.exception = e.$javaException.constructor.$meta.name; + message.stack = e.$javaException.constructor.$meta.name + ": "; + var exceptionMessage = extractException(e.$javaException); + message.stack += exceptionMessage ? $rt_ustr(exceptionMessage) : ""; + } + message.stack += "\n" + stack; } \ No newline at end of file diff --git a/tools/maven/plugin/src/main/resources/teavm-selenium.js b/tools/maven/plugin/src/main/resources/teavm-selenium.js index 3afcaf999..bbf451b11 100644 --- a/tools/maven/plugin/src/main/resources/teavm-selenium.js +++ b/tools/maven/plugin/src/main/resources/teavm-selenium.js @@ -1,40 +1,43 @@ var runtimeSource = arguments[0] var testSource = arguments[1] var adapterSource = arguments[2] +var seleniumCallback = arguments[arguments.length - 1] var iframe = document.createElement("iframe") -document.appendChild(iframe) +document.body.appendChild(iframe) var doc = iframe.contentDocument -loadScripts([ runtimeSource, adapterSource, testSource ], runTest) +window.jsErrors = [] +window.onerror = reportError +iframe.contentWindow.onerror = reportError + +loadScripts([ runtimeSource, adapterSource, testSource ]) window.addEventListener("message", handleMessage) function handleMessage(event) { window.removeEventListener("message", handleMessage) - callback(JSON.stringify(message.data)) + document.body.removeChild(iframe) + seleniumCallback(event.data) } -var handler = window.addEventListener("message", function(event) { - window.removeEventListener -}) - function loadScript(script, callback) { - var elem = doc.createElement("script") - elem.setAttribute("type", "text/javascript") - elem.appendChild(doc.createTextNode(runtimeSource)) - elem.onload = function() { - callback() - } - doc.body.appendChild(script) + callback() } -function loadScripts(scripts, callback, index) { - index = index || 0 - loadScript(scripts[i], function() { - if (++index == scripts.length) { - callback() - } else { - loadScripts(scripts, callback, index) - } - }) +function loadScripts(scripts) { + for (var i = 0; i < scripts.length; ++i) { + var elem = doc.createElement("script") + elem.type = "text/javascript" + doc.head.appendChild(elem) + elem.text = scripts[i] + } +} +function reportError(error, url, line) { + window.jsErrors.push(error + " at " + line) +} +function report(error) { + window.jsErrors.push(error) +} +function globalEval(window, arg) { + eval.apply(window, [arg]) } \ No newline at end of file From 90fec4e2190aa4bc8f486d6e9dd8da50cf4253e5 Mon Sep 17 00:00:00 2001 From: Alexey Andreev Date: Thu, 8 Oct 2015 18:27:48 +0300 Subject: [PATCH 03/16] Refactoring test compiler --- .../java/org/teavm/tooling/TeaVMTestCase.java | 12 +- .../org/teavm/tooling/TeaVMTestClass.java | 39 ++++ .../org/teavm/tooling/TeaVMTestMethod.java | 49 +++++ .../java/org/teavm/tooling/TeaVMTestTool.java | 193 ++++++++++-------- 4 files changed, 211 insertions(+), 82 deletions(-) create mode 100644 core/src/main/java/org/teavm/tooling/TeaVMTestClass.java create mode 100644 core/src/main/java/org/teavm/tooling/TeaVMTestMethod.java diff --git a/core/src/main/java/org/teavm/tooling/TeaVMTestCase.java b/core/src/main/java/org/teavm/tooling/TeaVMTestCase.java index d33833c98..98ec0ffea 100644 --- a/core/src/main/java/org/teavm/tooling/TeaVMTestCase.java +++ b/core/src/main/java/org/teavm/tooling/TeaVMTestCase.java @@ -16,6 +16,9 @@ package org.teavm.tooling; import java.io.File; +import java.util.ArrayList; +import java.util.Collections; +import java.util.List; import org.teavm.model.MethodReference; /** @@ -27,12 +30,15 @@ public class TeaVMTestCase { private File runtimeScript; private File testScript; private File debugTable; + private List expectedExceptions = new ArrayList<>(); - public TeaVMTestCase(MethodReference testMethod, File runtimeScript, File testScript, File debugTable) { + public TeaVMTestCase(MethodReference testMethod, File runtimeScript, File testScript, File debugTable, + List expectedExceptions) { this.testMethod = testMethod; this.runtimeScript = runtimeScript; this.testScript = testScript; this.debugTable = debugTable; + this.expectedExceptions = Collections.unmodifiableList(new ArrayList<>(expectedExceptions)); } public MethodReference getTestMethod() { @@ -50,4 +56,8 @@ public class TeaVMTestCase { public File getDebugTable() { return debugTable; } + + public List getExpectedExceptions() { + return expectedExceptions; + } } diff --git a/core/src/main/java/org/teavm/tooling/TeaVMTestClass.java b/core/src/main/java/org/teavm/tooling/TeaVMTestClass.java new file mode 100644 index 000000000..b69d59126 --- /dev/null +++ b/core/src/main/java/org/teavm/tooling/TeaVMTestClass.java @@ -0,0 +1,39 @@ +/* + * Copyright 2015 Alexey Andreev. + * + * Licensed 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.teavm.tooling; + +import java.util.List; + +/** + * + * @author Alexey Andreev + */ +class TeaVMTestClass { + private String className; + private List methods; + + public TeaVMTestClass(String className) { + this.className = className; + } + + public String getClassName() { + return className; + } + + public List getMethods() { + return methods; + } +} diff --git a/core/src/main/java/org/teavm/tooling/TeaVMTestMethod.java b/core/src/main/java/org/teavm/tooling/TeaVMTestMethod.java new file mode 100644 index 000000000..a4adb7f39 --- /dev/null +++ b/core/src/main/java/org/teavm/tooling/TeaVMTestMethod.java @@ -0,0 +1,49 @@ +/* + * Copyright 2015 Alexey Andreev. + * + * Licensed 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.teavm.tooling; + +import java.util.ArrayList; +import java.util.Collections; +import java.util.List; +import org.teavm.model.MethodReference; + +/** + * + * @author Alexey Andreev + */ +class TeaVMTestMethod { + private MethodReference method; + private String fileName; + private List expectedExceptions = new ArrayList<>(); + + public TeaVMTestMethod(MethodReference method, String fileName, List expectedExceptions) { + this.method = method; + this.fileName = fileName; + this.expectedExceptions = Collections.unmodifiableList(new ArrayList<>(expectedExceptions)); + } + + public MethodReference getMethod() { + return method; + } + + public String getFileName() { + return fileName; + } + + public List getExpectedExceptions() { + return expectedExceptions; + } +} diff --git a/core/src/main/java/org/teavm/tooling/TeaVMTestTool.java b/core/src/main/java/org/teavm/tooling/TeaVMTestTool.java index 01768014b..2a73c839d 100644 --- a/core/src/main/java/org/teavm/tooling/TeaVMTestTool.java +++ b/core/src/main/java/org/teavm/tooling/TeaVMTestTool.java @@ -15,8 +15,16 @@ */ package org.teavm.tooling; -import java.io.*; -import java.util.*; +import java.io.File; +import java.io.FileOutputStream; +import java.io.IOException; +import java.io.InputStream; +import java.io.OutputStream; +import java.io.OutputStreamWriter; +import java.io.Writer; +import java.util.ArrayList; +import java.util.List; +import java.util.Properties; import org.apache.commons.io.IOUtils; import org.teavm.common.FiniteExecutor; import org.teavm.common.SimpleFiniteExecutor; @@ -26,7 +34,16 @@ import org.teavm.debugging.information.DebugInformationBuilder; import org.teavm.javascript.EmptyRegularMethodNodeCache; import org.teavm.javascript.InMemoryRegularMethodNodeCache; import org.teavm.javascript.MethodNodeCache; -import org.teavm.model.*; +import org.teavm.model.ClassHolder; +import org.teavm.model.ClassHolderSource; +import org.teavm.model.ClassHolderTransformer; +import org.teavm.model.CopyClassHolderSource; +import org.teavm.model.InMemoryProgramCache; +import org.teavm.model.MethodHolder; +import org.teavm.model.MethodReference; +import org.teavm.model.PreOptimizingClassHolderSource; +import org.teavm.model.ProgramCache; +import org.teavm.model.ValueType; import org.teavm.parsing.ClasspathClassHolderSource; import org.teavm.testing.JUnitTestAdapter; import org.teavm.testing.TestAdapter; @@ -39,9 +56,6 @@ import org.teavm.vm.TeaVMBuilder; * @author Alexey Andreev */ public class TeaVMTestTool { - private Map> groupedMethods = new HashMap<>(); - private Map fileNames = new HashMap<>(); - private List testMethods = new ArrayList<>(); private File outputDir = new File("."); private boolean minifying = true; private int numThreads = 1; @@ -62,6 +76,8 @@ public class TeaVMTestTool { private ProgramCache programCache; private SourceFilesCopier sourceFilesCopier; private List listeners = new ArrayList<>(); + private List testPlan = new ArrayList<>(); + private int fileIndexGenerator; public File getOutputDir() { return outputDir; @@ -199,58 +215,8 @@ public class TeaVMTestTool { astCache = new InMemoryRegularMethodNodeCache(); programCache = new InMemoryProgramCache(); } - File allTestsFile = new File(outputDir, "tests/all.js"); - try (Writer allTestsWriter = new OutputStreamWriter(new FileOutputStream(allTestsFile), "UTF-8")) { - allTestsWriter.write("prepare = function() {\n"); - allTestsWriter.write(" return new JUnitServer(document.body).readTests(["); - boolean first = true; - for (String testClass : testClasses) { - Collection methods = groupedMethods.get(testClass); - if (methods == null) { - continue; - } - if (!first) { - allTestsWriter.append(","); - } - first = false; - allTestsWriter.append("\n { name : \"").append(testClass).append("\", methods : ["); - boolean firstMethod = true; - for (MethodReference methodRef : methods) { - String scriptName = "tests/" + fileNames.size() + ".js"; - fileNames.put(methodRef, scriptName); - if (!firstMethod) { - allTestsWriter.append(","); - } - firstMethod = false; - allTestsWriter.append("\n { name : \"" + methodRef.getName() + "\", script : \"" - + scriptName + "\", expected : ["); - MethodHolder methodHolder = classSource.get(testClass).getMethod( - methodRef.getDescriptor()); - boolean firstException = true; - for (String exception : adapter.getExpectedExceptions(methodHolder)) { - if (!firstException) { - allTestsWriter.append(", "); - } - firstException = false; - allTestsWriter.append("\"" + exception + "\""); - } - allTestsWriter.append("], additionalScripts : ["); - for (int i = 0; i < additionalScriptLocalPaths.size(); ++i) { - if (i > 0) { - allTestsWriter.append(", "); - } - escapeString(additionalScriptLocalPaths.get(i), allTestsWriter); - } - allTestsWriter.append("] }"); - } - allTestsWriter.append("] }"); - } - allTestsWriter.write("], function() {}); }"); - } - int methodsGenerated = 0; - log.info("Generating test files"); - sourceFilesCopier = new SourceFilesCopier(sourceFileProviders); - sourceFilesCopier.setLog(log); + writeMetadata(); + FiniteExecutor executor = new SimpleFiniteExecutor(); if (numThreads != 1) { int threads = numThreads != 0 ? numThreads : Runtime.getRuntime().availableProcessors(); @@ -258,20 +224,8 @@ public class TeaVMTestTool { finalizer = () -> threadedExecutor.stop(); executor = threadedExecutor; } - for (final MethodReference method : testMethods) { - final ClassHolderSource builderClassSource = classSource; - executor.execute(() -> { - log.debug("Building test for " + method); - try { - decompileClassesForTest(classLoader, new CopyClassHolderSource(builderClassSource), method, - fileNames.get(method)); - } catch (IOException e) { - log.error("Error generating JavaScript", e); - } - }); - ++methodsGenerated; - } - executor.complete(); + int methodsGenerated = writeMethods(executor, classSource); + if (sourceFilesCopied) { sourceFilesCopier.copy(new File(new File(outputDir, "tests"), "src")); } @@ -285,6 +239,75 @@ public class TeaVMTestTool { } } + private void writeMetadata() throws IOException { + File allTestsFile = new File(outputDir, "tests/all.js"); + try (Writer allTestsWriter = new OutputStreamWriter(new FileOutputStream(allTestsFile), "UTF-8")) { + allTestsWriter.write("prepare = function() {\n"); + allTestsWriter.write(" return new JUnitServer(document.body).readTests(["); + boolean first = true; + for (TeaVMTestClass testClass : testPlan) { + if (!first) { + allTestsWriter.append(","); + } + first = false; + allTestsWriter.append("\n { name : \"").append(testClass.getClassName()) + .append("\", methods : ["); + boolean firstMethod = true; + for (TeaVMTestMethod testMethod : testClass.getMethods()) { + String scriptName = testMethod.getFileName(); + if (!firstMethod) { + allTestsWriter.append(","); + } + firstMethod = false; + allTestsWriter.append("\n { name : \"" + testMethod.getMethod().getName() + + "\", script : \"" + scriptName + "\", expected : ["); + boolean firstException = true; + for (String exception : testMethod.getExpectedExceptions()) { + if (!firstException) { + allTestsWriter.append(", "); + } + firstException = false; + allTestsWriter.append("\"" + exception + "\""); + } + allTestsWriter.append("], additionalScripts : ["); + for (int i = 0; i < additionalScriptLocalPaths.size(); ++i) { + if (i > 0) { + allTestsWriter.append(", "); + } + escapeString(additionalScriptLocalPaths.get(i), allTestsWriter); + } + allTestsWriter.append("] }"); + } + allTestsWriter.append("] }"); + } + allTestsWriter.write("], function() {}); }"); + } + } + + private int writeMethods(FiniteExecutor executor, ClassHolderSource classSource) { + int methodsGenerated = 0; + log.info("Generating test files"); + sourceFilesCopier = new SourceFilesCopier(sourceFileProviders); + sourceFilesCopier.setLog(log); + for (TeaVMTestClass testClass : testPlan) { + for (TeaVMTestMethod testMethod : testClass.getMethods()) { + final ClassHolderSource builderClassSource = classSource; + executor.execute(() -> { + log.debug("Building test for " + testMethod.getMethod()); + try { + decompileClassesForTest(classLoader, new CopyClassHolderSource(builderClassSource), + testMethod); + } catch (IOException e) { + log.error("Error generating JavaScript", e); + } + }); + ++methodsGenerated; + } + } + executor.complete(); + return methodsGenerated; + } + private void resourceToFile(String resource, String fileName) throws IOException { try (InputStream input = TeaVMTestTool.class.getClassLoader().getResourceAsStream(resource)) { try (OutputStream output = new FileOutputStream(new File(outputDir, fileName))) { @@ -294,18 +317,24 @@ public class TeaVMTestTool { } private void findTests(ClassHolder cls) { + TeaVMTestClass testClass = new TeaVMTestClass(cls.getName()); for (MethodHolder method : cls.getMethods()) { if (adapter.acceptMethod(method)) { MethodReference ref = new MethodReference(cls.getName(), method.getDescriptor()); - testMethods.add(ref); - List group = groupedMethods.get(cls.getName()); - if (group == null) { - group = new ArrayList<>(); - groupedMethods.put(cls.getName(), group); + String fileName = "tests/" + fileIndexGenerator++ + ".js"; + + List exceptions = new ArrayList<>(); + for (String exception : adapter.getExpectedExceptions(method)) { + exceptions.add(exception); } - group.add(ref); + + TeaVMTestMethod testMethod = new TeaVMTestMethod(ref, fileName, exceptions); + testClass.getMethods().add(testMethod); } } + if (!testClass.getMethods().isEmpty()) { + testPlan.add(testClass); + } } private void includeAdditionalScripts(ClassLoader classLoader) throws TeaVMToolException { @@ -333,7 +362,8 @@ public class TeaVMTestTool { } private void decompileClassesForTest(ClassLoader classLoader, ClassHolderSource classSource, - MethodReference methodRef, String targetName) throws IOException { + TeaVMTestMethod testMethod) throws IOException { + String targetName = testMethod.getFileName(); TeaVM vm = new TeaVMBuilder() .setClassLoader(classLoader) .setClassSource(classSource) @@ -349,9 +379,10 @@ public class TeaVMTestTool { vm.add(transformer); } - File file = new File(outputDir, targetName); + File file = new File(outputDir, testMethod.getFileName()); DebugInformationBuilder debugInfoBuilder = sourceMapsGenerated || debugInformationGenerated ? new DebugInformationBuilder() : null; + MethodReference methodRef = testMethod.getMethod(); try (Writer innerWriter = new OutputStreamWriter(new FileOutputStream(file), "UTF-8")) { MethodReference cons = new MethodReference(methodRef.getClassName(), "", ValueType.VOID); MethodReference exceptionMsg = new MethodReference(ExceptionHelper.class, "showException", @@ -401,7 +432,7 @@ public class TeaVMTestTool { } TeaVMTestCase testCase = new TeaVMTestCase(methodRef, new File(outputDir, "res/runtime.js"), - file, debugTableFile); + file, debugTableFile, testMethod.getExpectedExceptions()); for (TeaVMTestToolListener listener : listeners) { listener.testGenerated(testCase); } From 5522f55c689b0ec093c9f5c0bb055bb938a3c262 Mon Sep 17 00:00:00 2001 From: Alexey Andreev Date: Fri, 9 Oct 2015 17:56:38 +0300 Subject: [PATCH 04/16] Deep refactoring of tooling libraries --- html4j/pom.xml | 10 +- jso/apis/pom.xml | 1 + jso/core/pom.xml | 1 + jso/impl/pom.xml | 1 + pom.xml | 12 + samples/async/pom.xml | 3 +- samples/benchmark/pom.xml | 3 +- samples/hello/pom.xml | 3 +- samples/kotlin/pom.xml | 3 +- samples/pom.xml | 2 + samples/scala/pom.xml | 3 +- samples/storage/pom.xml | 3 +- samples/video/pom.xml | 3 +- tests/pom.xml | 3 +- tools/cli/pom.xml | 3 +- .../java/org/teavm/cli/TeaVMTestRunner.java | 12 +- tools/core/pom.xml | 64 ++++ .../java/org/teavm/tooling/BaseTeaVMTool.java | 50 ++++ .../java/org/teavm/tooling/ClassAlias.java | 0 .../org/teavm/tooling/EmptyTeaVMToolLog.java | 0 .../tooling/InstructionLocationReader.java | 0 .../java/org/teavm/tooling/MethodAlias.java | 0 .../teavm/tooling/RuntimeCopyOperation.java | 0 .../teavm/tooling/TeaVMProblemRenderer.java | 0 .../java/org/teavm/tooling/TeaVMTool.java | 15 +- .../org/teavm/tooling/TeaVMToolException.java | 0 .../java/org/teavm/tooling/TeaVMToolLog.java | 0 .../sources}/DirectorySourceFileProvider.java | 2 +- .../sources}/JarSourceFileProvider.java | 2 +- .../sources}/ProgramSourceAggregator.java | 2 +- .../tooling/sources}/SourceFileProvider.java | 2 +- .../tooling/sources}/SourceFilesCopier.java | 4 +- .../tooling/testing}/ExceptionHelper.java | 2 +- .../teavm/tooling/testing}/TeaVMTestTool.java | 120 +++++--- .../testing}/TeaVMTestToolListener.java | 5 +- .../org/teavm/tooling/testing/TestCase.java | 34 ++- .../tooling/testing/TestClassBuilder.java | 11 +- .../testing}/TestExceptionDependency.java | 2 +- .../tooling/testing}/TestExceptionPlugin.java | 2 +- .../org/teavm/tooling/testing/TestGroup.java | 49 +++ .../tooling/testing/TestMethodBuilder.java | 6 +- .../org/teavm/tooling/testing/TestPlan.java | 47 +++ .../resources/org/teavm/tooling/main.html | 0 .../org/teavm/tooling/test/junit.html | 0 .../org/teavm/tooling/test/res/class_obj.png | Bin .../tooling/test/res/control-000-small.png | Bin .../teavm/tooling/test/res/junit-support.js | 0 .../org/teavm/tooling/test/res/junit.css | 0 .../teavm/tooling/test/res/methpub_obj.png | Bin .../teavm/tooling/test/res/package_obj.png | Bin .../teavm/tooling/test/res/tick-small-red.png | Bin .../org/teavm/tooling/test/res/tick-small.png | Bin .../tooling/test/res/toggle-small-expand.png | Bin .../teavm/tooling/test/res/toggle-small.png | Bin .../eclipse/core-plugin/META-INF/MANIFEST.MF | 1 + tools/eclipse/core-plugin/build.properties | 1 + tools/eclipse/core-plugin/dep-pom.xml | 5 + tools/eclipse/pom.xml | 1 + tools/maven/plugin/pom.xml | 3 +- .../teavm/maven/AbstractJavascriptMojo.java | 219 ++++++++++++++ .../org/teavm/maven/BuildJavascriptMojo.java | 280 +----------------- .../teavm/maven/BuildJavascriptTestMojo.java | 248 ++-------------- .../maven/MavenSourceFileProviderLookup.java | 6 +- .../java/org/teavm/maven/RunTestsMojo.java | 31 ++ .../org/teavm/maven/SeleniumTestRunner.java | 96 +++--- tools/maven/pom.xml | 1 + 66 files changed, 744 insertions(+), 633 deletions(-) create mode 100644 tools/core/pom.xml create mode 100644 tools/core/src/main/java/org/teavm/tooling/BaseTeaVMTool.java rename {core => tools/core}/src/main/java/org/teavm/tooling/ClassAlias.java (100%) rename {core => tools/core}/src/main/java/org/teavm/tooling/EmptyTeaVMToolLog.java (100%) rename {core => tools/core}/src/main/java/org/teavm/tooling/InstructionLocationReader.java (100%) rename {core => tools/core}/src/main/java/org/teavm/tooling/MethodAlias.java (100%) rename {core => tools/core}/src/main/java/org/teavm/tooling/RuntimeCopyOperation.java (100%) rename {core => tools/core}/src/main/java/org/teavm/tooling/TeaVMProblemRenderer.java (100%) rename {core => tools/core}/src/main/java/org/teavm/tooling/TeaVMTool.java (98%) rename {core => tools/core}/src/main/java/org/teavm/tooling/TeaVMToolException.java (100%) rename {core => tools/core}/src/main/java/org/teavm/tooling/TeaVMToolLog.java (100%) rename {core/src/main/java/org/teavm/tooling => tools/core/src/main/java/org/teavm/tooling/sources}/DirectorySourceFileProvider.java (97%) rename {core/src/main/java/org/teavm/tooling => tools/core/src/main/java/org/teavm/tooling/sources}/JarSourceFileProvider.java (98%) rename {core/src/main/java/org/teavm/tooling => tools/core/src/main/java/org/teavm/tooling/sources}/ProgramSourceAggregator.java (99%) rename {core/src/main/java/org/teavm/tooling => tools/core/src/main/java/org/teavm/tooling/sources}/SourceFileProvider.java (96%) rename {core/src/main/java/org/teavm/tooling => tools/core/src/main/java/org/teavm/tooling/sources}/SourceFilesCopier.java (96%) rename {core/src/main/java/org/teavm/tooling => tools/core/src/main/java/org/teavm/tooling/testing}/ExceptionHelper.java (95%) rename {core/src/main/java/org/teavm/tooling => tools/core/src/main/java/org/teavm/tooling/testing}/TeaVMTestTool.java (83%) rename {core/src/main/java/org/teavm/tooling => tools/core/src/main/java/org/teavm/tooling/testing}/TeaVMTestToolListener.java (89%) rename core/src/main/java/org/teavm/tooling/TeaVMTestCase.java => tools/core/src/main/java/org/teavm/tooling/testing/TestCase.java (64%) rename core/src/main/java/org/teavm/tooling/TeaVMTestClass.java => tools/core/src/main/java/org/teavm/tooling/testing/TestClassBuilder.java (77%) rename {core/src/main/java/org/teavm/tooling => tools/core/src/main/java/org/teavm/tooling/testing}/TestExceptionDependency.java (98%) rename {core/src/main/java/org/teavm/tooling => tools/core/src/main/java/org/teavm/tooling/testing}/TestExceptionPlugin.java (96%) create mode 100644 tools/core/src/main/java/org/teavm/tooling/testing/TestGroup.java rename core/src/main/java/org/teavm/tooling/TeaVMTestMethod.java => tools/core/src/main/java/org/teavm/tooling/testing/TestMethodBuilder.java (88%) create mode 100644 tools/core/src/main/java/org/teavm/tooling/testing/TestPlan.java rename {core => tools/core}/src/main/resources/org/teavm/tooling/main.html (100%) rename {core => tools/core}/src/main/resources/org/teavm/tooling/test/junit.html (100%) rename {core => tools/core}/src/main/resources/org/teavm/tooling/test/res/class_obj.png (100%) rename {core => tools/core}/src/main/resources/org/teavm/tooling/test/res/control-000-small.png (100%) rename {core => tools/core}/src/main/resources/org/teavm/tooling/test/res/junit-support.js (100%) rename {core => tools/core}/src/main/resources/org/teavm/tooling/test/res/junit.css (100%) rename {core => tools/core}/src/main/resources/org/teavm/tooling/test/res/methpub_obj.png (100%) rename {core => tools/core}/src/main/resources/org/teavm/tooling/test/res/package_obj.png (100%) rename {core => tools/core}/src/main/resources/org/teavm/tooling/test/res/tick-small-red.png (100%) rename {core => tools/core}/src/main/resources/org/teavm/tooling/test/res/tick-small.png (100%) rename {core => tools/core}/src/main/resources/org/teavm/tooling/test/res/toggle-small-expand.png (100%) rename {core => tools/core}/src/main/resources/org/teavm/tooling/test/res/toggle-small.png (100%) create mode 100644 tools/maven/plugin/src/main/java/org/teavm/maven/AbstractJavascriptMojo.java create mode 100644 tools/maven/plugin/src/main/java/org/teavm/maven/RunTestsMojo.java diff --git a/html4j/pom.xml b/html4j/pom.xml index bffacb498..4626c9ea4 100644 --- a/html4j/pom.xml +++ b/html4j/pom.xml @@ -74,12 +74,11 @@ generate-javascript-tests - build-test-javascript + testCompile - process-test-classes false - ${project.build.directory}/javascript-test + ${project.build.directory}/javascript-test true true @@ -87,13 +86,12 @@ generate-javascript-tck - build-test-javascript + testCompile - process-test-classes false true - ${project.build.directory}/javascript-tck + ${project.build.directory}/javascript-tck org.teavm.html4j.testing.KOTestAdapter org.teavm.javascript.NullPointerExceptionTransformer diff --git a/jso/apis/pom.xml b/jso/apis/pom.xml index fe2ced996..4ff751af4 100644 --- a/jso/apis/pom.xml +++ b/jso/apis/pom.xml @@ -21,6 +21,7 @@ xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xs org.teavm teavm 0.4.0-SNAPSHOT + ../.. teavm-jso-apis diff --git a/jso/core/pom.xml b/jso/core/pom.xml index 89a011db5..f44fe2475 100644 --- a/jso/core/pom.xml +++ b/jso/core/pom.xml @@ -21,6 +21,7 @@ xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xs org.teavm teavm 0.4.0-SNAPSHOT + ../.. teavm-jso diff --git a/jso/impl/pom.xml b/jso/impl/pom.xml index f2c9e9bf3..c596a2929 100644 --- a/jso/impl/pom.xml +++ b/jso/impl/pom.xml @@ -21,6 +21,7 @@ xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xs org.teavm teavm 0.4.0-SNAPSHOT + ../.. teavm-jso-impl diff --git a/pom.xml b/pom.xml index f84f2ee34..21282c232 100644 --- a/pom.xml +++ b/pom.xml @@ -70,6 +70,7 @@ 9.2.1.v20140609 1.7.7 2.47.2 + 2.6.2 @@ -81,6 +82,7 @@ html4j samples platform + tools/core tools/cli tools/maven tools/chrome-rdp @@ -176,6 +178,16 @@ selenium-remote-driver ${selenium.version} + + com.fasterxml.jackson.core + jackson-annotations + ${jackson.version} + + + com.fasterxml.jackson.core + jackson-databind + ${jackson.version} + diff --git a/samples/async/pom.xml b/samples/async/pom.xml index 001e04006..2ea775d90 100644 --- a/samples/async/pom.xml +++ b/samples/async/pom.xml @@ -57,9 +57,8 @@ web-client - prepare-package - build-javascript + compile ${project.build.directory}/generated/js/teavm diff --git a/samples/benchmark/pom.xml b/samples/benchmark/pom.xml index ed0590921..378ee7c83 100644 --- a/samples/benchmark/pom.xml +++ b/samples/benchmark/pom.xml @@ -111,9 +111,8 @@ web-client - prepare-package - build-javascript + compile ${project.build.directory}/generated/js/teavm diff --git a/samples/hello/pom.xml b/samples/hello/pom.xml index ed8128e63..ff9ea0b65 100644 --- a/samples/hello/pom.xml +++ b/samples/hello/pom.xml @@ -76,9 +76,8 @@ web-client - prepare-package - build-javascript + compile ${project.build.directory}/generated/js/teavm diff --git a/samples/kotlin/pom.xml b/samples/kotlin/pom.xml index f9fcc0606..1af5c380a 100644 --- a/samples/kotlin/pom.xml +++ b/samples/kotlin/pom.xml @@ -92,9 +92,8 @@ web-client - prepare-package - build-javascript + compile ${project.build.directory}/generated/js/teavm diff --git a/samples/pom.xml b/samples/pom.xml index fea836574..60292acad 100644 --- a/samples/pom.xml +++ b/samples/pom.xml @@ -36,6 +36,8 @@ video async kotlin + \ No newline at end of file diff --git a/samples/scala/pom.xml b/samples/scala/pom.xml index e1c2c61a0..f0837e8cc 100644 --- a/samples/scala/pom.xml +++ b/samples/scala/pom.xml @@ -67,9 +67,8 @@ web-client - prepare-package - build-javascript + compile ${project.build.directory}/generated/js/teavm diff --git a/samples/storage/pom.xml b/samples/storage/pom.xml index 70d0cc0bc..3537a4fce 100644 --- a/samples/storage/pom.xml +++ b/samples/storage/pom.xml @@ -78,12 +78,11 @@ web-client prepare-package - build-javascript + compile ${project.build.directory}/generated/js/teavm org.teavm.samples.storage.Application - SEPARATE false true true diff --git a/samples/video/pom.xml b/samples/video/pom.xml index 1f64bc021..77502485e 100644 --- a/samples/video/pom.xml +++ b/samples/video/pom.xml @@ -76,9 +76,8 @@ web-client - prepare-package - build-javascript + compile ${project.build.directory}/generated/js/teavm diff --git a/tests/pom.xml b/tests/pom.xml index 7614f5da9..8518a31dd 100644 --- a/tests/pom.xml +++ b/tests/pom.xml @@ -72,9 +72,8 @@ generate-javascript-tests - build-test-javascript + testCompile - process-test-classes false true diff --git a/tools/cli/pom.xml b/tools/cli/pom.xml index 7d1e838c8..51557637f 100644 --- a/tools/cli/pom.xml +++ b/tools/cli/pom.xml @@ -21,6 +21,7 @@ org.teavm teavm 0.4.0-SNAPSHOT + ../.. teavm-cli @@ -30,7 +31,7 @@ org.teavm - teavm-core + teavm-tooling ${project.version} diff --git a/tools/cli/src/main/java/org/teavm/cli/TeaVMTestRunner.java b/tools/cli/src/main/java/org/teavm/cli/TeaVMTestRunner.java index 32bf89b19..0a2a45328 100644 --- a/tools/cli/src/main/java/org/teavm/cli/TeaVMTestRunner.java +++ b/tools/cli/src/main/java/org/teavm/cli/TeaVMTestRunner.java @@ -19,11 +19,17 @@ import java.io.File; import java.lang.reflect.Constructor; import java.lang.reflect.InvocationTargetException; import java.util.Arrays; -import org.apache.commons.cli.*; +import org.apache.commons.cli.CommandLine; +import org.apache.commons.cli.CommandLineParser; +import org.apache.commons.cli.HelpFormatter; +import org.apache.commons.cli.OptionBuilder; +import org.apache.commons.cli.Options; +import org.apache.commons.cli.ParseException; +import org.apache.commons.cli.PosixParser; import org.teavm.model.ClassHolderTransformer; import org.teavm.testing.TestAdapter; -import org.teavm.tooling.TeaVMTestTool; import org.teavm.tooling.TeaVMToolException; +import org.teavm.tooling.testing.TeaVMTestTool; /** * @@ -84,7 +90,7 @@ public final class TeaVMTestRunner { } TeaVMTestTool tool = new TeaVMTestTool(); - tool.setOutputDir(new File(commandLine.getOptionValue("d", "."))); + tool.setTargetDirectory(new File(commandLine.getOptionValue("d", "."))); tool.setMinifying(commandLine.hasOption("m")); try { tool.setNumThreads(Integer.parseInt(commandLine.getOptionValue("t", "1"))); diff --git a/tools/core/pom.xml b/tools/core/pom.xml new file mode 100644 index 000000000..7abaacfc8 --- /dev/null +++ b/tools/core/pom.xml @@ -0,0 +1,64 @@ + + + 4.0.0 + + + org.teavm + teavm + 0.4.0-SNAPSHOT + ../.. + + teavm-tooling + + TeaVM tooling core + TeaVM API that helps to create tooling + + + + org.teavm + teavm-core + ${project.version} + + + com.fasterxml.jackson.core + jackson-annotations + true + + + + + + + org.apache.maven.plugins + maven-checkstyle-plugin + + ../../checkstyle.xml + config_loc=${basedir}/../.. + + + + org.apache.maven.plugins + maven-source-plugin + + + org.apache.maven.plugins + maven-javadoc-plugin + + + + \ No newline at end of file diff --git a/tools/core/src/main/java/org/teavm/tooling/BaseTeaVMTool.java b/tools/core/src/main/java/org/teavm/tooling/BaseTeaVMTool.java new file mode 100644 index 000000000..b279ff85b --- /dev/null +++ b/tools/core/src/main/java/org/teavm/tooling/BaseTeaVMTool.java @@ -0,0 +1,50 @@ +/* + * Copyright 2015 Alexey Andreev. + * + * Licensed 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.teavm.tooling; + +import java.io.File; +import java.util.List; +import java.util.Properties; +import org.teavm.model.ClassHolderTransformer; +import org.teavm.tooling.sources.SourceFileProvider; + +/** + * + * @author Alexey Andreev + */ +public interface BaseTeaVMTool { + void setTargetDirectory(File targetDirectory); + + void setMinifying(boolean minifying); + + void setIncremental(boolean incremental); + + void setDebugInformationGenerated(boolean debugInformationGenerated); + + void setSourceMapsFileGenerated(boolean sourceMapsFileGenerated); + + void setSourceFilesCopied(boolean sourceFilesCopied); + + Properties getProperties(); + + List getTransformers(); + + void setLog(TeaVMToolLog log); + + void setClassLoader(ClassLoader classLoader); + + void addSourceFileProvider(SourceFileProvider sourceFileProvider); +} diff --git a/core/src/main/java/org/teavm/tooling/ClassAlias.java b/tools/core/src/main/java/org/teavm/tooling/ClassAlias.java similarity index 100% rename from core/src/main/java/org/teavm/tooling/ClassAlias.java rename to tools/core/src/main/java/org/teavm/tooling/ClassAlias.java diff --git a/core/src/main/java/org/teavm/tooling/EmptyTeaVMToolLog.java b/tools/core/src/main/java/org/teavm/tooling/EmptyTeaVMToolLog.java similarity index 100% rename from core/src/main/java/org/teavm/tooling/EmptyTeaVMToolLog.java rename to tools/core/src/main/java/org/teavm/tooling/EmptyTeaVMToolLog.java diff --git a/core/src/main/java/org/teavm/tooling/InstructionLocationReader.java b/tools/core/src/main/java/org/teavm/tooling/InstructionLocationReader.java similarity index 100% rename from core/src/main/java/org/teavm/tooling/InstructionLocationReader.java rename to tools/core/src/main/java/org/teavm/tooling/InstructionLocationReader.java diff --git a/core/src/main/java/org/teavm/tooling/MethodAlias.java b/tools/core/src/main/java/org/teavm/tooling/MethodAlias.java similarity index 100% rename from core/src/main/java/org/teavm/tooling/MethodAlias.java rename to tools/core/src/main/java/org/teavm/tooling/MethodAlias.java diff --git a/core/src/main/java/org/teavm/tooling/RuntimeCopyOperation.java b/tools/core/src/main/java/org/teavm/tooling/RuntimeCopyOperation.java similarity index 100% rename from core/src/main/java/org/teavm/tooling/RuntimeCopyOperation.java rename to tools/core/src/main/java/org/teavm/tooling/RuntimeCopyOperation.java diff --git a/core/src/main/java/org/teavm/tooling/TeaVMProblemRenderer.java b/tools/core/src/main/java/org/teavm/tooling/TeaVMProblemRenderer.java similarity index 100% rename from core/src/main/java/org/teavm/tooling/TeaVMProblemRenderer.java rename to tools/core/src/main/java/org/teavm/tooling/TeaVMProblemRenderer.java diff --git a/core/src/main/java/org/teavm/tooling/TeaVMTool.java b/tools/core/src/main/java/org/teavm/tooling/TeaVMTool.java similarity index 98% rename from core/src/main/java/org/teavm/tooling/TeaVMTool.java rename to tools/core/src/main/java/org/teavm/tooling/TeaVMTool.java index ae767fb16..5938e2e83 100644 --- a/core/src/main/java/org/teavm/tooling/TeaVMTool.java +++ b/tools/core/src/main/java/org/teavm/tooling/TeaVMTool.java @@ -29,6 +29,8 @@ import org.teavm.diagnostics.ProblemProvider; import org.teavm.javascript.RenderingContext; import org.teavm.model.*; import org.teavm.parsing.ClasspathClassHolderSource; +import org.teavm.tooling.sources.SourceFileProvider; +import org.teavm.tooling.sources.SourceFilesCopier; import org.teavm.vm.*; import org.teavm.vm.spi.AbstractRendererListener; @@ -36,7 +38,7 @@ import org.teavm.vm.spi.AbstractRendererListener; * * @author Alexey Andreev */ -public class TeaVMTool { +public class TeaVMTool implements BaseTeaVMTool { private File targetDirectory = new File("."); private String targetFileName = "classes.js"; private boolean minifying = true; @@ -69,6 +71,7 @@ public class TeaVMTool { return targetDirectory; } + @Override public void setTargetDirectory(File targetDirectory) { this.targetDirectory = targetDirectory; } @@ -85,6 +88,7 @@ public class TeaVMTool { return minifying; } + @Override public void setMinifying(boolean minifying) { this.minifying = minifying; } @@ -93,6 +97,7 @@ public class TeaVMTool { return incremental; } + @Override public void setIncremental(boolean incremental) { this.incremental = incremental; } @@ -133,6 +138,7 @@ public class TeaVMTool { return debugInformationGenerated; } + @Override public void setDebugInformationGenerated(boolean debugInformationGenerated) { this.debugInformationGenerated = debugInformationGenerated; } @@ -149,6 +155,7 @@ public class TeaVMTool { return sourceMapsFileGenerated; } + @Override public void setSourceMapsFileGenerated(boolean sourceMapsFileGenerated) { this.sourceMapsFileGenerated = sourceMapsFileGenerated; } @@ -157,14 +164,17 @@ public class TeaVMTool { return sourceFilesCopied; } + @Override public void setSourceFilesCopied(boolean sourceFilesCopied) { this.sourceFilesCopied = sourceFilesCopied; } + @Override public Properties getProperties() { return properties; } + @Override public List getTransformers() { return transformers; } @@ -181,6 +191,7 @@ public class TeaVMTool { return log; } + @Override public void setLog(TeaVMToolLog log) { this.log = log; } @@ -189,6 +200,7 @@ public class TeaVMTool { return classLoader; } + @Override public void setClassLoader(ClassLoader classLoader) { this.classLoader = classLoader; } @@ -245,6 +257,7 @@ public class TeaVMTool { return resources; } + @Override public void addSourceFileProvider(SourceFileProvider sourceFileProvider) { sourceFileProviders.add(sourceFileProvider); } diff --git a/core/src/main/java/org/teavm/tooling/TeaVMToolException.java b/tools/core/src/main/java/org/teavm/tooling/TeaVMToolException.java similarity index 100% rename from core/src/main/java/org/teavm/tooling/TeaVMToolException.java rename to tools/core/src/main/java/org/teavm/tooling/TeaVMToolException.java diff --git a/core/src/main/java/org/teavm/tooling/TeaVMToolLog.java b/tools/core/src/main/java/org/teavm/tooling/TeaVMToolLog.java similarity index 100% rename from core/src/main/java/org/teavm/tooling/TeaVMToolLog.java rename to tools/core/src/main/java/org/teavm/tooling/TeaVMToolLog.java diff --git a/core/src/main/java/org/teavm/tooling/DirectorySourceFileProvider.java b/tools/core/src/main/java/org/teavm/tooling/sources/DirectorySourceFileProvider.java similarity index 97% rename from core/src/main/java/org/teavm/tooling/DirectorySourceFileProvider.java rename to tools/core/src/main/java/org/teavm/tooling/sources/DirectorySourceFileProvider.java index 21841bed8..aaf0e2abc 100644 --- a/core/src/main/java/org/teavm/tooling/DirectorySourceFileProvider.java +++ b/tools/core/src/main/java/org/teavm/tooling/sources/DirectorySourceFileProvider.java @@ -13,7 +13,7 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package org.teavm.tooling; +package org.teavm.tooling.sources; import java.io.File; import java.io.FileInputStream; diff --git a/core/src/main/java/org/teavm/tooling/JarSourceFileProvider.java b/tools/core/src/main/java/org/teavm/tooling/sources/JarSourceFileProvider.java similarity index 98% rename from core/src/main/java/org/teavm/tooling/JarSourceFileProvider.java rename to tools/core/src/main/java/org/teavm/tooling/sources/JarSourceFileProvider.java index 88b747199..07269d76f 100644 --- a/core/src/main/java/org/teavm/tooling/JarSourceFileProvider.java +++ b/tools/core/src/main/java/org/teavm/tooling/sources/JarSourceFileProvider.java @@ -13,7 +13,7 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package org.teavm.tooling; +package org.teavm.tooling.sources; import java.io.File; import java.io.IOException; diff --git a/core/src/main/java/org/teavm/tooling/ProgramSourceAggregator.java b/tools/core/src/main/java/org/teavm/tooling/sources/ProgramSourceAggregator.java similarity index 99% rename from core/src/main/java/org/teavm/tooling/ProgramSourceAggregator.java rename to tools/core/src/main/java/org/teavm/tooling/sources/ProgramSourceAggregator.java index fd8997642..b9e2170a0 100644 --- a/core/src/main/java/org/teavm/tooling/ProgramSourceAggregator.java +++ b/tools/core/src/main/java/org/teavm/tooling/sources/ProgramSourceAggregator.java @@ -13,7 +13,7 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package org.teavm.tooling; +package org.teavm.tooling.sources; import java.util.List; import java.util.Set; diff --git a/core/src/main/java/org/teavm/tooling/SourceFileProvider.java b/tools/core/src/main/java/org/teavm/tooling/sources/SourceFileProvider.java similarity index 96% rename from core/src/main/java/org/teavm/tooling/SourceFileProvider.java rename to tools/core/src/main/java/org/teavm/tooling/sources/SourceFileProvider.java index c5567b036..c1dbebd9b 100644 --- a/core/src/main/java/org/teavm/tooling/SourceFileProvider.java +++ b/tools/core/src/main/java/org/teavm/tooling/sources/SourceFileProvider.java @@ -13,7 +13,7 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package org.teavm.tooling; +package org.teavm.tooling.sources; import java.io.IOException; import java.io.InputStream; diff --git a/core/src/main/java/org/teavm/tooling/SourceFilesCopier.java b/tools/core/src/main/java/org/teavm/tooling/sources/SourceFilesCopier.java similarity index 96% rename from core/src/main/java/org/teavm/tooling/SourceFilesCopier.java rename to tools/core/src/main/java/org/teavm/tooling/sources/SourceFilesCopier.java index f400c20bf..746f38bdf 100644 --- a/core/src/main/java/org/teavm/tooling/SourceFilesCopier.java +++ b/tools/core/src/main/java/org/teavm/tooling/sources/SourceFilesCopier.java @@ -13,7 +13,7 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package org.teavm.tooling; +package org.teavm.tooling.sources; import java.io.*; import java.util.HashSet; @@ -23,6 +23,8 @@ import org.apache.commons.io.IOUtils; import org.teavm.model.ClassReader; import org.teavm.model.ListableClassReaderSource; import org.teavm.model.MethodReader; +import org.teavm.tooling.EmptyTeaVMToolLog; +import org.teavm.tooling.TeaVMToolLog; /** * diff --git a/core/src/main/java/org/teavm/tooling/ExceptionHelper.java b/tools/core/src/main/java/org/teavm/tooling/testing/ExceptionHelper.java similarity index 95% rename from core/src/main/java/org/teavm/tooling/ExceptionHelper.java rename to tools/core/src/main/java/org/teavm/tooling/testing/ExceptionHelper.java index ac53214c3..1977a6c7b 100644 --- a/core/src/main/java/org/teavm/tooling/ExceptionHelper.java +++ b/tools/core/src/main/java/org/teavm/tooling/testing/ExceptionHelper.java @@ -13,7 +13,7 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package org.teavm.tooling; +package org.teavm.tooling.testing; /** * diff --git a/core/src/main/java/org/teavm/tooling/TeaVMTestTool.java b/tools/core/src/main/java/org/teavm/tooling/testing/TeaVMTestTool.java similarity index 83% rename from core/src/main/java/org/teavm/tooling/TeaVMTestTool.java rename to tools/core/src/main/java/org/teavm/tooling/testing/TeaVMTestTool.java index 2a73c839d..9f0903ddd 100644 --- a/core/src/main/java/org/teavm/tooling/TeaVMTestTool.java +++ b/tools/core/src/main/java/org/teavm/tooling/testing/TeaVMTestTool.java @@ -13,7 +13,7 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package org.teavm.tooling; +package org.teavm.tooling.testing; import java.io.File; import java.io.FileOutputStream; @@ -25,6 +25,7 @@ import java.io.Writer; import java.util.ArrayList; import java.util.List; import java.util.Properties; +import java.util.concurrent.atomic.AtomicInteger; import org.apache.commons.io.IOUtils; import org.teavm.common.FiniteExecutor; import org.teavm.common.SimpleFiniteExecutor; @@ -47,6 +48,13 @@ import org.teavm.model.ValueType; import org.teavm.parsing.ClasspathClassHolderSource; import org.teavm.testing.JUnitTestAdapter; import org.teavm.testing.TestAdapter; +import org.teavm.tooling.BaseTeaVMTool; +import org.teavm.tooling.EmptyTeaVMToolLog; +import org.teavm.tooling.TeaVMProblemRenderer; +import org.teavm.tooling.TeaVMToolException; +import org.teavm.tooling.TeaVMToolLog; +import org.teavm.tooling.sources.SourceFileProvider; +import org.teavm.tooling.sources.SourceFilesCopier; import org.teavm.vm.DirectoryBuildTarget; import org.teavm.vm.TeaVM; import org.teavm.vm.TeaVMBuilder; @@ -55,7 +63,7 @@ import org.teavm.vm.TeaVMBuilder; * * @author Alexey Andreev */ -public class TeaVMTestTool { +public class TeaVMTestTool implements BaseTeaVMTool { private File outputDir = new File("."); private boolean minifying = true; private int numThreads = 1; @@ -68,22 +76,25 @@ public class TeaVMTestTool { private ClassLoader classLoader = TeaVMTestTool.class.getClassLoader(); private TeaVMToolLog log = new EmptyTeaVMToolLog(); private boolean debugInformationGenerated; - private boolean sourceMapsGenerated; + private boolean sourceMapsFileGenerated; private boolean sourceFilesCopied; private boolean incremental; private List sourceFileProviders = new ArrayList<>(); private MethodNodeCache astCache; private ProgramCache programCache; private SourceFilesCopier sourceFilesCopier; - private List listeners = new ArrayList<>(); - private List testPlan = new ArrayList<>(); + private List testPlan = new ArrayList<>(); private int fileIndexGenerator; + private long startTime; + private int testCount; + private AtomicInteger testsBuilt = new AtomicInteger(); public File getOutputDir() { return outputDir; } - public void setOutputDir(File outputDir) { + @Override + public void setTargetDirectory(File outputDir) { this.outputDir = outputDir; } @@ -91,6 +102,7 @@ public class TeaVMTestTool { return minifying; } + @Override public void setMinifying(boolean minifying) { this.minifying = minifying; } @@ -111,6 +123,7 @@ public class TeaVMTestTool { this.adapter = adapter; } + @Override public List getTransformers() { return transformers; } @@ -119,6 +132,7 @@ public class TeaVMTestTool { return additionalScripts; } + @Override public Properties getProperties() { return properties; } @@ -131,6 +145,7 @@ public class TeaVMTestTool { return classLoader; } + @Override public void setClassLoader(ClassLoader classLoader) { this.classLoader = classLoader; } @@ -139,6 +154,7 @@ public class TeaVMTestTool { return log; } + @Override public void setLog(TeaVMToolLog log) { this.log = log; } @@ -147,6 +163,7 @@ public class TeaVMTestTool { return incremental; } + @Override public void setIncremental(boolean incremental) { this.incremental = incremental; } @@ -155,31 +172,36 @@ public class TeaVMTestTool { return debugInformationGenerated; } + @Override public void setDebugInformationGenerated(boolean debugInformationGenerated) { this.debugInformationGenerated = debugInformationGenerated; } - public boolean isSourceMapsGenerated() { - return sourceMapsGenerated; + public boolean isSourceMapsFileGenerated() { + return sourceMapsFileGenerated; } - public void setSourceMapsGenerated(boolean sourceMapsGenerated) { - this.sourceMapsGenerated = sourceMapsGenerated; + @Override + public void setSourceMapsFileGenerated(boolean sourceMapsFileGenerated) { + this.sourceMapsFileGenerated = sourceMapsFileGenerated; } public boolean isSourceFilesCopied() { return sourceFilesCopied; } + @Override public void setSourceFilesCopied(boolean sourceFilesCopied) { this.sourceFilesCopied = sourceFilesCopied; } + @Override public void addSourceFileProvider(SourceFileProvider sourceFileProvider) { sourceFileProviders.add(sourceFileProvider); } - public void generate() throws TeaVMToolException { + public TestPlan generate() throws TeaVMToolException { + testsBuilt.set(0); Runnable finalizer = null; try { new File(outputDir, "tests").mkdirs(); @@ -201,12 +223,17 @@ public class TeaVMTestTool { if (incremental) { classSource = new PreOptimizingClassHolderSource(classSource); } + + List groups = new ArrayList<>(); for (String testClass : testClasses) { ClassHolder classHolder = classSource.get(testClass); if (classHolder == null) { throw new TeaVMToolException("Could not find class " + testClass); } - findTests(classHolder); + TestGroup group = findTests(classHolder); + if (group != null) { + groups.add(group); + } } includeAdditionalScripts(classLoader); @@ -220,16 +247,21 @@ public class TeaVMTestTool { FiniteExecutor executor = new SimpleFiniteExecutor(); if (numThreads != 1) { int threads = numThreads != 0 ? numThreads : Runtime.getRuntime().availableProcessors(); - final ThreadPoolFiniteExecutor threadedExecutor = new ThreadPoolFiniteExecutor(threads); + ThreadPoolFiniteExecutor threadedExecutor = new ThreadPoolFiniteExecutor(threads); finalizer = () -> threadedExecutor.stop(); executor = threadedExecutor; } + startTime = System.currentTimeMillis(); int methodsGenerated = writeMethods(executor, classSource); if (sourceFilesCopied) { sourceFilesCopier.copy(new File(new File(outputDir, "tests"), "src")); } - log.info("Test files successfully generated for " + methodsGenerated + " method(s)."); + long timeSpent = System.currentTimeMillis() - startTime; + log.info("Test files successfully generated for " + methodsGenerated + " method(s) in " + + (timeSpent / 1000.0) + " seconds."); + + return new TestPlan("res/runtime.js", groups); } catch (IOException e) { throw new TeaVMToolException("IO error occured generating JavaScript files", e); } finally { @@ -245,7 +277,7 @@ public class TeaVMTestTool { allTestsWriter.write("prepare = function() {\n"); allTestsWriter.write(" return new JUnitServer(document.body).readTests(["); boolean first = true; - for (TeaVMTestClass testClass : testPlan) { + for (TestClassBuilder testClass : testPlan) { if (!first) { allTestsWriter.append(","); } @@ -253,7 +285,7 @@ public class TeaVMTestTool { allTestsWriter.append("\n { name : \"").append(testClass.getClassName()) .append("\", methods : ["); boolean firstMethod = true; - for (TeaVMTestMethod testMethod : testClass.getMethods()) { + for (TestMethodBuilder testMethod : testClass.getMethods()) { String scriptName = testMethod.getFileName(); if (!firstMethod) { allTestsWriter.append(","); @@ -289,13 +321,12 @@ public class TeaVMTestTool { log.info("Generating test files"); sourceFilesCopier = new SourceFilesCopier(sourceFileProviders); sourceFilesCopier.setLog(log); - for (TeaVMTestClass testClass : testPlan) { - for (TeaVMTestMethod testMethod : testClass.getMethods()) { - final ClassHolderSource builderClassSource = classSource; + for (TestClassBuilder testClass : testPlan) { + for (TestMethodBuilder testMethod : testClass.getMethods()) { executor.execute(() -> { log.debug("Building test for " + testMethod.getMethod()); try { - decompileClassesForTest(classLoader, new CopyClassHolderSource(builderClassSource), + decompileClassesForTest(classLoader, new CopyClassHolderSource(classSource), testMethod); } catch (IOException e) { log.error("Error generating JavaScript", e); @@ -316,8 +347,9 @@ public class TeaVMTestTool { } } - private void findTests(ClassHolder cls) { - TeaVMTestClass testClass = new TeaVMTestClass(cls.getName()); + private TestGroup findTests(ClassHolder cls) { + List cases = new ArrayList<>(); + TestClassBuilder testClass = new TestClassBuilder(cls.getName()); for (MethodHolder method : cls.getMethods()) { if (adapter.acceptMethod(method)) { MethodReference ref = new MethodReference(cls.getName(), method.getDescriptor()); @@ -328,12 +360,19 @@ public class TeaVMTestTool { exceptions.add(exception); } - TeaVMTestMethod testMethod = new TeaVMTestMethod(ref, fileName, exceptions); + TestMethodBuilder testMethod = new TestMethodBuilder(ref, fileName, exceptions); testClass.getMethods().add(testMethod); + + String debugTable = debugInformationGenerated ? testMethod.getFileName() + ".teavmdbg" : null; + cases.add(new TestCase(ref, testMethod.getFileName(), debugTable, testMethod.getExpectedExceptions())); + ++testCount; } } if (!testClass.getMethods().isEmpty()) { testPlan.add(testClass); + return new TestGroup(cls.getName(), cases); + } else { + return null; } } @@ -362,7 +401,7 @@ public class TeaVMTestTool { } private void decompileClassesForTest(ClassLoader classLoader, ClassHolderSource classSource, - TeaVMTestMethod testMethod) throws IOException { + TestMethodBuilder testMethod) throws IOException { String targetName = testMethod.getFileName(); TeaVM vm = new TeaVMBuilder() .setClassLoader(classLoader) @@ -380,7 +419,7 @@ public class TeaVMTestTool { } File file = new File(outputDir, testMethod.getFileName()); - DebugInformationBuilder debugInfoBuilder = sourceMapsGenerated || debugInformationGenerated + DebugInformationBuilder debugInfoBuilder = sourceMapsFileGenerated || debugInformationGenerated ? new DebugInformationBuilder() : null; MethodReference methodRef = testMethod.getMethod(); try (Writer innerWriter = new OutputStreamWriter(new FileOutputStream(file), "UTF-8")) { @@ -395,7 +434,7 @@ public class TeaVMTestTool { vm.build(innerWriter, new DirectoryBuildTarget(outputDir)); innerWriter.append("\n"); innerWriter.append("\nJUnitClient.run();"); - if (sourceMapsGenerated) { + if (sourceMapsFileGenerated) { String sourceMapsFileName = targetName.substring(targetName.lastIndexOf('/') + 1) + ".map"; innerWriter.append("\n//# sourceMappingURL=").append(sourceMapsFileName); } @@ -410,16 +449,15 @@ public class TeaVMTestTool { } } - File debugTableFile = null; if (debugInformationGenerated) { DebugInformation debugInfo = debugInfoBuilder.getDebugInformation(); - debugTableFile = new File(outputDir, targetName + ".teavmdbg"); + File debugTableFile = new File(outputDir, targetName + ".teavmdbg"); try (OutputStream debugInfoOut = new FileOutputStream(debugTableFile)) { debugInfo.write(debugInfoOut); } } - if (sourceMapsGenerated) { + if (sourceMapsFileGenerated) { DebugInformation debugInfo = debugInfoBuilder.getDebugInformation(); String sourceMapsFileName = targetName + ".map"; try (Writer sourceMapsOut = new OutputStreamWriter(new FileOutputStream( @@ -431,11 +469,19 @@ public class TeaVMTestTool { sourceFilesCopier.addClasses(vm.getWrittenClasses()); } - TeaVMTestCase testCase = new TeaVMTestCase(methodRef, new File(outputDir, "res/runtime.js"), - file, debugTableFile, testMethod.getExpectedExceptions()); - for (TeaVMTestToolListener listener : listeners) { - listener.testGenerated(testCase); + incrementCounter(); + } + + private void incrementCounter() { + int count = testsBuilt.incrementAndGet(); + if (count % 10 != 0) { + return; } + + long timeSpent = System.currentTimeMillis() - startTime; + + getLog().info(count + " of " + testCount + " tests built in " + (timeSpent / 1000.0) + " seconds (" + + String.format("%.2f", (double) count / timeSpent * 1000.0) + " tests per second avg.)"); } private void escapeString(String string, Writer writer) throws IOException { @@ -465,12 +511,4 @@ public class TeaVMTestTool { } writer.append('\"'); } - - public void addListener(TeaVMTestToolListener listener) { - listeners.add(listener); - } - - public void removeListener(TeaVMTestToolListener listener) { - listeners.remove(listener); - } } diff --git a/core/src/main/java/org/teavm/tooling/TeaVMTestToolListener.java b/tools/core/src/main/java/org/teavm/tooling/testing/TeaVMTestToolListener.java similarity index 89% rename from core/src/main/java/org/teavm/tooling/TeaVMTestToolListener.java rename to tools/core/src/main/java/org/teavm/tooling/testing/TeaVMTestToolListener.java index 68f87a267..4460b2575 100644 --- a/core/src/main/java/org/teavm/tooling/TeaVMTestToolListener.java +++ b/tools/core/src/main/java/org/teavm/tooling/testing/TeaVMTestToolListener.java @@ -13,12 +13,13 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package org.teavm.tooling; +package org.teavm.tooling.testing; + /** * * @author Alexey Andreev */ public interface TeaVMTestToolListener { - void testGenerated(TeaVMTestCase testCase); + void testGenerated(TestCase testCase); } diff --git a/core/src/main/java/org/teavm/tooling/TeaVMTestCase.java b/tools/core/src/main/java/org/teavm/tooling/testing/TestCase.java similarity index 64% rename from core/src/main/java/org/teavm/tooling/TeaVMTestCase.java rename to tools/core/src/main/java/org/teavm/tooling/testing/TestCase.java index 98ec0ffea..a534649b4 100644 --- a/core/src/main/java/org/teavm/tooling/TeaVMTestCase.java +++ b/tools/core/src/main/java/org/teavm/tooling/testing/TestCase.java @@ -13,9 +13,11 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package org.teavm.tooling; +package org.teavm.tooling.testing; -import java.io.File; +import com.fasterxml.jackson.annotation.JsonCreator; +import com.fasterxml.jackson.annotation.JsonGetter; +import com.fasterxml.jackson.annotation.JsonProperty; import java.util.ArrayList; import java.util.Collections; import java.util.List; @@ -25,38 +27,40 @@ import org.teavm.model.MethodReference; * * @author Alexey Andreev */ -public class TeaVMTestCase { +public class TestCase { private MethodReference testMethod; - private File runtimeScript; - private File testScript; - private File debugTable; + private String testScript; + private String debugTable; private List expectedExceptions = new ArrayList<>(); - public TeaVMTestCase(MethodReference testMethod, File runtimeScript, File testScript, File debugTable, - List expectedExceptions) { + @JsonCreator + public TestCase( + @JsonProperty("testMethod") MethodReference testMethod, + @JsonProperty("script") String testScript, + @JsonProperty("debugTable") String debugTable, + @JsonProperty("expectedExceptions") List expectedExceptions) { this.testMethod = testMethod; - this.runtimeScript = runtimeScript; this.testScript = testScript; this.debugTable = debugTable; this.expectedExceptions = Collections.unmodifiableList(new ArrayList<>(expectedExceptions)); } + @JsonGetter public MethodReference getTestMethod() { return testMethod; } - public File getRuntimeScript() { - return runtimeScript; - } - - public File getTestScript() { + @JsonGetter("script") + public String getTestScript() { return testScript; } - public File getDebugTable() { + @JsonGetter + public String getDebugTable() { return debugTable; } + @JsonGetter public List getExpectedExceptions() { return expectedExceptions; } diff --git a/core/src/main/java/org/teavm/tooling/TeaVMTestClass.java b/tools/core/src/main/java/org/teavm/tooling/testing/TestClassBuilder.java similarity index 77% rename from core/src/main/java/org/teavm/tooling/TeaVMTestClass.java rename to tools/core/src/main/java/org/teavm/tooling/testing/TestClassBuilder.java index b69d59126..d50e2b264 100644 --- a/core/src/main/java/org/teavm/tooling/TeaVMTestClass.java +++ b/tools/core/src/main/java/org/teavm/tooling/testing/TestClassBuilder.java @@ -13,19 +13,20 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package org.teavm.tooling; +package org.teavm.tooling.testing; +import java.util.ArrayList; import java.util.List; /** * * @author Alexey Andreev */ -class TeaVMTestClass { +class TestClassBuilder { private String className; - private List methods; + private List methods = new ArrayList<>(); - public TeaVMTestClass(String className) { + public TestClassBuilder(String className) { this.className = className; } @@ -33,7 +34,7 @@ class TeaVMTestClass { return className; } - public List getMethods() { + public List getMethods() { return methods; } } diff --git a/core/src/main/java/org/teavm/tooling/TestExceptionDependency.java b/tools/core/src/main/java/org/teavm/tooling/testing/TestExceptionDependency.java similarity index 98% rename from core/src/main/java/org/teavm/tooling/TestExceptionDependency.java rename to tools/core/src/main/java/org/teavm/tooling/testing/TestExceptionDependency.java index 9fa8acd60..e388e80f6 100644 --- a/core/src/main/java/org/teavm/tooling/TestExceptionDependency.java +++ b/tools/core/src/main/java/org/teavm/tooling/testing/TestExceptionDependency.java @@ -13,7 +13,7 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package org.teavm.tooling; +package org.teavm.tooling.testing; import org.teavm.dependency.AbstractDependencyListener; import org.teavm.dependency.DependencyAgent; diff --git a/core/src/main/java/org/teavm/tooling/TestExceptionPlugin.java b/tools/core/src/main/java/org/teavm/tooling/testing/TestExceptionPlugin.java similarity index 96% rename from core/src/main/java/org/teavm/tooling/TestExceptionPlugin.java rename to tools/core/src/main/java/org/teavm/tooling/testing/TestExceptionPlugin.java index 2ec7136c6..19a2c04a1 100644 --- a/core/src/main/java/org/teavm/tooling/TestExceptionPlugin.java +++ b/tools/core/src/main/java/org/teavm/tooling/testing/TestExceptionPlugin.java @@ -13,7 +13,7 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package org.teavm.tooling; +package org.teavm.tooling.testing; import org.teavm.vm.spi.TeaVMHost; import org.teavm.vm.spi.TeaVMPlugin; diff --git a/tools/core/src/main/java/org/teavm/tooling/testing/TestGroup.java b/tools/core/src/main/java/org/teavm/tooling/testing/TestGroup.java new file mode 100644 index 000000000..4ab9d5cbb --- /dev/null +++ b/tools/core/src/main/java/org/teavm/tooling/testing/TestGroup.java @@ -0,0 +1,49 @@ +/* + * Copyright 2015 Alexey Andreev. + * + * Licensed 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.teavm.tooling.testing; + +import com.fasterxml.jackson.annotation.JsonCreator; +import com.fasterxml.jackson.annotation.JsonGetter; +import com.fasterxml.jackson.annotation.JsonProperty; +import java.util.ArrayList; +import java.util.Collections; +import java.util.List; + +/** + * + * @author Alexey Andreev + */ +public class TestGroup { + private String className; + private List testCases; + + @JsonCreator + public TestGroup(@JsonProperty("className") String className, + @JsonProperty("testCases") List testCases) { + this.className = className; + this.testCases = Collections.unmodifiableList(new ArrayList<>(testCases)); + } + + @JsonGetter("className") + public String getClassName() { + return className; + } + + @JsonGetter("testCases") + public List getTestCases() { + return testCases; + } +} diff --git a/core/src/main/java/org/teavm/tooling/TeaVMTestMethod.java b/tools/core/src/main/java/org/teavm/tooling/testing/TestMethodBuilder.java similarity index 88% rename from core/src/main/java/org/teavm/tooling/TeaVMTestMethod.java rename to tools/core/src/main/java/org/teavm/tooling/testing/TestMethodBuilder.java index a4adb7f39..3faa384d7 100644 --- a/core/src/main/java/org/teavm/tooling/TeaVMTestMethod.java +++ b/tools/core/src/main/java/org/teavm/tooling/testing/TestMethodBuilder.java @@ -13,7 +13,7 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package org.teavm.tooling; +package org.teavm.tooling.testing; import java.util.ArrayList; import java.util.Collections; @@ -24,12 +24,12 @@ import org.teavm.model.MethodReference; * * @author Alexey Andreev */ -class TeaVMTestMethod { +class TestMethodBuilder { private MethodReference method; private String fileName; private List expectedExceptions = new ArrayList<>(); - public TeaVMTestMethod(MethodReference method, String fileName, List expectedExceptions) { + public TestMethodBuilder(MethodReference method, String fileName, List expectedExceptions) { this.method = method; this.fileName = fileName; this.expectedExceptions = Collections.unmodifiableList(new ArrayList<>(expectedExceptions)); diff --git a/tools/core/src/main/java/org/teavm/tooling/testing/TestPlan.java b/tools/core/src/main/java/org/teavm/tooling/testing/TestPlan.java new file mode 100644 index 000000000..e5eefd289 --- /dev/null +++ b/tools/core/src/main/java/org/teavm/tooling/testing/TestPlan.java @@ -0,0 +1,47 @@ +/* + * Copyright 2015 Alexey Andreev. + * + * Licensed 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.teavm.tooling.testing; + +import com.fasterxml.jackson.annotation.JsonCreator; +import com.fasterxml.jackson.annotation.JsonProperty; +import java.util.ArrayList; +import java.util.Collections; +import java.util.List; + +/** + * + * @author Alexey Andreev + */ +public class TestPlan { + private String runtimeScript; + private List groups = new ArrayList<>(); + + @JsonCreator + public TestPlan( + @JsonProperty("runtimeScript") String runtimeScript, + @JsonProperty("groupList") List groups) { + this.runtimeScript = runtimeScript; + this.groups = Collections.unmodifiableList(new ArrayList<>(groups)); + } + + public String getRuntimeScript() { + return runtimeScript; + } + + public List getGroups() { + return groups; + } +} diff --git a/core/src/main/resources/org/teavm/tooling/main.html b/tools/core/src/main/resources/org/teavm/tooling/main.html similarity index 100% rename from core/src/main/resources/org/teavm/tooling/main.html rename to tools/core/src/main/resources/org/teavm/tooling/main.html diff --git a/core/src/main/resources/org/teavm/tooling/test/junit.html b/tools/core/src/main/resources/org/teavm/tooling/test/junit.html similarity index 100% rename from core/src/main/resources/org/teavm/tooling/test/junit.html rename to tools/core/src/main/resources/org/teavm/tooling/test/junit.html diff --git a/core/src/main/resources/org/teavm/tooling/test/res/class_obj.png b/tools/core/src/main/resources/org/teavm/tooling/test/res/class_obj.png similarity index 100% rename from core/src/main/resources/org/teavm/tooling/test/res/class_obj.png rename to tools/core/src/main/resources/org/teavm/tooling/test/res/class_obj.png diff --git a/core/src/main/resources/org/teavm/tooling/test/res/control-000-small.png b/tools/core/src/main/resources/org/teavm/tooling/test/res/control-000-small.png similarity index 100% rename from core/src/main/resources/org/teavm/tooling/test/res/control-000-small.png rename to tools/core/src/main/resources/org/teavm/tooling/test/res/control-000-small.png diff --git a/core/src/main/resources/org/teavm/tooling/test/res/junit-support.js b/tools/core/src/main/resources/org/teavm/tooling/test/res/junit-support.js similarity index 100% rename from core/src/main/resources/org/teavm/tooling/test/res/junit-support.js rename to tools/core/src/main/resources/org/teavm/tooling/test/res/junit-support.js diff --git a/core/src/main/resources/org/teavm/tooling/test/res/junit.css b/tools/core/src/main/resources/org/teavm/tooling/test/res/junit.css similarity index 100% rename from core/src/main/resources/org/teavm/tooling/test/res/junit.css rename to tools/core/src/main/resources/org/teavm/tooling/test/res/junit.css diff --git a/core/src/main/resources/org/teavm/tooling/test/res/methpub_obj.png b/tools/core/src/main/resources/org/teavm/tooling/test/res/methpub_obj.png similarity index 100% rename from core/src/main/resources/org/teavm/tooling/test/res/methpub_obj.png rename to tools/core/src/main/resources/org/teavm/tooling/test/res/methpub_obj.png diff --git a/core/src/main/resources/org/teavm/tooling/test/res/package_obj.png b/tools/core/src/main/resources/org/teavm/tooling/test/res/package_obj.png similarity index 100% rename from core/src/main/resources/org/teavm/tooling/test/res/package_obj.png rename to tools/core/src/main/resources/org/teavm/tooling/test/res/package_obj.png diff --git a/core/src/main/resources/org/teavm/tooling/test/res/tick-small-red.png b/tools/core/src/main/resources/org/teavm/tooling/test/res/tick-small-red.png similarity index 100% rename from core/src/main/resources/org/teavm/tooling/test/res/tick-small-red.png rename to tools/core/src/main/resources/org/teavm/tooling/test/res/tick-small-red.png diff --git a/core/src/main/resources/org/teavm/tooling/test/res/tick-small.png b/tools/core/src/main/resources/org/teavm/tooling/test/res/tick-small.png similarity index 100% rename from core/src/main/resources/org/teavm/tooling/test/res/tick-small.png rename to tools/core/src/main/resources/org/teavm/tooling/test/res/tick-small.png diff --git a/core/src/main/resources/org/teavm/tooling/test/res/toggle-small-expand.png b/tools/core/src/main/resources/org/teavm/tooling/test/res/toggle-small-expand.png similarity index 100% rename from core/src/main/resources/org/teavm/tooling/test/res/toggle-small-expand.png rename to tools/core/src/main/resources/org/teavm/tooling/test/res/toggle-small-expand.png diff --git a/core/src/main/resources/org/teavm/tooling/test/res/toggle-small.png b/tools/core/src/main/resources/org/teavm/tooling/test/res/toggle-small.png similarity index 100% rename from core/src/main/resources/org/teavm/tooling/test/res/toggle-small.png rename to tools/core/src/main/resources/org/teavm/tooling/test/res/toggle-small.png diff --git a/tools/eclipse/core-plugin/META-INF/MANIFEST.MF b/tools/eclipse/core-plugin/META-INF/MANIFEST.MF index 52513c7cb..a0133cc02 100644 --- a/tools/eclipse/core-plugin/META-INF/MANIFEST.MF +++ b/tools/eclipse/core-plugin/META-INF/MANIFEST.MF @@ -39,6 +39,7 @@ Bundle-ClassPath: ., lib/slf4j-api-1.7.7.jar, lib/teavm-chrome-rdp-0.4.0-SNAPSHOT.jar, lib/teavm-core-0.4.0-SNAPSHOT.jar, + lib/teavm-tooling-0.4.0-SNAPSHOT.jar, lib/websocket-api-9.2.1.v20140609.jar, lib/websocket-client-9.2.1.v20140609.jar, lib/websocket-common-9.2.1.v20140609.jar, diff --git a/tools/eclipse/core-plugin/build.properties b/tools/eclipse/core-plugin/build.properties index ea8d50c54..95269dd03 100644 --- a/tools/eclipse/core-plugin/build.properties +++ b/tools/eclipse/core-plugin/build.properties @@ -36,6 +36,7 @@ bin.includes = META-INF/,\ lib/slf4j-api-1.7.7.jar,\ lib/teavm-chrome-rdp-0.4.0-SNAPSHOT.jar,\ lib/teavm-core-0.4.0-SNAPSHOT.jar,\ + lib/teavm-tooling-0.4.0-SNAPSHOT.jar,\ lib/websocket-api-9.2.1.v20140609.jar,\ lib/websocket-client-9.2.1.v20140609.jar,\ lib/websocket-common-9.2.1.v20140609.jar,\ diff --git a/tools/eclipse/core-plugin/dep-pom.xml b/tools/eclipse/core-plugin/dep-pom.xml index 41fe15f28..52dd1023d 100644 --- a/tools/eclipse/core-plugin/dep-pom.xml +++ b/tools/eclipse/core-plugin/dep-pom.xml @@ -79,6 +79,11 @@ teavm-core ${project.version} + + org.teavm + teavm-tooling + ${project.version} + org.teavm teavm-chrome-rdp diff --git a/tools/eclipse/pom.xml b/tools/eclipse/pom.xml index 9d5cccf51..024fdcba6 100644 --- a/tools/eclipse/pom.xml +++ b/tools/eclipse/pom.xml @@ -21,6 +21,7 @@ org.teavm teavm 0.4.0-SNAPSHOT + ../.. teavm-eclipse pom diff --git a/tools/maven/plugin/pom.xml b/tools/maven/plugin/pom.xml index 24c18e8b2..34fe8454c 100644 --- a/tools/maven/plugin/pom.xml +++ b/tools/maven/plugin/pom.xml @@ -50,7 +50,7 @@ org.teavm - teavm-core + teavm-tooling ${project.version} @@ -68,7 +68,6 @@ com.fasterxml.jackson.core jackson-databind - 2.6.2 junit diff --git a/tools/maven/plugin/src/main/java/org/teavm/maven/AbstractJavascriptMojo.java b/tools/maven/plugin/src/main/java/org/teavm/maven/AbstractJavascriptMojo.java new file mode 100644 index 000000000..6446e3441 --- /dev/null +++ b/tools/maven/plugin/src/main/java/org/teavm/maven/AbstractJavascriptMojo.java @@ -0,0 +1,219 @@ +/* + * Copyright 2015 Alexey Andreev. + * + * Licensed 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.teavm.maven; + +import java.io.File; +import java.lang.reflect.Constructor; +import java.lang.reflect.InvocationTargetException; +import java.net.MalformedURLException; +import java.net.URL; +import java.net.URLClassLoader; +import java.util.ArrayList; +import java.util.Collections; +import java.util.List; +import java.util.Properties; +import org.apache.maven.artifact.Artifact; +import org.apache.maven.artifact.repository.MavenArtifactRepository; +import org.apache.maven.plugin.AbstractMojo; +import org.apache.maven.plugin.MojoExecutionException; +import org.apache.maven.plugin.logging.Log; +import org.apache.maven.plugins.annotations.Component; +import org.apache.maven.plugins.annotations.Parameter; +import org.apache.maven.project.MavenProject; +import org.apache.maven.repository.RepositorySystem; +import org.teavm.model.ClassHolderTransformer; +import org.teavm.tooling.BaseTeaVMTool; +import org.teavm.tooling.sources.SourceFileProvider; + +/** + * + * @author Alexey Andreev + */ +public abstract class AbstractJavascriptMojo extends AbstractMojo { + @Component + protected MavenProject project; + + @Component + protected RepositorySystem repositorySystem; + + @Parameter(required = true, readonly = true, defaultValue = "${localRepository}") + protected MavenArtifactRepository localRepository; + + @Parameter(required = true, readonly = true, defaultValue = "${project.remoteArtifactRepositories}") + protected List remoteRepositories; + + @Parameter(readonly = true, defaultValue = "${plugin.artifacts}") + protected List pluginArtifacts; + + @Parameter(defaultValue = "${project.build.outputDirectory}") + protected File classFiles; + + @Parameter + protected List compileScopes; + + @Parameter + protected boolean minifying = true; + + @Parameter + protected String mainClass; + + @Parameter + protected Properties properties; + + @Parameter + protected boolean debugInformationGenerated; + + @Parameter + protected boolean sourceMapsGenerated; + + @Parameter + protected boolean sourceFilesCopied; + + @Parameter + protected boolean incremental; + + @Parameter + protected String[] transformers; + + protected ClassLoader classLoader; + + protected abstract File getTargetDirectory(); + + protected final List instantiateTransformers(ClassLoader classLoader) + throws MojoExecutionException { + List transformerInstances = new ArrayList<>(); + if (transformers == null) { + return transformerInstances; + } + for (String transformerName : transformers) { + Class transformerRawType; + try { + transformerRawType = Class.forName(transformerName, true, classLoader); + } catch (ClassNotFoundException e) { + throw new MojoExecutionException("Transformer not found: " + transformerName, e); + } + if (!ClassHolderTransformer.class.isAssignableFrom(transformerRawType)) { + throw new MojoExecutionException("Transformer " + transformerName + " is not subtype of " + + ClassHolderTransformer.class.getName()); + } + Class transformerType = transformerRawType.asSubclass( + ClassHolderTransformer.class); + Constructor ctor; + try { + ctor = transformerType.getConstructor(); + } catch (NoSuchMethodException e) { + throw new MojoExecutionException("Transformer " + transformerName + " has no default constructor"); + } + try { + ClassHolderTransformer transformer = ctor.newInstance(); + transformerInstances.add(transformer); + } catch (InstantiationException | IllegalAccessException | InvocationTargetException e) { + throw new MojoExecutionException("Error instantiating transformer " + transformerName, e); + } + } + return transformerInstances; + } + + protected void setupTool(BaseTeaVMTool tool) throws MojoExecutionException { + tool.setLog(new MavenTeaVMToolLog(getLog())); + try { + ClassLoader classLoader = prepareClassLoader(); + tool.setClassLoader(classLoader); + tool.setMinifying(minifying); + tool.setTargetDirectory(getTargetDirectory()); + tool.getTransformers().addAll(instantiateTransformers(classLoader)); + if (sourceFilesCopied) { + for (SourceFileProvider provider : getSourceFileProviders()) { + tool.addSourceFileProvider(provider); + } + } + if (properties != null) { + tool.getProperties().putAll(properties); + } + tool.setIncremental(incremental); + tool.setDebugInformationGenerated(debugInformationGenerated); + tool.setSourceMapsFileGenerated(sourceMapsGenerated); + tool.setSourceFilesCopied(sourceFilesCopied); + } catch (RuntimeException e) { + throw new MojoExecutionException("Unexpected error occured", e); + } + } + + protected final ClassLoader prepareClassLoader() throws MojoExecutionException { + try { + Log log = getLog(); + log.info("Preparing classpath for JavaScript generation"); + List urls = new ArrayList<>(); + StringBuilder classpath = new StringBuilder(); + for (Artifact artifact : project.getArtifacts()) { + if (!filterByScope(artifact)) { + continue; + } + File file = artifact.getFile(); + if (classpath.length() > 0) { + classpath.append(':'); + } + classpath.append(file.getPath()); + urls.add(file.toURI().toURL()); + } + if (classpath.length() > 0) { + classpath.append(':'); + } + classpath.append(classFiles.getPath()); + urls.add(classFiles.toURI().toURL()); + for (File additionalEntry : getAdditionalClassPath()) { + classpath.append(':').append(additionalEntry.getPath()); + urls.add(additionalEntry.toURI().toURL()); + } + log.info("Using the following classpath for JavaScript generation: " + classpath); + classLoader = new URLClassLoader(urls.toArray(new URL[urls.size()]), + AbstractJavascriptMojo.class.getClassLoader()); + return classLoader; + } catch (MalformedURLException e) { + throw new MojoExecutionException("Error gathering classpath information", e); + } + } + + protected List getAdditionalClassPath() { + return Collections.emptyList(); + } + + protected boolean filterByScope(Artifact artifact) { + return compileScopes == null ? isSupportedScope(artifact.getScope()) + : compileScopes.contains(artifact.getScope()); + } + + protected boolean isSupportedScope(String scope) { + switch (scope) { + case Artifact.SCOPE_COMPILE: + case Artifact.SCOPE_PROVIDED: + case Artifact.SCOPE_SYSTEM: + return true; + default: + return false; + } + } + + protected final List getSourceFileProviders() { + MavenSourceFileProviderLookup lookup = new MavenSourceFileProviderLookup(); + lookup.setMavenProject(project); + lookup.setRepositorySystem(repositorySystem); + lookup.setLocalRepository(localRepository); + lookup.setRemoteRepositories(remoteRepositories); + lookup.setPluginDependencies(pluginArtifacts); + return lookup.resolve(); + } +} diff --git a/tools/maven/plugin/src/main/java/org/teavm/maven/BuildJavascriptMojo.java b/tools/maven/plugin/src/main/java/org/teavm/maven/BuildJavascriptMojo.java index 42c47edbf..511dd0cb1 100644 --- a/tools/maven/plugin/src/main/java/org/teavm/maven/BuildJavascriptMojo.java +++ b/tools/maven/plugin/src/main/java/org/teavm/maven/BuildJavascriptMojo.java @@ -16,33 +16,16 @@ package org.teavm.maven; import java.io.File; -import java.lang.reflect.Constructor; -import java.lang.reflect.InvocationTargetException; -import java.net.MalformedURLException; -import java.net.URL; -import java.net.URLClassLoader; -import java.util.ArrayList; import java.util.Arrays; -import java.util.HashSet; -import java.util.List; -import java.util.Properties; -import java.util.Set; -import org.apache.maven.artifact.Artifact; -import org.apache.maven.artifact.repository.MavenArtifactRepository; -import org.apache.maven.plugin.AbstractMojo; import org.apache.maven.plugin.MojoExecutionException; import org.apache.maven.plugin.logging.Log; -import org.apache.maven.plugins.annotations.Component; +import org.apache.maven.plugins.annotations.LifecyclePhase; import org.apache.maven.plugins.annotations.Mojo; import org.apache.maven.plugins.annotations.Parameter; import org.apache.maven.plugins.annotations.ResolutionScope; -import org.apache.maven.project.MavenProject; -import org.apache.maven.repository.RepositorySystem; -import org.teavm.model.ClassHolderTransformer; import org.teavm.tooling.ClassAlias; import org.teavm.tooling.MethodAlias; import org.teavm.tooling.RuntimeCopyOperation; -import org.teavm.tooling.SourceFileProvider; import org.teavm.tooling.TeaVMTool; import org.teavm.tooling.TeaVMToolException; @@ -50,72 +33,25 @@ import org.teavm.tooling.TeaVMToolException; * * @author Alexey Andreev */ -@Mojo(name = "build-javascript", requiresDependencyResolution = ResolutionScope.COMPILE_PLUS_RUNTIME, - requiresDependencyCollection = ResolutionScope.COMPILE_PLUS_RUNTIME) -public class BuildJavascriptMojo extends AbstractMojo { - @Component - private MavenProject project; - - @Component - private RepositorySystem repositorySystem; - - @Parameter(required = true, readonly = true, defaultValue = "${localRepository}") - private MavenArtifactRepository localRepository; - - @Parameter(required = true, readonly = true, defaultValue = "${project.remoteArtifactRepositories}") - private List remoteRepositories; - - @Parameter(readonly = true, defaultValue = "${plugin.artifacts}") - private List pluginArtifacts; - +@Mojo(name = "compile", requiresDependencyResolution = ResolutionScope.COMPILE_PLUS_RUNTIME, + requiresDependencyCollection = ResolutionScope.COMPILE_PLUS_RUNTIME, + defaultPhase = LifecyclePhase.PROCESS_CLASSES) +public class BuildJavascriptMojo extends AbstractJavascriptMojo { @Parameter(defaultValue = "${project.build.directory}/javascript") private File targetDirectory; - @Parameter(defaultValue = "${project.build.outputDirectory}") - private File classFiles; - - @Parameter - private List compileScopes; - @Parameter private String targetFileName = "classes.js"; - @Parameter - private boolean minifying = true; - @Parameter private String mainClass; - @Parameter - private RuntimeCopyOperation runtime = RuntimeCopyOperation.SEPARATE; - - @Parameter - private Properties properties; - @Parameter private boolean mainPageIncluded; @Parameter private boolean bytecodeLogging; - @Parameter - private boolean debugInformationGenerated; - - @Parameter - private boolean sourceMapsGenerated; - - @Parameter - private boolean sourceFilesCopied; - - @Parameter - private boolean incremental; - - @Parameter(defaultValue = "${project.build.directory}/teavm-cache") - private File cacheDirectory; - - @Parameter - private String[] transformers; - @Parameter private ClassAlias[] classAliases; @@ -125,152 +61,37 @@ public class BuildJavascriptMojo extends AbstractMojo { @Parameter private boolean stopOnErrors = true; + @Parameter + protected RuntimeCopyOperation runtime = RuntimeCopyOperation.SEPARATE; + + @Parameter(defaultValue = "${project.build.directory}/teavm-cache") + protected File cacheDirectory; + private TeaVMTool tool = new TeaVMTool(); - public void setProject(MavenProject project) { - this.project = project; - } - - public void setTargetDirectory(File targetDirectory) { - this.targetDirectory = targetDirectory; - } - - public void setTargetFileName(String targetFileName) { - this.targetFileName = targetFileName; - } - - public void setClassFiles(File classFiles) { - this.classFiles = classFiles; - } - - public void setMinifying(boolean minifying) { - this.minifying = minifying; - } - - public void setBytecodeLogging(boolean bytecodeLogging) { - this.bytecodeLogging = bytecodeLogging; - } - - public void setRuntimeCopy(RuntimeCopyOperation runtimeCopy) { - this.runtime = runtimeCopy; - } - - public void setMainPageIncluded(boolean mainPageIncluded) { - this.mainPageIncluded = mainPageIncluded; - } - - public void setCompileScopes(List compileScopes) { - this.compileScopes = compileScopes; - } - - public void setMainClass(String mainClass) { - this.mainClass = mainClass; - } - - public String[] getTransformers() { - return transformers; - } - - public void setTransformers(String[] transformers) { - this.transformers = transformers; - } - - public void setProperties(Properties properties) { - this.properties = properties; - } - - public void setClassAliases(ClassAlias[] classAliases) { - this.classAliases = classAliases; - } - - public void setMethodAliases(MethodAlias[] methodAliases) { - this.methodAliases = methodAliases; - } - - public boolean isDebugInformationGenerated() { - return debugInformationGenerated; - } - - public void setDebugInformationGenerated(boolean debugInformationGenerated) { - this.debugInformationGenerated = debugInformationGenerated; - } - - public boolean isSourceMapsGenerated() { - return sourceMapsGenerated; - } - - public void setSourceMapsGenerated(boolean sourceMapsGenerated) { - this.sourceMapsGenerated = sourceMapsGenerated; - } - - public boolean isSourceFilesCopied() { - return sourceFilesCopied; - } - - public void setSourceFilesCopied(boolean sourceFilesCopied) { - this.sourceFilesCopied = sourceFilesCopied; - } - - public boolean isIncremental() { - return incremental; - } - - public void setIncremental(boolean incremental) { - this.incremental = incremental; - } - - public void setStopOnErrors(boolean stopOnErrors) { - this.stopOnErrors = stopOnErrors; - } - - public File getCacheDirectory() { - return cacheDirectory; - } - - public void setCacheDirectory(File cacheDirectory) { - this.cacheDirectory = cacheDirectory; + @Override + protected File getTargetDirectory() { + return targetDirectory; } @Override public void execute() throws MojoExecutionException { Log log = getLog(); + setupTool(tool); tool.setLog(new MavenTeaVMToolLog(log)); try { - ClassLoader classLoader = prepareClassLoader(); - tool.setClassLoader(classLoader); tool.setBytecodeLogging(bytecodeLogging); tool.setMainClass(mainClass); tool.setMainPageIncluded(mainPageIncluded); - tool.setMinifying(minifying); tool.setRuntime(runtime); - tool.setTargetDirectory(targetDirectory); tool.setTargetFileName(targetFileName); - tool.getTransformers().addAll(instantiateTransformers(classLoader)); - if (sourceFilesCopied) { - MavenSourceFileProviderLookup lookup = new MavenSourceFileProviderLookup(); - lookup.setMavenProject(project); - lookup.setRepositorySystem(repositorySystem); - lookup.setLocalRepository(localRepository); - lookup.setRemoteRepositories(remoteRepositories); - lookup.setPluginDependencies(pluginArtifacts); - for (SourceFileProvider provider : lookup.resolve()) { - tool.addSourceFileProvider(provider); - } - } if (classAliases != null) { tool.getClassAliases().addAll(Arrays.asList(classAliases)); } if (methodAliases != null) { tool.getMethodAliases().addAll(Arrays.asList(methodAliases)); } - if (properties != null) { - tool.getProperties().putAll(properties); - } tool.setCacheDirectory(cacheDirectory); - tool.setIncremental(incremental); - tool.setDebugInformationGenerated(debugInformationGenerated); - tool.setSourceMapsFileGenerated(sourceMapsGenerated); - tool.setSourceFilesCopied(sourceFilesCopied); tool.generate(); if (stopOnErrors && !tool.getProblemProvider().getSevereProblems().isEmpty()) { throw new MojoExecutionException("Build error"); @@ -281,75 +102,4 @@ public class BuildJavascriptMojo extends AbstractMojo { throw new MojoExecutionException("IO error occured", e); } } - - private List instantiateTransformers(ClassLoader classLoader) - throws MojoExecutionException { - List transformerInstances = new ArrayList<>(); - if (transformers == null) { - return transformerInstances; - } - for (String transformerName : transformers) { - Class transformerRawType; - try { - transformerRawType = Class.forName(transformerName, true, classLoader); - } catch (ClassNotFoundException e) { - throw new MojoExecutionException("Transformer not found: " + transformerName, e); - } - if (!ClassHolderTransformer.class.isAssignableFrom(transformerRawType)) { - throw new MojoExecutionException("Transformer " + transformerName + " is not subtype of " + - ClassHolderTransformer.class.getName()); - } - Class transformerType = transformerRawType.asSubclass( - ClassHolderTransformer.class); - Constructor ctor; - try { - ctor = transformerType.getConstructor(); - } catch (NoSuchMethodException e) { - throw new MojoExecutionException("Transformer " + transformerName + " has no default constructor"); - } - try { - ClassHolderTransformer transformer = ctor.newInstance(); - transformerInstances.add(transformer); - } catch (InstantiationException | IllegalAccessException | InvocationTargetException e) { - throw new MojoExecutionException("Error instantiating transformer " + transformerName, e); - } - } - return transformerInstances; - } - - private ClassLoader prepareClassLoader() throws MojoExecutionException { - try { - Log log = getLog(); - log.info("Preparing classpath for JavaScript generation"); - List urls = new ArrayList<>(); - StringBuilder classpath = new StringBuilder(); - Set scopes; - if (compileScopes == null) { - scopes = new HashSet<>(Arrays.asList( - Artifact.SCOPE_COMPILE, Artifact.SCOPE_PROVIDED, Artifact.SCOPE_SYSTEM)); - } else { - scopes = new HashSet<>(compileScopes); - } - for (Artifact artifact : project.getArtifacts()) { - if (!scopes.contains(artifact.getScope())) { - continue; - } - File file = artifact.getFile(); - if (classpath.length() > 0) { - classpath.append(':'); - } - classpath.append(file.getPath()); - urls.add(file.toURI().toURL()); - } - if (classpath.length() > 0) { - classpath.append(':'); - } - classpath.append(classFiles.getPath()); - urls.add(classFiles.toURI().toURL()); - log.info("Using the following classpath for JavaScript generation: " + classpath); - return new URLClassLoader(urls.toArray(new URL[urls.size()]), BuildJavascriptMojo.class.getClassLoader()); - } catch (MalformedURLException e) { - throw new MojoExecutionException("Error gathering classpath information", e); - } - } } diff --git a/tools/maven/plugin/src/main/java/org/teavm/maven/BuildJavascriptTestMojo.java b/tools/maven/plugin/src/main/java/org/teavm/maven/BuildJavascriptTestMojo.java index 3f1ff546e..a5c702111 100644 --- a/tools/maven/plugin/src/main/java/org/teavm/maven/BuildJavascriptTestMojo.java +++ b/tools/maven/plugin/src/main/java/org/teavm/maven/BuildJavascriptTestMojo.java @@ -21,8 +21,6 @@ import java.lang.reflect.Constructor; import java.lang.reflect.InvocationTargetException; import java.net.MalformedURLException; import java.net.URL; -import java.net.URLClassLoader; -import java.util.ArrayList; import java.util.Arrays; import java.util.Enumeration; import java.util.HashSet; @@ -33,55 +31,31 @@ import java.util.jar.JarEntry; import java.util.jar.JarFile; import org.apache.commons.io.FilenameUtils; import org.apache.maven.artifact.Artifact; -import org.apache.maven.artifact.repository.MavenArtifactRepository; -import org.apache.maven.plugin.AbstractMojo; import org.apache.maven.plugin.MojoExecutionException; import org.apache.maven.plugin.MojoFailureException; import org.apache.maven.plugin.logging.Log; -import org.apache.maven.plugins.annotations.Component; +import org.apache.maven.plugins.annotations.LifecyclePhase; import org.apache.maven.plugins.annotations.Mojo; import org.apache.maven.plugins.annotations.Parameter; import org.apache.maven.plugins.annotations.ResolutionScope; -import org.apache.maven.project.MavenProject; -import org.apache.maven.repository.RepositorySystem; -import org.teavm.model.ClassHolderTransformer; import org.teavm.testing.JUnitTestAdapter; import org.teavm.testing.TestAdapter; -import org.teavm.tooling.SourceFileProvider; -import org.teavm.tooling.TeaVMTestTool; import org.teavm.tooling.TeaVMToolException; +import org.teavm.tooling.testing.TeaVMTestTool; /** * * @author Alexey Andreev */ -@Mojo(name = "build-test-javascript", requiresDependencyResolution = ResolutionScope.TEST, - requiresDependencyCollection = ResolutionScope.TEST) -public class BuildJavascriptTestMojo extends AbstractMojo { +@Mojo(name = "testCompile", requiresDependencyResolution = ResolutionScope.TEST, + requiresDependencyCollection = ResolutionScope.TEST, + defaultPhase = LifecyclePhase.PROCESS_TEST_CLASSES) +public class BuildJavascriptTestMojo extends AbstractJavascriptMojo { private static Set testScopes = new HashSet<>(Arrays.asList( Artifact.SCOPE_COMPILE, Artifact.SCOPE_TEST, Artifact.SCOPE_SYSTEM, Artifact.SCOPE_RUNTIME, Artifact.SCOPE_PROVIDED)); - - @Component - private MavenProject project; - - @Component - private RepositorySystem repositorySystem; - - @Parameter(required = true, readonly = true, defaultValue = "${localRepository}") - private MavenArtifactRepository localRepository; - - @Parameter(required = true, readonly = true, defaultValue = "${project.remoteArtifactRepositories}") - private List remoteRepositories; - - @Parameter(readonly = true, defaultValue = "${plugin.artifacts}") - private List pluginArtifacts; - @Parameter(defaultValue = "${project.build.directory}/javascript-test") - private File outputDir; - - @Parameter(defaultValue = "${project.build.outputDirectory}") - private File classFiles; + private File targetDirectory; @Parameter(defaultValue = "${project.build.testOutputDirectory}") private File testFiles; @@ -92,9 +66,6 @@ public class BuildJavascriptTestMojo extends AbstractMojo { @Parameter private String[] excludeWildcards = new String[0]; - @Parameter - private boolean minifying = true; - @Parameter private boolean scanDependencies; @@ -104,9 +75,6 @@ public class BuildJavascriptTestMojo extends AbstractMojo { @Parameter private String adapterClass = JUnitTestAdapter.class.getName(); - @Parameter - private String[] transformers; - @Parameter private String[] additionalScripts; @@ -116,15 +84,6 @@ public class BuildJavascriptTestMojo extends AbstractMojo { @Parameter private boolean incremental; - @Parameter - private boolean debugInformationGenerated; - - @Parameter - private boolean sourceMapsGenerated; - - @Parameter - private boolean sourceFilesCopied; - @Parameter private URL seleniumURL; @@ -132,86 +91,6 @@ public class BuildJavascriptTestMojo extends AbstractMojo { private TeaVMTestTool tool = new TeaVMTestTool(); - public void setProject(MavenProject project) { - this.project = project; - } - - public void setOutputDir(File outputDir) { - this.outputDir = outputDir; - } - - public void setClassFiles(File classFiles) { - this.classFiles = classFiles; - } - - public void setTestFiles(File testFiles) { - this.testFiles = testFiles; - } - - public void setMinifying(boolean minifying) { - this.minifying = minifying; - } - - public void setNumThreads(int numThreads) { - this.numThreads = numThreads; - } - - public void setAdapterClass(String adapterClass) { - this.adapterClass = adapterClass; - } - - public void setWildcards(String[] wildcards) { - this.wildcards = wildcards; - } - - public void setExcludeWildcards(String[] excludeWildcards) { - this.excludeWildcards = excludeWildcards; - } - - public String[] getTransformers() { - return transformers; - } - - public void setTransformers(String[] transformers) { - this.transformers = transformers; - } - - public void setProperties(Properties properties) { - this.properties = properties; - } - - public void setIncremental(boolean incremental) { - this.incremental = incremental; - } - - public boolean isDebugInformationGenerated() { - return debugInformationGenerated; - } - - public void setDebugInformationGenerated(boolean debugInformationGenerated) { - this.debugInformationGenerated = debugInformationGenerated; - } - - public boolean isSourceMapsGenerated() { - return sourceMapsGenerated; - } - - public void setSourceMapsGenerated(boolean sourceMapsGenerated) { - this.sourceMapsGenerated = sourceMapsGenerated; - } - - public boolean isSourceFilesCopied() { - return sourceFilesCopied; - } - - public void setSourceFilesCopied(boolean sourceFilesCopied) { - this.sourceFilesCopied = sourceFilesCopied; - } - - public void setSeleniumURL(URL seleniumURL) { - this.seleniumURL = seleniumURL; - } - @Override public void execute() throws MojoExecutionException, MojoFailureException { if (System.getProperty("maven.test.skip", "false").equals("true") || @@ -220,54 +99,21 @@ public class BuildJavascriptTestMojo extends AbstractMojo { return; } - seleniumRunner = new SeleniumTestRunner(); - seleniumRunner.setUrl(seleniumURL); - seleniumRunner.setLog(getLog()); - seleniumRunner.detectSelenium(); + setupTool(tool); try { - final ClassLoader classLoader = prepareClassLoader(); getLog().info("Searching for tests in the directory `" + testFiles.getAbsolutePath() + "'"); - tool.setClassLoader(classLoader); tool.setAdapter(createAdapter(classLoader)); findTestClasses(classLoader, testFiles, ""); if (scanDependencies) { findTestsInDependencies(classLoader); } - tool.getTransformers().addAll(instantiateTransformers(classLoader)); - tool.setLog(new MavenTeaVMToolLog(getLog())); - tool.setOutputDir(outputDir); tool.setNumThreads(numThreads); - tool.setMinifying(minifying); - tool.setIncremental(incremental); - tool.setDebugInformationGenerated(debugInformationGenerated); - tool.setSourceMapsGenerated(sourceMapsGenerated); - tool.setSourceFilesCopied(sourceFilesCopied); - if (sourceFilesCopied) { - MavenSourceFileProviderLookup lookup = new MavenSourceFileProviderLookup(); - lookup.setMavenProject(project); - lookup.setRepositorySystem(repositorySystem); - lookup.setLocalRepository(localRepository); - lookup.setRemoteRepositories(remoteRepositories); - lookup.setPluginDependencies(pluginArtifacts); - for (SourceFileProvider provider : lookup.resolve()) { - tool.addSourceFileProvider(provider); - } - } - if (properties != null) { - tool.getProperties().putAll(properties); - } if (additionalScripts != null) { tool.getAdditionalScripts().addAll(Arrays.asList(additionalScripts)); } - tool.addListener(testCase -> seleniumRunner.run(testCase)); tool.generate(); - seleniumRunner.stopSelenium(); - seleniumRunner.waitForSelenium(); - processReport(seleniumRunner.getReport()); } catch (TeaVMToolException e) { throw new MojoFailureException("Error occured generating JavaScript files", e); - } finally { - seleniumRunner.stopSelenium(); } } @@ -318,38 +164,6 @@ public class BuildJavascriptTestMojo extends AbstractMojo { } } - private ClassLoader prepareClassLoader() throws MojoExecutionException { - try { - Log log = getLog(); - log.info("Preparing classpath for JavaScript test generation"); - List urls = new ArrayList<>(); - StringBuilder classpath = new StringBuilder(); - for (Artifact artifact : project.getArtifacts()) { - if (!testScopes.contains(artifact.getScope())) { - continue; - } - File file = artifact.getFile(); - if (classpath.length() > 0) { - classpath.append(':'); - } - classpath.append(file.getPath()); - urls.add(file.toURI().toURL()); - } - if (classpath.length() > 0) { - classpath.append(':'); - } - classpath.append(testFiles.getPath()); - urls.add(testFiles.toURI().toURL()); - classpath.append(':').append(classFiles.getPath()); - urls.add(classFiles.toURI().toURL()); - log.info("Using the following classpath for JavaScript test generation: " + classpath); - return new URLClassLoader(urls.toArray(new URL[urls.size()]), - BuildJavascriptTestMojo.class.getClassLoader()); - } catch (MalformedURLException e) { - throw new MojoExecutionException("Error gathering classpath information", e); - } - } - private void findTestsInDependencies(ClassLoader classLoader) throws MojoExecutionException { try { Log log = getLog(); @@ -430,40 +244,18 @@ public class BuildJavascriptTestMojo extends AbstractMojo { } } - - private List instantiateTransformers(ClassLoader classLoader) - throws MojoExecutionException { - List transformerInstances = new ArrayList<>(); - if (transformers == null) { - return transformerInstances; - } - for (String transformerName : transformers) { - Class transformerRawType; - try { - transformerRawType = Class.forName(transformerName, true, classLoader); - } catch (ClassNotFoundException e) { - throw new MojoExecutionException("Transformer not found: " + transformerName, e); - } - if (!ClassHolderTransformer.class.isAssignableFrom(transformerRawType)) { - throw new MojoExecutionException("Transformer " + transformerName + " is not subtype of " + - ClassHolderTransformer.class.getName()); - } - Class transformerType = transformerRawType.asSubclass( - ClassHolderTransformer.class); - Constructor ctor; - try { - ctor = transformerType.getConstructor(); - } catch (NoSuchMethodException e) { - throw new MojoExecutionException("Transformer " + transformerName + " has no default constructor"); - } - try { - ClassHolderTransformer transformer = ctor.newInstance(); - transformerInstances.add(transformer); - } catch (InstantiationException | IllegalAccessException | InvocationTargetException e) { - throw new MojoExecutionException("Error instantiating transformer " + transformerName, e); - } - } - return transformerInstances; + @Override + protected File getTargetDirectory() { + return targetDirectory; } + @Override + protected List getAdditionalClassPath() { + return Arrays.asList(testFiles); + } + + @Override + protected boolean isSupportedScope(String scope) { + return testScopes.contains(scope); + } } diff --git a/tools/maven/plugin/src/main/java/org/teavm/maven/MavenSourceFileProviderLookup.java b/tools/maven/plugin/src/main/java/org/teavm/maven/MavenSourceFileProviderLookup.java index 42887a97b..9d6567645 100644 --- a/tools/maven/plugin/src/main/java/org/teavm/maven/MavenSourceFileProviderLookup.java +++ b/tools/maven/plugin/src/main/java/org/teavm/maven/MavenSourceFileProviderLookup.java @@ -26,9 +26,9 @@ import org.apache.maven.artifact.resolver.ArtifactResolutionRequest; import org.apache.maven.artifact.resolver.ArtifactResolutionResult; import org.apache.maven.project.MavenProject; import org.apache.maven.repository.RepositorySystem; -import org.teavm.tooling.DirectorySourceFileProvider; -import org.teavm.tooling.JarSourceFileProvider; -import org.teavm.tooling.SourceFileProvider; +import org.teavm.tooling.sources.DirectorySourceFileProvider; +import org.teavm.tooling.sources.JarSourceFileProvider; +import org.teavm.tooling.sources.SourceFileProvider; /** * diff --git a/tools/maven/plugin/src/main/java/org/teavm/maven/RunTestsMojo.java b/tools/maven/plugin/src/main/java/org/teavm/maven/RunTestsMojo.java new file mode 100644 index 000000000..9b6f3df63 --- /dev/null +++ b/tools/maven/plugin/src/main/java/org/teavm/maven/RunTestsMojo.java @@ -0,0 +1,31 @@ +/* + * Copyright 2015 Alexey Andreev. + * + * Licensed 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.teavm.maven; + +import java.io.File; +import org.apache.maven.plugins.annotations.LifecyclePhase; +import org.apache.maven.plugins.annotations.Mojo; +import org.apache.maven.plugins.annotations.Parameter; + +/** + * + * @author Alexey Andreev + */ +@Mojo(name = "run-tests", defaultPhase = LifecyclePhase.TEST) +public class RunTestsMojo { + @Parameter(defaultValue = "${project.build.directory}/javascript-tests") + private File targetDirectory; +} diff --git a/tools/maven/plugin/src/main/java/org/teavm/maven/SeleniumTestRunner.java b/tools/maven/plugin/src/main/java/org/teavm/maven/SeleniumTestRunner.java index bde8eef59..b42118682 100644 --- a/tools/maven/plugin/src/main/java/org/teavm/maven/SeleniumTestRunner.java +++ b/tools/maven/plugin/src/main/java/org/teavm/maven/SeleniumTestRunner.java @@ -35,7 +35,9 @@ import org.openqa.selenium.JavascriptExecutor; import org.openqa.selenium.WebDriver; import org.openqa.selenium.WebDriverException; import org.openqa.selenium.chrome.ChromeDriver; -import org.teavm.tooling.TeaVMTestCase; +import org.teavm.tooling.testing.TestCase; +import org.teavm.tooling.testing.TestGroup; +import org.teavm.tooling.testing.TestPlan; /** * @@ -43,13 +45,15 @@ import org.teavm.tooling.TeaVMTestCase; */ public class SeleniumTestRunner { private URL url; - private WebDriver webDriver; + private int numThreads = 1; + private ThreadLocal webDriver = new ThreadLocal<>(); private BlockingQueue seleniumTaskQueue = new LinkedBlockingQueue<>(); private CountDownLatch latch = new CountDownLatch(1); private volatile boolean seleniumStopped = false; private Log log; private List report = new CopyOnWriteArrayList<>(); private ThreadLocal> localReport = new ThreadLocal<>(); + private File directory = new File("."); public URL getUrl() { return url; @@ -63,28 +67,55 @@ public class SeleniumTestRunner { this.log = log; } - public void detectSelenium() { - if (url == null) { - return; - } - ChromeDriver driver = new ChromeDriver(); - webDriver = driver; - new Thread(() -> { - localReport.set(new ArrayList<>()); - while (!seleniumStopped) { - Runnable task; - try { - task = seleniumTaskQueue.poll(1, TimeUnit.SECONDS); - } catch (InterruptedException e) { - break; - } - if (task != null) { - task.run(); - } + public File getDirectory() { + return directory; + } + + public void setDirectory(File directory) { + this.directory = directory; + } + + public int getNumThreads() { + return numThreads; + } + + public void setNumThreads(int numThreads) { + this.numThreads = numThreads; + } + + public void run(TestPlan testPlan) { + initSelenium(); + for (TestGroup group : testPlan.getGroups()) { + for (TestCase testCase : group.getTestCases()) { + run(testPlan.getRuntimeScript(), testCase); } - report.addAll(localReport.get()); - localReport.remove(); - }).start(); + } + stopSelenium(); + waitForCompletion(); + } + + private void initSelenium() { + for (int i = 0; i < numThreads; ++i) { + new Thread(() -> { + ChromeDriver driver = new ChromeDriver(); + webDriver.set(driver); + localReport.set(new ArrayList<>()); + while (!seleniumStopped) { + Runnable task; + try { + task = seleniumTaskQueue.poll(1, TimeUnit.SECONDS); + } catch (InterruptedException e) { + break; + } + if (task != null) { + task.run(); + } + } + report.addAll(localReport.get()); + localReport.remove(); + webDriver.remove(); + }).start(); + } } private void addSeleniumTask(Runnable runnable) { @@ -93,14 +124,14 @@ public class SeleniumTestRunner { } } - public void stopSelenium() { + private void stopSelenium() { addSeleniumTask(() -> { seleniumStopped = true; latch.countDown(); }); } - public void waitForSelenium() { + private void waitForCompletion() { try { latch.await(); } catch (InterruptedException e) { @@ -108,21 +139,18 @@ public class SeleniumTestRunner { } } - public void run(TeaVMTestCase testCase) { - addSeleniumTask(() -> runImpl(testCase)); + private void run(String runtimeScript, TestCase testCase) { + addSeleniumTask(() -> runImpl(runtimeScript, testCase)); } - private void runImpl(TeaVMTestCase testCase) { - if (webDriver == null) { - return; - } - webDriver.manage().timeouts().setScriptTimeout(5, TimeUnit.SECONDS); + private void runImpl(String runtimeScript, TestCase testCase) { + webDriver.get().manage().timeouts().setScriptTimeout(2, TimeUnit.SECONDS); JavascriptExecutor js = (JavascriptExecutor) webDriver; try { String result = (String) js.executeAsyncScript( readResource("teavm-selenium.js"), - readFile(testCase.getRuntimeScript()), - readFile(testCase.getTestScript()), + readFile(new File(directory, runtimeScript)), + readFile(new File(directory, testCase.getTestScript())), readResource("teavm-selenium-adapter.js")); ObjectMapper mapper = new ObjectMapper(); ObjectNode resultObject = (ObjectNode) mapper.readTree(result); diff --git a/tools/maven/pom.xml b/tools/maven/pom.xml index 84507fd9b..f20bff3e7 100644 --- a/tools/maven/pom.xml +++ b/tools/maven/pom.xml @@ -21,6 +21,7 @@ org.teavm teavm 0.4.0-SNAPSHOT + ../.. teavm-maven From d007b0c8ac49d8728032c24d161b59ae9583bb25 Mon Sep 17 00:00:00 2001 From: Alexey Andreev Date: Fri, 9 Oct 2015 18:30:31 +0300 Subject: [PATCH 05/16] TeaVM test runner as a separate mojo --- tests/pom.xml | 7 ++- .../teavm/tooling/testing/TeaVMTestTool.java | 3 +- .../org/teavm/tooling/testing/TestCase.java | 7 +-- .../org/teavm/tooling/testing/TestPlan.java | 5 +- .../teavm/maven/BuildJavascriptTestMojo.java | 37 ++++------- .../java/org/teavm/maven/RunTestsMojo.java | 62 +++++++++++++++++-- .../org/teavm/maven/SeleniumTestRunner.java | 26 ++++---- 7 files changed, 99 insertions(+), 48 deletions(-) diff --git a/tests/pom.xml b/tests/pom.xml index 8518a31dd..28955d1bd 100644 --- a/tests/pom.xml +++ b/tests/pom.xml @@ -86,9 +86,14 @@ en, en_US, en_GB, ru, ru_RU ${teavm.test.incremental} - http://127.0.0.1:4444/wd/hub + + run-javascript-tests + + test + + diff --git a/tools/core/src/main/java/org/teavm/tooling/testing/TeaVMTestTool.java b/tools/core/src/main/java/org/teavm/tooling/testing/TeaVMTestTool.java index 9f0903ddd..b65841aa6 100644 --- a/tools/core/src/main/java/org/teavm/tooling/testing/TeaVMTestTool.java +++ b/tools/core/src/main/java/org/teavm/tooling/testing/TeaVMTestTool.java @@ -364,7 +364,8 @@ public class TeaVMTestTool implements BaseTeaVMTool { testClass.getMethods().add(testMethod); String debugTable = debugInformationGenerated ? testMethod.getFileName() + ".teavmdbg" : null; - cases.add(new TestCase(ref, testMethod.getFileName(), debugTable, testMethod.getExpectedExceptions())); + cases.add(new TestCase(ref.toString(), testMethod.getFileName(), debugTable, + testMethod.getExpectedExceptions())); ++testCount; } } diff --git a/tools/core/src/main/java/org/teavm/tooling/testing/TestCase.java b/tools/core/src/main/java/org/teavm/tooling/testing/TestCase.java index a534649b4..5c0ae9e1b 100644 --- a/tools/core/src/main/java/org/teavm/tooling/testing/TestCase.java +++ b/tools/core/src/main/java/org/teavm/tooling/testing/TestCase.java @@ -21,21 +21,20 @@ import com.fasterxml.jackson.annotation.JsonProperty; import java.util.ArrayList; import java.util.Collections; import java.util.List; -import org.teavm.model.MethodReference; /** * * @author Alexey Andreev */ public class TestCase { - private MethodReference testMethod; + private String testMethod; private String testScript; private String debugTable; private List expectedExceptions = new ArrayList<>(); @JsonCreator public TestCase( - @JsonProperty("testMethod") MethodReference testMethod, + @JsonProperty("testMethod") String testMethod, @JsonProperty("script") String testScript, @JsonProperty("debugTable") String debugTable, @JsonProperty("expectedExceptions") List expectedExceptions) { @@ -46,7 +45,7 @@ public class TestCase { } @JsonGetter - public MethodReference getTestMethod() { + public String getTestMethod() { return testMethod; } diff --git a/tools/core/src/main/java/org/teavm/tooling/testing/TestPlan.java b/tools/core/src/main/java/org/teavm/tooling/testing/TestPlan.java index e5eefd289..32ce4b364 100644 --- a/tools/core/src/main/java/org/teavm/tooling/testing/TestPlan.java +++ b/tools/core/src/main/java/org/teavm/tooling/testing/TestPlan.java @@ -16,6 +16,7 @@ package org.teavm.tooling.testing; import com.fasterxml.jackson.annotation.JsonCreator; +import com.fasterxml.jackson.annotation.JsonGetter; import com.fasterxml.jackson.annotation.JsonProperty; import java.util.ArrayList; import java.util.Collections; @@ -32,15 +33,17 @@ public class TestPlan { @JsonCreator public TestPlan( @JsonProperty("runtimeScript") String runtimeScript, - @JsonProperty("groupList") List groups) { + @JsonProperty("groups") List groups) { this.runtimeScript = runtimeScript; this.groups = Collections.unmodifiableList(new ArrayList<>(groups)); } + @JsonGetter public String getRuntimeScript() { return runtimeScript; } + @JsonGetter public List getGroups() { return groups; } diff --git a/tools/maven/plugin/src/main/java/org/teavm/maven/BuildJavascriptTestMojo.java b/tools/maven/plugin/src/main/java/org/teavm/maven/BuildJavascriptTestMojo.java index a5c702111..de0617ebd 100644 --- a/tools/maven/plugin/src/main/java/org/teavm/maven/BuildJavascriptTestMojo.java +++ b/tools/maven/plugin/src/main/java/org/teavm/maven/BuildJavascriptTestMojo.java @@ -15,12 +15,15 @@ */ package org.teavm.maven; +import com.fasterxml.jackson.databind.ObjectMapper; import java.io.File; +import java.io.FileOutputStream; import java.io.IOException; +import java.io.OutputStreamWriter; +import java.io.Writer; import java.lang.reflect.Constructor; import java.lang.reflect.InvocationTargetException; import java.net.MalformedURLException; -import java.net.URL; import java.util.Arrays; import java.util.Enumeration; import java.util.HashSet; @@ -42,6 +45,7 @@ import org.teavm.testing.JUnitTestAdapter; import org.teavm.testing.TestAdapter; import org.teavm.tooling.TeaVMToolException; import org.teavm.tooling.testing.TeaVMTestTool; +import org.teavm.tooling.testing.TestPlan; /** * @@ -84,11 +88,6 @@ public class BuildJavascriptTestMojo extends AbstractJavascriptMojo { @Parameter private boolean incremental; - @Parameter - private URL seleniumURL; - - private SeleniumTestRunner seleniumRunner; - private TeaVMTestTool tool = new TeaVMTestTool(); @Override @@ -111,29 +110,19 @@ public class BuildJavascriptTestMojo extends AbstractJavascriptMojo { if (additionalScripts != null) { tool.getAdditionalScripts().addAll(Arrays.asList(additionalScripts)); } - tool.generate(); + writePlan(tool.generate()); } catch (TeaVMToolException e) { throw new MojoFailureException("Error occured generating JavaScript files", e); } } - private void processReport(List report) throws MojoExecutionException { - if (report.isEmpty()) { - getLog().info("No tests ran"); - return; - } - - int failedTests = 0; - for (TestResult result : report) { - if (result.getStatus() != TestStatus.PASSED) { - failedTests++; - } - } - - if (failedTests > 0) { - throw new MojoExecutionException(failedTests + " of " + report.size() + " test(s) failed"); - } else { - getLog().info("All of " + report.size() + " tests successfully passed"); + private void writePlan(TestPlan plan) throws MojoExecutionException { + File file = new File(targetDirectory, "plan.json"); + try (Writer writer = new OutputStreamWriter(new FileOutputStream(file), "UTF-8")) { + ObjectMapper mapper = new ObjectMapper(); + mapper.writeValue(writer, plan); + } catch (IOException e) { + throw new MojoExecutionException("Error writing test plan", e); } } diff --git a/tools/maven/plugin/src/main/java/org/teavm/maven/RunTestsMojo.java b/tools/maven/plugin/src/main/java/org/teavm/maven/RunTestsMojo.java index 9b6f3df63..f89a3d176 100644 --- a/tools/maven/plugin/src/main/java/org/teavm/maven/RunTestsMojo.java +++ b/tools/maven/plugin/src/main/java/org/teavm/maven/RunTestsMojo.java @@ -15,17 +15,71 @@ */ package org.teavm.maven; +import com.fasterxml.jackson.databind.ObjectMapper; import java.io.File; +import java.io.FileInputStream; +import java.io.IOException; +import java.io.InputStreamReader; +import java.io.Reader; +import java.net.URL; +import java.util.List; +import org.apache.maven.plugin.AbstractMojo; +import org.apache.maven.plugin.MojoExecutionException; +import org.apache.maven.plugin.MojoFailureException; import org.apache.maven.plugins.annotations.LifecyclePhase; import org.apache.maven.plugins.annotations.Mojo; import org.apache.maven.plugins.annotations.Parameter; +import org.teavm.tooling.testing.TestPlan; /** * * @author Alexey Andreev */ -@Mojo(name = "run-tests", defaultPhase = LifecyclePhase.TEST) -public class RunTestsMojo { - @Parameter(defaultValue = "${project.build.directory}/javascript-tests") - private File targetDirectory; +@Mojo(name = "test", defaultPhase = LifecyclePhase.TEST) +public class RunTestsMojo extends AbstractMojo { + @Parameter(defaultValue = "${project.build.directory}/javascript-test") + private File testDirectory; + + @Parameter + private URL seleniumURL; + + @Override + public void execute() throws MojoExecutionException, MojoFailureException { + SeleniumTestRunner runner = new SeleniumTestRunner(); + runner.setLog(getLog()); + runner.setDirectory(testDirectory); + runner.setUrl(seleniumURL); + + TestPlan plan; + ObjectMapper mapper = new ObjectMapper(); + File file = new File(testDirectory, "plan.json"); + try (Reader reader = new InputStreamReader(new FileInputStream(file), "UTF-8")) { + plan = mapper.readValue(reader, TestPlan.class); + } catch (IOException e) { + throw new MojoExecutionException("Error reading test plan", e); + } + + runner.run(plan); + processReport(runner.getReport()); + } + + private void processReport(List report) throws MojoExecutionException { + if (report.isEmpty()) { + getLog().info("No tests ran"); + return; + } + + int failedTests = 0; + for (TestResult result : report) { + if (result.getStatus() != TestStatus.PASSED) { + failedTests++; + } + } + + if (failedTests > 0) { + throw new MojoExecutionException(failedTests + " of " + report.size() + " test(s) failed"); + } else { + getLog().info("All of " + report.size() + " tests successfully passed"); + } + } } diff --git a/tools/maven/plugin/src/main/java/org/teavm/maven/SeleniumTestRunner.java b/tools/maven/plugin/src/main/java/org/teavm/maven/SeleniumTestRunner.java index b42118682..836cfd405 100644 --- a/tools/maven/plugin/src/main/java/org/teavm/maven/SeleniumTestRunner.java +++ b/tools/maven/plugin/src/main/java/org/teavm/maven/SeleniumTestRunner.java @@ -35,6 +35,7 @@ import org.openqa.selenium.JavascriptExecutor; import org.openqa.selenium.WebDriver; import org.openqa.selenium.WebDriverException; import org.openqa.selenium.chrome.ChromeDriver; +import org.teavm.model.MethodReference; import org.teavm.tooling.testing.TestCase; import org.teavm.tooling.testing.TestGroup; import org.teavm.tooling.testing.TestPlan; @@ -48,7 +49,7 @@ public class SeleniumTestRunner { private int numThreads = 1; private ThreadLocal webDriver = new ThreadLocal<>(); private BlockingQueue seleniumTaskQueue = new LinkedBlockingQueue<>(); - private CountDownLatch latch = new CountDownLatch(1); + private CountDownLatch latch; private volatile boolean seleniumStopped = false; private Log log; private List report = new CopyOnWriteArrayList<>(); @@ -95,15 +96,16 @@ public class SeleniumTestRunner { } private void initSelenium() { + latch = new CountDownLatch(numThreads); for (int i = 0; i < numThreads; ++i) { new Thread(() -> { ChromeDriver driver = new ChromeDriver(); webDriver.set(driver); localReport.set(new ArrayList<>()); - while (!seleniumStopped) { + while (!seleniumStopped || !seleniumTaskQueue.isEmpty()) { Runnable task; try { - task = seleniumTaskQueue.poll(1, TimeUnit.SECONDS); + task = seleniumTaskQueue.poll(100, TimeUnit.MILLISECONDS); } catch (InterruptedException e) { break; } @@ -113,22 +115,19 @@ public class SeleniumTestRunner { } report.addAll(localReport.get()); localReport.remove(); + webDriver.get().close(); webDriver.remove(); + latch.countDown(); }).start(); } } private void addSeleniumTask(Runnable runnable) { - if (url != null) { - seleniumTaskQueue.add(runnable); - } + seleniumTaskQueue.add(runnable); } private void stopSelenium() { - addSeleniumTask(() -> { - seleniumStopped = true; - latch.countDown(); - }); + seleniumStopped = true; } private void waitForCompletion() { @@ -145,7 +144,7 @@ public class SeleniumTestRunner { private void runImpl(String runtimeScript, TestCase testCase) { webDriver.get().manage().timeouts().setScriptTimeout(2, TimeUnit.SECONDS); - JavascriptExecutor js = (JavascriptExecutor) webDriver; + JavascriptExecutor js = (JavascriptExecutor) webDriver.get(); try { String result = (String) js.executeAsyncScript( readResource("teavm-selenium.js"), @@ -155,15 +154,16 @@ public class SeleniumTestRunner { ObjectMapper mapper = new ObjectMapper(); ObjectNode resultObject = (ObjectNode) mapper.readTree(result); String status = resultObject.get("status").asText(); + MethodReference ref = MethodReference.parse(testCase.getTestMethod()); switch (status) { case "ok": log.info("Test passed: " + testCase.getTestMethod()); - localReport.get().add(TestResult.passed(testCase.getTestMethod())); + localReport.get().add(TestResult.passed(ref)); break; case "exception": { String stack = resultObject.get("stack").asText(); log.info("Test failed: " + testCase.getTestMethod()); - localReport.get().add(TestResult.error(testCase.getTestMethod(), stack)); + localReport.get().add(TestResult.error(ref, stack)); break; } } From d29339f0b8ee4d04d4e6763c93b24e68bad9956d Mon Sep 17 00:00:00 2001 From: Alexey Andreev Date: Fri, 9 Oct 2015 22:54:50 +0300 Subject: [PATCH 06/16] Test runner --- core/pom.xml | 5 ++ .../java/org/teavm/model/MethodReference.java | 4 ++ samples/pom.xml | 2 - tests/pom.xml | 10 ++++ tools/core/pom.xml | 12 +++++ .../eclipse/core-plugin/META-INF/MANIFEST.MF | 1 + tools/eclipse/m2e-plugin/META-INF/MANIFEST.MF | 2 +- .../m2e-plugin/lifecycle-mapping-metadata.xml | 2 +- .../eclipse/m2e/TeaVMProjectConfigurator.java | 2 +- tools/eclipse/plugin/META-INF/MANIFEST.MF | 3 +- .../teavm/eclipse/TeaVMProjectBuilder.java | 52 ++++++++++++++++--- .../teavm/maven/BuildJavascriptTestMojo.java | 7 --- .../java/org/teavm/maven/RunTestsMojo.java | 50 +++++++++++++++--- .../org/teavm/maven/SeleniumTestRunner.java | 30 ++++++++--- .../main/java/org/teavm/maven/TestReport.java | 16 ++++++ .../main/java/org/teavm/maven/TestResult.java | 32 ++++++++++-- .../main/java/org/teavm/maven/TestStatus.java | 3 +- .../resources/archetype-resources/pom.xml | 18 ++----- 18 files changed, 196 insertions(+), 55 deletions(-) create mode 100644 tools/maven/plugin/src/main/java/org/teavm/maven/TestReport.java diff --git a/core/pom.xml b/core/pom.xml index 798a6b5a8..98b1d0192 100644 --- a/core/pom.xml +++ b/core/pom.xml @@ -45,6 +45,11 @@ hppc 0.6.1 + + com.fasterxml.jackson.core + jackson-annotations + true + TeaVM core diff --git a/core/src/main/java/org/teavm/model/MethodReference.java b/core/src/main/java/org/teavm/model/MethodReference.java index a60d8b4ea..d5ed4a70f 100644 --- a/core/src/main/java/org/teavm/model/MethodReference.java +++ b/core/src/main/java/org/teavm/model/MethodReference.java @@ -15,6 +15,8 @@ */ package org.teavm.model; +import com.fasterxml.jackson.annotation.JsonCreator; +import com.fasterxml.jackson.annotation.JsonValue; import java.util.Arrays; /** @@ -132,6 +134,7 @@ public class MethodReference { } @Override + @JsonValue public String toString() { if (reprCache == null) { reprCache = className + "." + name + signatureToString(); @@ -139,6 +142,7 @@ public class MethodReference { return reprCache; } + @JsonCreator public static MethodReference parse(String string) { MethodReference reference = parseIfPossible(string); if (reference == null) { diff --git a/samples/pom.xml b/samples/pom.xml index 60292acad..fea836574 100644 --- a/samples/pom.xml +++ b/samples/pom.xml @@ -36,8 +36,6 @@ video async kotlin - \ No newline at end of file diff --git a/tests/pom.xml b/tests/pom.xml index 28955d1bd..17b57350d 100644 --- a/tests/pom.xml +++ b/tests/pom.xml @@ -27,6 +27,12 @@ TeaVM tests Project containing TeaVM tests, as it is impossible to test each module separately + + false + 1 + + + org.teavm @@ -93,6 +99,10 @@ test + + ${teavm.test.threads} + ${teavm.test.selenium} + diff --git a/tools/core/pom.xml b/tools/core/pom.xml index 7abaacfc8..54c00a376 100644 --- a/tools/core/pom.xml +++ b/tools/core/pom.xml @@ -24,6 +24,7 @@ ../.. teavm-tooling + bundle TeaVM tooling core TeaVM API that helps to create tooling @@ -59,6 +60,17 @@ org.apache.maven.plugins maven-javadoc-plugin + + org.apache.felix + maven-bundle-plugin + true + + + org.teavm.* + teavm-tooling + + + \ No newline at end of file diff --git a/tools/eclipse/core-plugin/META-INF/MANIFEST.MF b/tools/eclipse/core-plugin/META-INF/MANIFEST.MF index a0133cc02..b4bee0aa9 100644 --- a/tools/eclipse/core-plugin/META-INF/MANIFEST.MF +++ b/tools/eclipse/core-plugin/META-INF/MANIFEST.MF @@ -71,5 +71,6 @@ Export-Package: org.teavm.cache, org.teavm.resource, org.teavm.testing, org.teavm.tooling, + org.teavm.tooling.sources, org.teavm.vm, org.teavm.vm.spi diff --git a/tools/eclipse/m2e-plugin/META-INF/MANIFEST.MF b/tools/eclipse/m2e-plugin/META-INF/MANIFEST.MF index 062e541a9..1574d6301 100644 --- a/tools/eclipse/m2e-plugin/META-INF/MANIFEST.MF +++ b/tools/eclipse/m2e-plugin/META-INF/MANIFEST.MF @@ -4,7 +4,7 @@ Bundle-Name: TeaVM plugin for m2e Bundle-SymbolicName: teavm-eclipse-m2e-plugin;singleton:=true Bundle-Version: 0.4.0.qualifier Bundle-Vendor: Alexey Andreev -Bundle-RequiredExecutionEnvironment: JavaSE-1.7 +Bundle-RequiredExecutionEnvironment: JavaSE-1.8 Require-Bundle: teavm-eclipse-plugin;bundle-version="[0.4.0,0.5.0)", org.eclipse.m2e.core;bundle-version="[1.3,2)", org.eclipse.core.runtime;bundle-version="[3.8,4.0)", diff --git a/tools/eclipse/m2e-plugin/lifecycle-mapping-metadata.xml b/tools/eclipse/m2e-plugin/lifecycle-mapping-metadata.xml index 3ca52caff..e2fb85a6e 100644 --- a/tools/eclipse/m2e-plugin/lifecycle-mapping-metadata.xml +++ b/tools/eclipse/m2e-plugin/lifecycle-mapping-metadata.xml @@ -7,7 +7,7 @@ teavm-maven-plugin 0.4.0-SNAPSHOT - build-javascript + compile diff --git a/tools/eclipse/m2e-plugin/src/main/java/org/teavm/eclipse/m2e/TeaVMProjectConfigurator.java b/tools/eclipse/m2e-plugin/src/main/java/org/teavm/eclipse/m2e/TeaVMProjectConfigurator.java index 220d4ed0f..a8ad00c3a 100644 --- a/tools/eclipse/m2e-plugin/src/main/java/org/teavm/eclipse/m2e/TeaVMProjectConfigurator.java +++ b/tools/eclipse/m2e-plugin/src/main/java/org/teavm/eclipse/m2e/TeaVMProjectConfigurator.java @@ -33,7 +33,7 @@ public class TeaVMProjectConfigurator extends AbstractProjectConfigurator { private static final String TOOL_ID = "teavm-eclipse-m2e-plugin.tool"; private static final String TEAVM_ARTIFACT_ID = "teavm-maven-plugin"; private static final String TEAVM_GROUP_ID = "org.teavm"; - private static final String TEAVM_MAIN_GOAL = "build-javascript"; + private static final String TEAVM_MAIN_GOAL = "compile"; private int executionIdGenerator; private Set usedExecutionIds = new HashSet<>(); private IMaven maven; diff --git a/tools/eclipse/plugin/META-INF/MANIFEST.MF b/tools/eclipse/plugin/META-INF/MANIFEST.MF index 416ca1e23..4a219dbb4 100644 --- a/tools/eclipse/plugin/META-INF/MANIFEST.MF +++ b/tools/eclipse/plugin/META-INF/MANIFEST.MF @@ -4,7 +4,7 @@ Bundle-Name: TeaVM plugin for Eclipse Bundle-SymbolicName: teavm-eclipse-plugin;singleton:=true Bundle-Version: 0.4.0.qualifier Bundle-Vendor: Alexey Andreev -Bundle-RequiredExecutionEnvironment: JavaSE-1.7 +Bundle-RequiredExecutionEnvironment: JavaSE-1.8 Bundle-Activator: org.teavm.eclipse.TeaVMEclipsePlugin Require-Bundle: org.eclipse.core.runtime;bundle-version="[3.8.0,4.0)", org.eclipse.debug.core;bundle-version="[3.7.0,4.0)", @@ -48,5 +48,6 @@ Import-Package: org.teavm.cache, org.teavm.resource, org.teavm.testing, org.teavm.tooling, + org.teavm.tooling.sources, org.teavm.vm, org.teavm.vm.spi diff --git a/tools/eclipse/plugin/src/main/java/org/teavm/eclipse/TeaVMProjectBuilder.java b/tools/eclipse/plugin/src/main/java/org/teavm/eclipse/TeaVMProjectBuilder.java index 41c2184b7..a09363e27 100644 --- a/tools/eclipse/plugin/src/main/java/org/teavm/eclipse/TeaVMProjectBuilder.java +++ b/tools/eclipse/plugin/src/main/java/org/teavm/eclipse/TeaVMProjectBuilder.java @@ -21,22 +21,62 @@ import java.lang.reflect.InvocationTargetException; import java.net.MalformedURLException; import java.net.URL; import java.net.URLClassLoader; -import java.util.*; +import java.util.ArrayDeque; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.Collection; +import java.util.HashSet; +import java.util.List; +import java.util.Map; +import java.util.Queue; +import java.util.Set; +import java.util.WeakHashMap; import java.util.regex.Matcher; import java.util.regex.Pattern; -import org.eclipse.core.resources.*; -import org.eclipse.core.runtime.*; +import org.eclipse.core.resources.IContainer; +import org.eclipse.core.resources.IFile; +import org.eclipse.core.resources.IMarker; +import org.eclipse.core.resources.IProject; +import org.eclipse.core.resources.IResource; +import org.eclipse.core.resources.IResourceDelta; +import org.eclipse.core.resources.IWorkspaceRoot; +import org.eclipse.core.resources.IncrementalProjectBuilder; +import org.eclipse.core.resources.ResourcesPlugin; +import org.eclipse.core.runtime.CoreException; +import org.eclipse.core.runtime.IPath; +import org.eclipse.core.runtime.IProgressMonitor; +import org.eclipse.core.runtime.IStatus; +import org.eclipse.core.runtime.Status; +import org.eclipse.core.runtime.SubProgressMonitor; import org.eclipse.core.runtime.jobs.Job; import org.eclipse.core.variables.IStringVariableManager; import org.eclipse.core.variables.VariablesPlugin; -import org.eclipse.jdt.core.*; +import org.eclipse.jdt.core.IClasspathEntry; +import org.eclipse.jdt.core.ICompilationUnit; +import org.eclipse.jdt.core.IJavaElement; +import org.eclipse.jdt.core.IJavaProject; +import org.eclipse.jdt.core.IMethod; +import org.eclipse.jdt.core.IType; +import org.eclipse.jdt.core.JavaCore; +import org.eclipse.jdt.core.Signature; import org.teavm.callgraph.CallGraph; import org.teavm.callgraph.CallGraphNode; import org.teavm.callgraph.CallSite; import org.teavm.diagnostics.Problem; import org.teavm.diagnostics.ProblemTextConsumer; -import org.teavm.model.*; -import org.teavm.tooling.*; +import org.teavm.model.CallLocation; +import org.teavm.model.ClassHolderTransformer; +import org.teavm.model.FieldReference; +import org.teavm.model.InstructionLocation; +import org.teavm.model.MethodReference; +import org.teavm.model.ValueType; +import org.teavm.tooling.ClassAlias; +import org.teavm.tooling.RuntimeCopyOperation; +import org.teavm.tooling.TeaVMTool; +import org.teavm.tooling.TeaVMToolException; +import org.teavm.tooling.sources.DirectorySourceFileProvider; +import org.teavm.tooling.sources.JarSourceFileProvider; +import org.teavm.tooling.sources.SourceFileProvider; /** * diff --git a/tools/maven/plugin/src/main/java/org/teavm/maven/BuildJavascriptTestMojo.java b/tools/maven/plugin/src/main/java/org/teavm/maven/BuildJavascriptTestMojo.java index de0617ebd..5beb6c135 100644 --- a/tools/maven/plugin/src/main/java/org/teavm/maven/BuildJavascriptTestMojo.java +++ b/tools/maven/plugin/src/main/java/org/teavm/maven/BuildJavascriptTestMojo.java @@ -28,7 +28,6 @@ import java.util.Arrays; import java.util.Enumeration; import java.util.HashSet; import java.util.List; -import java.util.Properties; import java.util.Set; import java.util.jar.JarEntry; import java.util.jar.JarFile; @@ -82,12 +81,6 @@ public class BuildJavascriptTestMojo extends AbstractJavascriptMojo { @Parameter private String[] additionalScripts; - @Parameter - private Properties properties; - - @Parameter - private boolean incremental; - private TeaVMTestTool tool = new TeaVMTestTool(); @Override diff --git a/tools/maven/plugin/src/main/java/org/teavm/maven/RunTestsMojo.java b/tools/maven/plugin/src/main/java/org/teavm/maven/RunTestsMojo.java index f89a3d176..8bfd3857e 100644 --- a/tools/maven/plugin/src/main/java/org/teavm/maven/RunTestsMojo.java +++ b/tools/maven/plugin/src/main/java/org/teavm/maven/RunTestsMojo.java @@ -16,13 +16,17 @@ package org.teavm.maven; import com.fasterxml.jackson.databind.ObjectMapper; +import com.fasterxml.jackson.databind.SerializationFeature; import java.io.File; import java.io.FileInputStream; +import java.io.FileOutputStream; import java.io.IOException; import java.io.InputStreamReader; +import java.io.OutputStreamWriter; import java.io.Reader; +import java.io.Writer; +import java.net.MalformedURLException; import java.net.URL; -import java.util.List; import org.apache.maven.plugin.AbstractMojo; import org.apache.maven.plugin.MojoExecutionException; import org.apache.maven.plugin.MojoFailureException; @@ -40,15 +44,37 @@ public class RunTestsMojo extends AbstractMojo { @Parameter(defaultValue = "${project.build.directory}/javascript-test") private File testDirectory; + @Parameter(defaultValue = "${project.build.directory}/teavm-test-report.json") + private File reportFile; + @Parameter - private URL seleniumURL; + private String seleniumURL; + + @Parameter + private int numThreads = 1; @Override public void execute() throws MojoExecutionException, MojoFailureException { + if (seleniumURL == null || seleniumURL.isEmpty()) { + getLog().info("Tests build skipped as selenium URL was not specified"); + return; + } + + if (System.getProperty("maven.test.skip", "false").equals("true") || + System.getProperty("skipTests") != null) { + getLog().info("Tests build skipped as specified by system property"); + return; + } + SeleniumTestRunner runner = new SeleniumTestRunner(); runner.setLog(getLog()); runner.setDirectory(testDirectory); - runner.setUrl(seleniumURL); + runner.setNumThreads(numThreads); + try { + runner.setUrl(new URL(seleniumURL)); + } catch (MalformedURLException e) { + throw new MojoFailureException("Can't parse URL: " + seleniumURL, e); + } TestPlan plan; ObjectMapper mapper = new ObjectMapper(); @@ -63,23 +89,31 @@ public class RunTestsMojo extends AbstractMojo { processReport(runner.getReport()); } - private void processReport(List report) throws MojoExecutionException { - if (report.isEmpty()) { + private void processReport(TestReport report) throws MojoExecutionException, MojoFailureException { + if (report.getResults().isEmpty()) { getLog().info("No tests ran"); return; } int failedTests = 0; - for (TestResult result : report) { + for (TestResult result : report.getResults()) { if (result.getStatus() != TestStatus.PASSED) { failedTests++; } } if (failedTests > 0) { - throw new MojoExecutionException(failedTests + " of " + report.size() + " test(s) failed"); + throw new MojoExecutionException(failedTests + " of " + report.getResults().size() + " test(s) failed"); } else { - getLog().info("All of " + report.size() + " tests successfully passed"); + getLog().info("All of " + report.getResults().size() + " tests successfully passed"); + } + + ObjectMapper mapper = new ObjectMapper(); + mapper.enable(SerializationFeature.INDENT_OUTPUT); + try (Writer writer = new OutputStreamWriter(new FileOutputStream(reportFile), "UTF-8")) { + mapper.writeValue(writer, report); + } catch (IOException e) { + throw new MojoFailureException("Error writing test report", e); } } } diff --git a/tools/maven/plugin/src/main/java/org/teavm/maven/SeleniumTestRunner.java b/tools/maven/plugin/src/main/java/org/teavm/maven/SeleniumTestRunner.java index 836cfd405..b90e7da2c 100644 --- a/tools/maven/plugin/src/main/java/org/teavm/maven/SeleniumTestRunner.java +++ b/tools/maven/plugin/src/main/java/org/teavm/maven/SeleniumTestRunner.java @@ -34,7 +34,8 @@ import org.apache.maven.plugin.logging.Log; import org.openqa.selenium.JavascriptExecutor; import org.openqa.selenium.WebDriver; import org.openqa.selenium.WebDriverException; -import org.openqa.selenium.chrome.ChromeDriver; +import org.openqa.selenium.remote.DesiredCapabilities; +import org.openqa.selenium.remote.RemoteWebDriver; import org.teavm.model.MethodReference; import org.teavm.tooling.testing.TestCase; import org.teavm.tooling.testing.TestGroup; @@ -99,7 +100,7 @@ public class SeleniumTestRunner { latch = new CountDownLatch(numThreads); for (int i = 0; i < numThreads; ++i) { new Thread(() -> { - ChromeDriver driver = new ChromeDriver(); + RemoteWebDriver driver = new RemoteWebDriver(DesiredCapabilities.chrome()); webDriver.set(driver); localReport.set(new ArrayList<>()); while (!seleniumStopped || !seleniumTaskQueue.isEmpty()) { @@ -157,13 +158,24 @@ public class SeleniumTestRunner { MethodReference ref = MethodReference.parse(testCase.getTestMethod()); switch (status) { case "ok": - log.info("Test passed: " + testCase.getTestMethod()); - localReport.get().add(TestResult.passed(ref)); + if (testCase.getExpectedExceptions().isEmpty()) { + log.info("Test passed: " + testCase.getTestMethod()); + localReport.get().add(TestResult.passed(ref)); + } else { + log.info("Test failed: " + testCase.getTestMethod()); + localReport.get().add(TestResult.exceptionNotThrown(ref)); + } break; case "exception": { String stack = resultObject.get("stack").asText(); - log.info("Test failed: " + testCase.getTestMethod()); - localReport.get().add(TestResult.error(ref, stack)); + String exception = resultObject.get("exception").asText(); + if (!testCase.getExpectedExceptions().contains(exception)) { + log.info("Test failed: " + testCase.getTestMethod()); + localReport.get().add(TestResult.error(ref, exception, stack)); + } else { + log.info("Test passed: " + testCase.getTestMethod()); + localReport.get().add(TestResult.passed(ref)); + } break; } } @@ -194,7 +206,9 @@ public class SeleniumTestRunner { } } - public List getReport() { - return new ArrayList<>(report); + public TestReport getReport() { + TestReport report = new TestReport(); + report.getResults().addAll(this.report); + return report; } } diff --git a/tools/maven/plugin/src/main/java/org/teavm/maven/TestReport.java b/tools/maven/plugin/src/main/java/org/teavm/maven/TestReport.java new file mode 100644 index 000000000..d8fab47b1 --- /dev/null +++ b/tools/maven/plugin/src/main/java/org/teavm/maven/TestReport.java @@ -0,0 +1,16 @@ +package org.teavm.maven; + +import java.util.ArrayList; +import java.util.List; + +/** + * + * @author Alexey Andreev + */ +public class TestReport { + private List results = new ArrayList<>(); + + public List getResults() { + return results; + } +} diff --git a/tools/maven/plugin/src/main/java/org/teavm/maven/TestResult.java b/tools/maven/plugin/src/main/java/org/teavm/maven/TestResult.java index 1151f2c85..9728857e6 100644 --- a/tools/maven/plugin/src/main/java/org/teavm/maven/TestResult.java +++ b/tools/maven/plugin/src/main/java/org/teavm/maven/TestResult.java @@ -15,6 +15,11 @@ */ package org.teavm.maven; +import com.fasterxml.jackson.annotation.JsonCreator; +import com.fasterxml.jackson.annotation.JsonGetter; +import com.fasterxml.jackson.annotation.JsonInclude; +import com.fasterxml.jackson.annotation.JsonInclude.Include; +import com.fasterxml.jackson.annotation.JsonProperty; import org.teavm.model.MethodReference; /** @@ -24,30 +29,49 @@ import org.teavm.model.MethodReference; public class TestResult { private MethodReference method; private TestStatus status; + private String exception; private String stack; - private TestResult(MethodReference method, TestStatus status, String stack) { + @JsonCreator + TestResult( + @JsonProperty("method") MethodReference method, + @JsonProperty("status") TestStatus status, + @JsonInclude(Include.NON_NULL) @JsonProperty("exception") String exception, + @JsonInclude(Include.NON_NULL) @JsonProperty("stack") String stack) { this.method = method; this.status = status; + this.exception = exception; this.stack = stack; } public static TestResult passed(MethodReference method) { - return new TestResult(method, TestStatus.PASSED, null); + return new TestResult(method, TestStatus.PASSED, null, null); } - public static TestResult error(MethodReference method, String stack) { - return new TestResult(method, TestStatus.ERROR, stack); + public static TestResult exceptionNotThrown(MethodReference method) { + return new TestResult(method, TestStatus.EXCEPTION_NOT_THROWN, null, null); } + public static TestResult error(MethodReference method, String exception, String stack) { + return new TestResult(method, TestStatus.ERROR, exception, stack); + } + + @JsonGetter public MethodReference getMethod() { return method; } + @JsonGetter public TestStatus getStatus() { return status; } + @JsonGetter + public String getException() { + return exception; + } + + @JsonGetter public String getStack() { return stack; } diff --git a/tools/maven/plugin/src/main/java/org/teavm/maven/TestStatus.java b/tools/maven/plugin/src/main/java/org/teavm/maven/TestStatus.java index 8bdbaecd2..366859a58 100644 --- a/tools/maven/plugin/src/main/java/org/teavm/maven/TestStatus.java +++ b/tools/maven/plugin/src/main/java/org/teavm/maven/TestStatus.java @@ -21,5 +21,6 @@ package org.teavm.maven; */ public enum TestStatus { PASSED, - ERROR + ERROR, + EXCEPTION_NOT_THROWN } diff --git a/tools/maven/webapp/src/main/resources/archetype-resources/pom.xml b/tools/maven/webapp/src/main/resources/archetype-resources/pom.xml index 0a265a56c..5a2eebaa2 100644 --- a/tools/maven/webapp/src/main/resources/archetype-resources/pom.xml +++ b/tools/maven/webapp/src/main/resources/archetype-resources/pom.xml @@ -8,7 +8,7 @@ war - 1.7 + 1.8 0.4.0-SNAPSHOT UTF-8 @@ -25,15 +25,7 @@ org.teavm - teavm-jso - ${teavm.version} - provided - - - - - org.teavm - teavm-dom + teavm-jso-apis ${teavm.version} provided @@ -80,9 +72,8 @@ web-client - prepare-package - build-javascript + compile ${package}.Client - - SEPARATE - true From 30c5564d47c80e9c362514b29bf713d818b2d8c8 Mon Sep 17 00:00:00 2001 From: Alexey Andreev Date: Sat, 10 Oct 2015 08:21:08 +0300 Subject: [PATCH 07/16] Add travis CI config --- .travis.yml | 1 + 1 file changed, 1 insertion(+) create mode 100644 .travis.yml diff --git a/.travis.yml b/.travis.yml new file mode 100644 index 000000000..f5c99a7f6 --- /dev/null +++ b/.travis.yml @@ -0,0 +1 @@ +language: java \ No newline at end of file From fac9471c2a758e109ba8d22630faf7f10c322245 Mon Sep 17 00:00:00 2001 From: Alexey Andreev Date: Sat, 10 Oct 2015 08:23:02 +0300 Subject: [PATCH 08/16] Trying to fix pom file --- tools/chrome-rdp/pom.xml | 1 + 1 file changed, 1 insertion(+) diff --git a/tools/chrome-rdp/pom.xml b/tools/chrome-rdp/pom.xml index cc17209eb..ab0e3875e 100644 --- a/tools/chrome-rdp/pom.xml +++ b/tools/chrome-rdp/pom.xml @@ -21,6 +21,7 @@ org.teavm teavm 0.4.0-SNAPSHOT + ../.. teavm-chrome-rdp From 161783400723d4038cf68e40add1cd6a630bf652 Mon Sep 17 00:00:00 2001 From: Alexey Andreev Date: Sat, 10 Oct 2015 08:25:51 +0300 Subject: [PATCH 09/16] Setup travis to use Java 8 --- .travis.yml | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/.travis.yml b/.travis.yml index f5c99a7f6..c4f11b7cf 100644 --- a/.travis.yml +++ b/.travis.yml @@ -1 +1,3 @@ -language: java \ No newline at end of file +language: java +jdk: + - oraclejdk8 \ No newline at end of file From 11e168bc25660997c451f1a9ff4c0c66822ccad9 Mon Sep 17 00:00:00 2001 From: Alexey Andreev Date: Sat, 10 Oct 2015 08:31:16 +0300 Subject: [PATCH 10/16] Remove wrong dependency --- platform/pom.xml | 5 ----- 1 file changed, 5 deletions(-) diff --git a/platform/pom.xml b/platform/pom.xml index 6299a95bc..d606b308a 100644 --- a/platform/pom.xml +++ b/platform/pom.xml @@ -40,11 +40,6 @@ teavm-jso-apis ${project.version} - - org.teavm - teavm-dom - ${project.version} - junit junit From acaec942a13fe9859f1fe60e3ceae00bf3e17963 Mon Sep 17 00:00:00 2001 From: Alexey Andreev Date: Sat, 10 Oct 2015 08:36:56 +0300 Subject: [PATCH 11/16] Get rid of teavm-dom dependencies --- samples/benchmark/pom.xml | 8 +------- samples/hello/pom.xml | 6 ------ samples/kotlin/pom.xml | 2 +- samples/storage/pom.xml | 8 +------- samples/video/pom.xml | 8 +------- 5 files changed, 4 insertions(+), 28 deletions(-) diff --git a/samples/benchmark/pom.xml b/samples/benchmark/pom.xml index 378ee7c83..4b1bfd80a 100644 --- a/samples/benchmark/pom.xml +++ b/samples/benchmark/pom.xml @@ -27,13 +27,7 @@ org.teavm - teavm-jso - ${project.version} - provided - - - org.teavm - teavm-dom + teavm-jso-apis ${project.version} provided diff --git a/samples/hello/pom.xml b/samples/hello/pom.xml index ff9ea0b65..b07252129 100644 --- a/samples/hello/pom.xml +++ b/samples/hello/pom.xml @@ -42,12 +42,6 @@ ${project.version} provided - - org.teavm - teavm-dom - ${project.version} - provided - javax.servlet javax.servlet-api diff --git a/samples/kotlin/pom.xml b/samples/kotlin/pom.xml index 1af5c380a..ce44c2989 100644 --- a/samples/kotlin/pom.xml +++ b/samples/kotlin/pom.xml @@ -53,7 +53,7 @@ org.teavm - teavm-dom + teavm-jso-apis ${project.version} provided diff --git a/samples/storage/pom.xml b/samples/storage/pom.xml index 3537a4fce..4bea360f1 100644 --- a/samples/storage/pom.xml +++ b/samples/storage/pom.xml @@ -38,13 +38,7 @@ org.teavm - teavm-jso - ${project.version} - provided - - - org.teavm - teavm-dom + teavm-jso-apis ${project.version} provided diff --git a/samples/video/pom.xml b/samples/video/pom.xml index 77502485e..02867ca12 100644 --- a/samples/video/pom.xml +++ b/samples/video/pom.xml @@ -38,13 +38,7 @@ org.teavm - teavm-jso - ${project.version} - provided - - - org.teavm - teavm-dom + teavm-jso-apis ${project.version} provided From 010a5fe579c1285ef86e243a8d7ca3b9cedfa459 Mon Sep 17 00:00:00 2001 From: Alexey Andreev Date: Sat, 10 Oct 2015 08:55:22 +0300 Subject: [PATCH 12/16] Trying to enable maven cache in travis. Add travis badge. Fix bug in source file copier --- .travis.yml | 7 ++++++- README.md | 2 ++ .../org/teavm/maven/MavenSourceFileProviderLookup.java | 7 ++++++- 3 files changed, 14 insertions(+), 2 deletions(-) diff --git a/.travis.yml b/.travis.yml index c4f11b7cf..c892b40dc 100644 --- a/.travis.yml +++ b/.travis.yml @@ -1,3 +1,8 @@ language: java jdk: - - oraclejdk8 \ No newline at end of file + - oraclejdk8 +cache: + directories: + - $HOME/.m2 +after_script: + - rm -rf $HOME/.m2/repository/org/teavm \ No newline at end of file diff --git a/README.md b/README.md index 38ff1e579..c17b93c53 100644 --- a/README.md +++ b/README.md @@ -1,6 +1,8 @@ TeaVM ===== +[![Build Status](https://travis-ci.org/konsoletyper/teavm.svg?branch=selenium)](https://travis-ci.org/konsoletyper/teavm) + What is TeaVM? -------------- diff --git a/tools/maven/plugin/src/main/java/org/teavm/maven/MavenSourceFileProviderLookup.java b/tools/maven/plugin/src/main/java/org/teavm/maven/MavenSourceFileProviderLookup.java index 9d6567645..3b6242f79 100644 --- a/tools/maven/plugin/src/main/java/org/teavm/maven/MavenSourceFileProviderLookup.java +++ b/tools/maven/plugin/src/main/java/org/teavm/maven/MavenSourceFileProviderLookup.java @@ -85,7 +85,12 @@ public class MavenSourceFileProviderLookup { ArtifactResolutionResult result = repositorySystem.resolve(request); for (Artifact resolvedArtifact : result.getArtifacts()) { if (resolvedArtifact.getFile() != null) { - providers.add(new JarSourceFileProvider(resolvedArtifact.getFile())); + File file = resolvedArtifact.getFile(); + if (!file.isDirectory()) { + providers.add(new JarSourceFileProvider(file)); + } else { + providers.add(new DirectorySourceFileProvider(file)); + } } } } From bac0785dc665b9db615313c80de7183c20cc76c3 Mon Sep 17 00:00:00 2001 From: Alexey Andreev Date: Sat, 10 Oct 2015 11:06:30 +0300 Subject: [PATCH 13/16] Add HtmlUnit test runner. Add travis + Sauce Labs config --- .travis.yml | 7 +- tests/pom.xml | 2 + tools/maven/plugin/pom.xml | 13 +++ .../teavm/maven/AbstractJavascriptMojo.java | 4 +- .../teavm/maven/BuildJavascriptTestMojo.java | 8 +- .../org/teavm/maven/HtmlUnitRunStrategy.java | 107 ++++++++++++++++++ .../org/teavm/maven/MavenTeaVMToolLog.java | 15 +++ .../java/org/teavm/maven/RunTestsMojo.java | 33 ++++-- .../org/teavm/maven/SeleniumRunStrategy.java | 95 ++++++++++++++++ .../main/java/org/teavm/maven/TestReport.java | 15 +++ .../java/org/teavm/maven/TestRunStrategy.java | 32 ++++++ ...eleniumTestRunner.java => TestRunner.java} | 90 ++++----------- .../main/resources/teavm-htmlunit-adapter.js | 65 +++++++++++ 13 files changed, 397 insertions(+), 89 deletions(-) create mode 100644 tools/maven/plugin/src/main/java/org/teavm/maven/HtmlUnitRunStrategy.java create mode 100644 tools/maven/plugin/src/main/java/org/teavm/maven/SeleniumRunStrategy.java create mode 100644 tools/maven/plugin/src/main/java/org/teavm/maven/TestRunStrategy.java rename tools/maven/plugin/src/main/java/org/teavm/maven/{SeleniumTestRunner.java => TestRunner.java} (61%) create mode 100644 tools/maven/plugin/src/main/resources/teavm-htmlunit-adapter.js diff --git a/.travis.yml b/.travis.yml index c892b40dc..92edf3e8c 100644 --- a/.travis.yml +++ b/.travis.yml @@ -5,4 +5,9 @@ cache: directories: - $HOME/.m2 after_script: - - rm -rf $HOME/.m2/repository/org/teavm \ No newline at end of file + - rm -rf $HOME/.m2/repository/org/teavm +script: + - mvn test \ + - -Pteavm.test.skip=false \ + - -Pteavm.test.selenium="http://$SAUCE_USER_NAME:$SAUCE_ACCESS_KEY@ondemand.saucelabs.com:80/wd/hub" \ + - -Pteavm.test.threads=2 \ No newline at end of file diff --git a/tests/pom.xml b/tests/pom.xml index 17b57350d..002d0faef 100644 --- a/tests/pom.xml +++ b/tests/pom.xml @@ -31,6 +31,7 @@ false 1 + true @@ -100,6 +101,7 @@ test + ${teavm.test.skip} ${teavm.test.threads} ${teavm.test.selenium} diff --git a/tools/maven/plugin/pom.xml b/tools/maven/plugin/pom.xml index 34fe8454c..2c7e153df 100644 --- a/tools/maven/plugin/pom.xml +++ b/tools/maven/plugin/pom.xml @@ -69,6 +69,11 @@ com.fasterxml.jackson.core jackson-databind + + net.sourceforge.htmlunit + htmlunit + 2.18 + junit junit @@ -103,6 +108,14 @@ org.apache.maven.plugins maven-javadoc-plugin + + org.apache.maven.plugins + maven-checkstyle-plugin + + ../../../checkstyle.xml + config_loc=${basedir}/../../.. + + diff --git a/tools/maven/plugin/src/main/java/org/teavm/maven/AbstractJavascriptMojo.java b/tools/maven/plugin/src/main/java/org/teavm/maven/AbstractJavascriptMojo.java index 6446e3441..cb43846e3 100644 --- a/tools/maven/plugin/src/main/java/org/teavm/maven/AbstractJavascriptMojo.java +++ b/tools/maven/plugin/src/main/java/org/teavm/maven/AbstractJavascriptMojo.java @@ -106,8 +106,8 @@ public abstract class AbstractJavascriptMojo extends AbstractMojo { throw new MojoExecutionException("Transformer not found: " + transformerName, e); } if (!ClassHolderTransformer.class.isAssignableFrom(transformerRawType)) { - throw new MojoExecutionException("Transformer " + transformerName + " is not subtype of " + - ClassHolderTransformer.class.getName()); + throw new MojoExecutionException("Transformer " + transformerName + " is not subtype of " + + ClassHolderTransformer.class.getName()); } Class transformerType = transformerRawType.asSubclass( ClassHolderTransformer.class); diff --git a/tools/maven/plugin/src/main/java/org/teavm/maven/BuildJavascriptTestMojo.java b/tools/maven/plugin/src/main/java/org/teavm/maven/BuildJavascriptTestMojo.java index 5beb6c135..7b8618570 100644 --- a/tools/maven/plugin/src/main/java/org/teavm/maven/BuildJavascriptTestMojo.java +++ b/tools/maven/plugin/src/main/java/org/teavm/maven/BuildJavascriptTestMojo.java @@ -85,8 +85,8 @@ public class BuildJavascriptTestMojo extends AbstractJavascriptMojo { @Override public void execute() throws MojoExecutionException, MojoFailureException { - if (System.getProperty("maven.test.skip", "false").equals("true") || - System.getProperty("skipTests") != null) { + if (System.getProperty("maven.test.skip", "false").equals("true") + || System.getProperty("skipTests") != null) { getLog().info("Tests build skipped as specified by system property"); return; } @@ -127,8 +127,8 @@ public class BuildJavascriptTestMojo extends AbstractJavascriptMojo { throw new MojoExecutionException("Adapter not found: " + adapterClass, e); } if (!TestAdapter.class.isAssignableFrom(adapterClsRaw)) { - throw new MojoExecutionException("Adapter " + adapterClass + " does not implement " + - TestAdapter.class.getName()); + throw new MojoExecutionException("Adapter " + adapterClass + " does not implement " + + TestAdapter.class.getName()); } Class adapterCls = adapterClsRaw.asSubclass(TestAdapter.class); Constructor cons; diff --git a/tools/maven/plugin/src/main/java/org/teavm/maven/HtmlUnitRunStrategy.java b/tools/maven/plugin/src/main/java/org/teavm/maven/HtmlUnitRunStrategy.java new file mode 100644 index 000000000..0b7b24a57 --- /dev/null +++ b/tools/maven/plugin/src/main/java/org/teavm/maven/HtmlUnitRunStrategy.java @@ -0,0 +1,107 @@ +/* + * Copyright 2015 Alexey Andreev. + * + * Licensed 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.teavm.maven; + +import com.gargoylesoftware.htmlunit.BrowserVersion; +import com.gargoylesoftware.htmlunit.WebClient; +import com.gargoylesoftware.htmlunit.WebWindow; +import com.gargoylesoftware.htmlunit.html.HtmlPage; +import java.io.File; +import java.io.FileInputStream; +import java.io.IOException; +import java.io.InputStream; +import java.util.concurrent.CountDownLatch; +import java.util.concurrent.TimeUnit; +import net.sourceforge.htmlunit.corejs.javascript.Function; +import net.sourceforge.htmlunit.corejs.javascript.NativeJavaObject; +import org.apache.commons.io.IOUtils; +import org.apache.maven.plugin.logging.Log; +import org.teavm.tooling.testing.TestCase; + +/** + * + * @author Alexey Andreev + */ +public class HtmlUnitRunStrategy implements TestRunStrategy { + private File directory; + + public HtmlUnitRunStrategy(File directory) { + this.directory = directory; + } + + @Override + public void beforeThread() { + } + + @Override + public void afterThread() { + } + + @Override + public String runTest(Log log, String runtimeScript, TestCase testCase) throws IOException { + try (WebClient webClient = new WebClient(BrowserVersion.CHROME)) { + HtmlPage page = webClient.getPage("about:blank"); + page.executeJavaScript(readFile(new File(directory, runtimeScript))); + + AsyncResult asyncResult = new AsyncResult(); + Function function = (Function) page.executeJavaScript(readResource("teavm-htmlunit-adapter.js")) + .getJavaScriptResult(); + Object[] args = new Object[] { new NativeJavaObject(function, asyncResult, AsyncResult.class) }; + page.executeJavaScriptFunctionIfPossible(function, function, args, page); + + page.executeJavaScript(readFile(new File(directory, testCase.getTestScript()))); + page.cleanUp(); + for (WebWindow window : webClient.getWebWindows()) { + window.getJobManager().removeAllJobs(); + } + return (String) asyncResult.getResult(); + } + } + + private String readFile(File file) throws IOException { + try (InputStream input = new FileInputStream(file)) { + return IOUtils.toString(input, "UTF-8"); + } + } + + private String readResource(String resourceName) throws IOException { + try (InputStream input = BuildJavascriptTestMojo.class.getClassLoader().getResourceAsStream(resourceName)) { + if (input == null) { + return ""; + } + return IOUtils.toString(input, "UTF-8"); + } + } + + public class AsyncResult { + private CountDownLatch latch = new CountDownLatch(1); + private Object result; + + public void complete(Object result) { + this.result = result; + latch.countDown(); + } + + public Object getResult() { + try { + latch.await(5, TimeUnit.SECONDS); + return result; + } catch (InterruptedException e) { + return null; + } + } + } +} diff --git a/tools/maven/plugin/src/main/java/org/teavm/maven/MavenTeaVMToolLog.java b/tools/maven/plugin/src/main/java/org/teavm/maven/MavenTeaVMToolLog.java index 862f5c605..1208d4a25 100644 --- a/tools/maven/plugin/src/main/java/org/teavm/maven/MavenTeaVMToolLog.java +++ b/tools/maven/plugin/src/main/java/org/teavm/maven/MavenTeaVMToolLog.java @@ -1,3 +1,18 @@ +/* + * Copyright 2015 Alexey Andreev. + * + * Licensed 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.teavm.maven; import org.apache.maven.plugin.logging.Log; diff --git a/tools/maven/plugin/src/main/java/org/teavm/maven/RunTestsMojo.java b/tools/maven/plugin/src/main/java/org/teavm/maven/RunTestsMojo.java index 8bfd3857e..2c0b82354 100644 --- a/tools/maven/plugin/src/main/java/org/teavm/maven/RunTestsMojo.java +++ b/tools/maven/plugin/src/main/java/org/teavm/maven/RunTestsMojo.java @@ -53,28 +53,25 @@ public class RunTestsMojo extends AbstractMojo { @Parameter private int numThreads = 1; + @Parameter + private boolean skip; + @Override public void execute() throws MojoExecutionException, MojoFailureException { - if (seleniumURL == null || seleniumURL.isEmpty()) { - getLog().info("Tests build skipped as selenium URL was not specified"); + if (skip) { + getLog().info("Tests run skipped as specified by skip property"); return; } - if (System.getProperty("maven.test.skip", "false").equals("true") || - System.getProperty("skipTests") != null) { - getLog().info("Tests build skipped as specified by system property"); + if (System.getProperty("maven.test.skip", "false").equals("true") + || System.getProperty("skipTests") != null) { + getLog().info("Tests run skipped as specified by system property"); return; } - SeleniumTestRunner runner = new SeleniumTestRunner(); + TestRunner runner = new TestRunner(pickStrategy()); runner.setLog(getLog()); - runner.setDirectory(testDirectory); runner.setNumThreads(numThreads); - try { - runner.setUrl(new URL(seleniumURL)); - } catch (MalformedURLException e) { - throw new MojoFailureException("Can't parse URL: " + seleniumURL, e); - } TestPlan plan; ObjectMapper mapper = new ObjectMapper(); @@ -89,6 +86,18 @@ public class RunTestsMojo extends AbstractMojo { processReport(runner.getReport()); } + private TestRunStrategy pickStrategy() throws MojoFailureException { + if (seleniumURL != null) { + try { + return new SeleniumRunStrategy(new URL(seleniumURL), testDirectory); + } catch (MalformedURLException e) { + throw new MojoFailureException("Can't parse URL: " + seleniumURL, e); + } + } else { + return new HtmlUnitRunStrategy(testDirectory); + } + } + private void processReport(TestReport report) throws MojoExecutionException, MojoFailureException { if (report.getResults().isEmpty()) { getLog().info("No tests ran"); diff --git a/tools/maven/plugin/src/main/java/org/teavm/maven/SeleniumRunStrategy.java b/tools/maven/plugin/src/main/java/org/teavm/maven/SeleniumRunStrategy.java new file mode 100644 index 000000000..1bb827c43 --- /dev/null +++ b/tools/maven/plugin/src/main/java/org/teavm/maven/SeleniumRunStrategy.java @@ -0,0 +1,95 @@ +/* + * Copyright 2015 Alexey Andreev. + * + * Licensed 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.teavm.maven; + +import java.io.File; +import java.io.FileInputStream; +import java.io.IOException; +import java.io.InputStream; +import java.net.URL; +import java.util.List; +import java.util.concurrent.TimeUnit; +import org.apache.commons.io.IOUtils; +import org.apache.maven.plugin.logging.Log; +import org.openqa.selenium.JavascriptExecutor; +import org.openqa.selenium.WebDriver; +import org.openqa.selenium.WebDriverException; +import org.openqa.selenium.remote.DesiredCapabilities; +import org.openqa.selenium.remote.RemoteWebDriver; +import org.teavm.tooling.testing.TestCase; + +/** + * + * @author Alexey Andreev + */ +public class SeleniumRunStrategy implements TestRunStrategy { + private URL url; + private File directory; + private ThreadLocal webDriver = new ThreadLocal<>(); + + public SeleniumRunStrategy(URL url, File directory) { + this.url = url; + this.directory = directory; + } + + @Override + public void beforeThread() { + RemoteWebDriver driver = new RemoteWebDriver(url, DesiredCapabilities.chrome()); + webDriver.set(driver); + } + + @Override + public void afterThread() { + webDriver.get().close(); + webDriver.remove(); + } + + @Override + public String runTest(Log log, String runtimeScript, TestCase testCase) throws IOException { + webDriver.get().manage().timeouts().setScriptTimeout(2, TimeUnit.SECONDS); + JavascriptExecutor js = (JavascriptExecutor) webDriver.get(); + try { + return (String) js.executeAsyncScript( + readResource("teavm-selenium.js"), + readFile(new File(directory, runtimeScript)), + readFile(new File(directory, testCase.getTestScript())), + readResource("teavm-selenium-adapter.js")); + } catch (WebDriverException e) { + log.error("Error occured running test " + testCase.getTestMethod(), e); + @SuppressWarnings("unchecked") + List errors = (List) js.executeScript("return window.jsErrors;"); + for (Object error : errors) { + log.error(" -- additional error: " + error); + } + return null; + } + } + + private String readFile(File file) throws IOException { + try (InputStream input = new FileInputStream(file)) { + return IOUtils.toString(input, "UTF-8"); + } + } + + private String readResource(String resourceName) throws IOException { + try (InputStream input = BuildJavascriptTestMojo.class.getClassLoader().getResourceAsStream(resourceName)) { + if (input == null) { + return ""; + } + return IOUtils.toString(input, "UTF-8"); + } + } +} diff --git a/tools/maven/plugin/src/main/java/org/teavm/maven/TestReport.java b/tools/maven/plugin/src/main/java/org/teavm/maven/TestReport.java index d8fab47b1..c6e57d502 100644 --- a/tools/maven/plugin/src/main/java/org/teavm/maven/TestReport.java +++ b/tools/maven/plugin/src/main/java/org/teavm/maven/TestReport.java @@ -1,3 +1,18 @@ +/* + * Copyright 2015 Alexey Andreev. + * + * Licensed 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.teavm.maven; import java.util.ArrayList; diff --git a/tools/maven/plugin/src/main/java/org/teavm/maven/TestRunStrategy.java b/tools/maven/plugin/src/main/java/org/teavm/maven/TestRunStrategy.java new file mode 100644 index 000000000..8c1bcc745 --- /dev/null +++ b/tools/maven/plugin/src/main/java/org/teavm/maven/TestRunStrategy.java @@ -0,0 +1,32 @@ +/* + * Copyright 2015 Alexey Andreev. + * + * Licensed 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.teavm.maven; + +import java.io.IOException; +import org.apache.maven.plugin.logging.Log; +import org.teavm.tooling.testing.TestCase; + +/** + * + * @author Alexey Andreev + */ +public interface TestRunStrategy { + void beforeThread(); + + void afterThread(); + + String runTest(Log log, String runtimeScript, TestCase testCase) throws IOException; +} diff --git a/tools/maven/plugin/src/main/java/org/teavm/maven/SeleniumTestRunner.java b/tools/maven/plugin/src/main/java/org/teavm/maven/TestRunner.java similarity index 61% rename from tools/maven/plugin/src/main/java/org/teavm/maven/SeleniumTestRunner.java rename to tools/maven/plugin/src/main/java/org/teavm/maven/TestRunner.java index b90e7da2c..3594cfec6 100644 --- a/tools/maven/plugin/src/main/java/org/teavm/maven/SeleniumTestRunner.java +++ b/tools/maven/plugin/src/main/java/org/teavm/maven/TestRunner.java @@ -17,11 +17,7 @@ package org.teavm.maven; import com.fasterxml.jackson.databind.ObjectMapper; import com.fasterxml.jackson.databind.node.ObjectNode; -import java.io.File; -import java.io.FileInputStream; import java.io.IOException; -import java.io.InputStream; -import java.net.URL; import java.util.ArrayList; import java.util.List; import java.util.concurrent.BlockingQueue; @@ -29,13 +25,7 @@ import java.util.concurrent.CopyOnWriteArrayList; import java.util.concurrent.CountDownLatch; import java.util.concurrent.LinkedBlockingQueue; import java.util.concurrent.TimeUnit; -import org.apache.commons.io.IOUtils; import org.apache.maven.plugin.logging.Log; -import org.openqa.selenium.JavascriptExecutor; -import org.openqa.selenium.WebDriver; -import org.openqa.selenium.WebDriverException; -import org.openqa.selenium.remote.DesiredCapabilities; -import org.openqa.selenium.remote.RemoteWebDriver; import org.teavm.model.MethodReference; import org.teavm.tooling.testing.TestCase; import org.teavm.tooling.testing.TestGroup; @@ -45,38 +35,24 @@ import org.teavm.tooling.testing.TestPlan; * * @author Alexey Andreev */ -public class SeleniumTestRunner { - private URL url; +public class TestRunner { private int numThreads = 1; - private ThreadLocal webDriver = new ThreadLocal<>(); - private BlockingQueue seleniumTaskQueue = new LinkedBlockingQueue<>(); + private TestRunStrategy strategy; + private BlockingQueue taskQueue = new LinkedBlockingQueue<>(); private CountDownLatch latch; - private volatile boolean seleniumStopped = false; + private volatile boolean stopped; private Log log; private List report = new CopyOnWriteArrayList<>(); private ThreadLocal> localReport = new ThreadLocal<>(); - private File directory = new File("."); - public URL getUrl() { - return url; - } - - public void setUrl(URL url) { - this.url = url; + public TestRunner(TestRunStrategy strategy) { + this.strategy = strategy; } public void setLog(Log log) { this.log = log; } - public File getDirectory() { - return directory; - } - - public void setDirectory(File directory) { - this.directory = directory; - } - public int getNumThreads() { return numThreads; } @@ -100,13 +76,12 @@ public class SeleniumTestRunner { latch = new CountDownLatch(numThreads); for (int i = 0; i < numThreads; ++i) { new Thread(() -> { - RemoteWebDriver driver = new RemoteWebDriver(DesiredCapabilities.chrome()); - webDriver.set(driver); + strategy.beforeThread(); localReport.set(new ArrayList<>()); - while (!seleniumStopped || !seleniumTaskQueue.isEmpty()) { + while (!stopped || !taskQueue.isEmpty()) { Runnable task; try { - task = seleniumTaskQueue.poll(100, TimeUnit.MILLISECONDS); + task = taskQueue.poll(100, TimeUnit.MILLISECONDS); } catch (InterruptedException e) { break; } @@ -116,19 +91,18 @@ public class SeleniumTestRunner { } report.addAll(localReport.get()); localReport.remove(); - webDriver.get().close(); - webDriver.remove(); + strategy.afterThread(); latch.countDown(); }).start(); } } - private void addSeleniumTask(Runnable runnable) { - seleniumTaskQueue.add(runnable); + private void addTask(Runnable runnable) { + taskQueue.add(runnable); } private void stopSelenium() { - seleniumStopped = true; + stopped = true; } private void waitForCompletion() { @@ -140,22 +114,20 @@ public class SeleniumTestRunner { } private void run(String runtimeScript, TestCase testCase) { - addSeleniumTask(() -> runImpl(runtimeScript, testCase)); + addTask(() -> runImpl(runtimeScript, testCase)); } private void runImpl(String runtimeScript, TestCase testCase) { - webDriver.get().manage().timeouts().setScriptTimeout(2, TimeUnit.SECONDS); - JavascriptExecutor js = (JavascriptExecutor) webDriver.get(); + MethodReference ref = MethodReference.parse(testCase.getTestMethod()); try { - String result = (String) js.executeAsyncScript( - readResource("teavm-selenium.js"), - readFile(new File(directory, runtimeScript)), - readFile(new File(directory, testCase.getTestScript())), - readResource("teavm-selenium-adapter.js")); + String result = strategy.runTest(log, runtimeScript, testCase); + if (result == null) { + log.info("Test failed: " + testCase.getTestMethod()); + localReport.get().add(TestResult.error(ref, null, null)); + } ObjectMapper mapper = new ObjectMapper(); ObjectNode resultObject = (ObjectNode) mapper.readTree(result); String status = resultObject.get("status").asText(); - MethodReference ref = MethodReference.parse(testCase.getTestMethod()); switch (status) { case "ok": if (testCase.getExpectedExceptions().isEmpty()) { @@ -181,28 +153,6 @@ public class SeleniumTestRunner { } } catch (IOException e) { log.error(e); - } catch (WebDriverException e) { - log.error("Error occured running test " + testCase.getTestMethod(), e); - @SuppressWarnings("unchecked") - List errors = (List) js.executeScript("return window.jsErrors;"); - for (Object error : errors) { - log.error(" -- additional error: " + error); - } - } - } - - private String readFile(File file) throws IOException { - try (InputStream input = new FileInputStream(file)) { - return IOUtils.toString(input, "UTF-8"); - } - } - - private String readResource(String resourceName) throws IOException { - try (InputStream input = BuildJavascriptTestMojo.class.getClassLoader().getResourceAsStream(resourceName)) { - if (input == null) { - return ""; - } - return IOUtils.toString(input, "UTF-8"); } } diff --git a/tools/maven/plugin/src/main/resources/teavm-htmlunit-adapter.js b/tools/maven/plugin/src/main/resources/teavm-htmlunit-adapter.js new file mode 100644 index 000000000..93d549474 --- /dev/null +++ b/tools/maven/plugin/src/main/resources/teavm-htmlunit-adapter.js @@ -0,0 +1,65 @@ +function(callback) { + var JUnitClient = {} + JUnitClient.run = function() { + $rt_startThread(function() { + var thread = $rt_nativeThread(); + var instance; + var ptr = 0; + var message; + if (thread.isResuming()) { + ptr = thread.pop(); + instance = thread.pop(); + } + loop: while (true) { switch (ptr) { + case 0: + instance = new TestClass(); + ptr = 1; + case 1: + try { + initInstance(instance); + } catch (e) { + message = {}; + JUnitClient.makeErrorMessage(message, e); + break loop; + } + if (thread.isSuspending()) { + thread.push(instance); + thread.push(ptr); + return; + } + ptr = 2; + case 2: + try { + runTest(instance); + } catch (e) { + message = {}; + JUnitClient.makeErrorMessage(message, e); + break loop; + } + if (thread.isSuspending()) { + thread.push(instance); + thread.push(ptr); + return; + } + message = {}; + message.status = "ok"; + break loop; + }} + callback.complete(JSON.stringify(message)); + }) + } + + JUnitClient.makeErrorMessage = function(message, e) { + message.status = "exception"; + var stack = e.stack; + if (e.$javaException && e.$javaException.constructor.$meta) { + message.exception = e.$javaException.constructor.$meta.name; + message.stack = e.$javaException.constructor.$meta.name + ": "; + var exceptionMessage = extractException(e.$javaException); + message.stack += exceptionMessage ? $rt_ustr(exceptionMessage) : ""; + } + message.stack += "\n" + stack; + } + + window.JUnitClient = JUnitClient; +} \ No newline at end of file From 931444fba44a33ad23ead39dc56f0d22609e702d Mon Sep 17 00:00:00 2001 From: Alexey Andreev Date: Sat, 10 Oct 2015 11:38:00 +0300 Subject: [PATCH 14/16] Update travis build script --- .travis.yml | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/.travis.yml b/.travis.yml index 92edf3e8c..ed207182d 100644 --- a/.travis.yml +++ b/.travis.yml @@ -4,10 +4,10 @@ jdk: cache: directories: - $HOME/.m2 +script: > + mvn test + -Pteavm.test.skip=false + -Pteavm.test.selenium="http://$SAUCE_USER_NAME:$SAUCE_ACCESS_KEY@ondemand.saucelabs.com:80/wd/hub" + -Pteavm.test.threads=2 after_script: - - rm -rf $HOME/.m2/repository/org/teavm -script: - - mvn test \ - - -Pteavm.test.skip=false \ - - -Pteavm.test.selenium="http://$SAUCE_USER_NAME:$SAUCE_ACCESS_KEY@ondemand.saucelabs.com:80/wd/hub" \ - - -Pteavm.test.threads=2 \ No newline at end of file + - rm -rf $HOME/.m2/repository/org/teavm \ No newline at end of file From a9e56d8f5c4a129bb5b3a935f01cf8d2dc433735 Mon Sep 17 00:00:00 2001 From: Alexey Andreev Date: Sat, 10 Oct 2015 11:59:29 +0300 Subject: [PATCH 15/16] Fix travis script --- .travis.yml | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/.travis.yml b/.travis.yml index ed207182d..54b22287e 100644 --- a/.travis.yml +++ b/.travis.yml @@ -5,9 +5,9 @@ cache: directories: - $HOME/.m2 script: > - mvn test - -Pteavm.test.skip=false - -Pteavm.test.selenium="http://$SAUCE_USER_NAME:$SAUCE_ACCESS_KEY@ondemand.saucelabs.com:80/wd/hub" + mvn test \ + -Pteavm.test.skip=false \ + -Pteavm.test.selenium="http://$SAUCE_USER_NAME:$SAUCE_ACCESS_KEY@ondemand.saucelabs.com:80/wd/hub" \ -Pteavm.test.threads=2 after_script: - rm -rf $HOME/.m2/repository/org/teavm \ No newline at end of file From c58493cabf98f28cb747c97af252d7f1898d33b9 Mon Sep 17 00:00:00 2001 From: Alexey Andreev Date: Sat, 10 Oct 2015 12:20:23 +0300 Subject: [PATCH 16/16] Fix build script --- .travis.yml | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/.travis.yml b/.travis.yml index 54b22287e..99a559dad 100644 --- a/.travis.yml +++ b/.travis.yml @@ -6,8 +6,8 @@ cache: - $HOME/.m2 script: > mvn test \ - -Pteavm.test.skip=false \ - -Pteavm.test.selenium="http://$SAUCE_USER_NAME:$SAUCE_ACCESS_KEY@ondemand.saucelabs.com:80/wd/hub" \ - -Pteavm.test.threads=2 + -Dteavm.test.skip=false \ + -Dteavm.test.selenium="http://$SAUCE_USER_NAME:$SAUCE_ACCESS_KEY@ondemand.saucelabs.com:80/wd/hub" \ + -Dteavm.test.threads=2 after_script: - rm -rf $HOME/.m2/repository/org/teavm \ No newline at end of file