From d007b0c8ac49d8728032c24d161b59ae9583bb25 Mon Sep 17 00:00:00 2001 From: Alexey Andreev Date: Fri, 9 Oct 2015 18:30:31 +0300 Subject: [PATCH] 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; } }