mirror of
https://github.com/Eaglercraft-TeaVM-Fork/eagler-teavm.git
synced 2024-12-22 08:14:09 -08:00
Add HtmlUnit test runner. Add travis + Sauce Labs config
This commit is contained in:
parent
010a5fe579
commit
bac0785dc6
|
@ -5,4 +5,9 @@ cache:
|
||||||
directories:
|
directories:
|
||||||
- $HOME/.m2
|
- $HOME/.m2
|
||||||
after_script:
|
after_script:
|
||||||
- rm -rf $HOME/.m2/repository/org/teavm
|
- 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
|
|
@ -31,6 +31,7 @@
|
||||||
<teavm.test.incremental>false</teavm.test.incremental>
|
<teavm.test.incremental>false</teavm.test.incremental>
|
||||||
<teavm.test.threads>1</teavm.test.threads>
|
<teavm.test.threads>1</teavm.test.threads>
|
||||||
<teavm.test.selenium></teavm.test.selenium>
|
<teavm.test.selenium></teavm.test.selenium>
|
||||||
|
<teavm.test.skip>true</teavm.test.skip>
|
||||||
</properties>
|
</properties>
|
||||||
|
|
||||||
<dependencies>
|
<dependencies>
|
||||||
|
@ -100,6 +101,7 @@
|
||||||
<goal>test</goal>
|
<goal>test</goal>
|
||||||
</goals>
|
</goals>
|
||||||
<configuration>
|
<configuration>
|
||||||
|
<skip>${teavm.test.skip}</skip>
|
||||||
<numThreads>${teavm.test.threads}</numThreads>
|
<numThreads>${teavm.test.threads}</numThreads>
|
||||||
<seleniumURL>${teavm.test.selenium}</seleniumURL>
|
<seleniumURL>${teavm.test.selenium}</seleniumURL>
|
||||||
</configuration>
|
</configuration>
|
||||||
|
|
|
@ -69,6 +69,11 @@
|
||||||
<groupId>com.fasterxml.jackson.core</groupId>
|
<groupId>com.fasterxml.jackson.core</groupId>
|
||||||
<artifactId>jackson-databind</artifactId>
|
<artifactId>jackson-databind</artifactId>
|
||||||
</dependency>
|
</dependency>
|
||||||
|
<dependency>
|
||||||
|
<groupId>net.sourceforge.htmlunit</groupId>
|
||||||
|
<artifactId>htmlunit</artifactId>
|
||||||
|
<version>2.18</version>
|
||||||
|
</dependency>
|
||||||
<dependency>
|
<dependency>
|
||||||
<groupId>junit</groupId>
|
<groupId>junit</groupId>
|
||||||
<artifactId>junit</artifactId>
|
<artifactId>junit</artifactId>
|
||||||
|
@ -103,6 +108,14 @@
|
||||||
<groupId>org.apache.maven.plugins</groupId>
|
<groupId>org.apache.maven.plugins</groupId>
|
||||||
<artifactId>maven-javadoc-plugin</artifactId>
|
<artifactId>maven-javadoc-plugin</artifactId>
|
||||||
</plugin>
|
</plugin>
|
||||||
|
<plugin>
|
||||||
|
<groupId>org.apache.maven.plugins</groupId>
|
||||||
|
<artifactId>maven-checkstyle-plugin</artifactId>
|
||||||
|
<configuration>
|
||||||
|
<configLocation>../../../checkstyle.xml</configLocation>
|
||||||
|
<propertyExpansion>config_loc=${basedir}/../../..</propertyExpansion>
|
||||||
|
</configuration>
|
||||||
|
</plugin>
|
||||||
</plugins>
|
</plugins>
|
||||||
</build>
|
</build>
|
||||||
</project>
|
</project>
|
||||||
|
|
|
@ -106,8 +106,8 @@ public abstract class AbstractJavascriptMojo extends AbstractMojo {
|
||||||
throw new MojoExecutionException("Transformer not found: " + transformerName, e);
|
throw new MojoExecutionException("Transformer not found: " + transformerName, e);
|
||||||
}
|
}
|
||||||
if (!ClassHolderTransformer.class.isAssignableFrom(transformerRawType)) {
|
if (!ClassHolderTransformer.class.isAssignableFrom(transformerRawType)) {
|
||||||
throw new MojoExecutionException("Transformer " + transformerName + " is not subtype of " +
|
throw new MojoExecutionException("Transformer " + transformerName + " is not subtype of "
|
||||||
ClassHolderTransformer.class.getName());
|
+ ClassHolderTransformer.class.getName());
|
||||||
}
|
}
|
||||||
Class<? extends ClassHolderTransformer> transformerType = transformerRawType.asSubclass(
|
Class<? extends ClassHolderTransformer> transformerType = transformerRawType.asSubclass(
|
||||||
ClassHolderTransformer.class);
|
ClassHolderTransformer.class);
|
||||||
|
|
|
@ -85,8 +85,8 @@ public class BuildJavascriptTestMojo extends AbstractJavascriptMojo {
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void execute() throws MojoExecutionException, MojoFailureException {
|
public void execute() throws MojoExecutionException, MojoFailureException {
|
||||||
if (System.getProperty("maven.test.skip", "false").equals("true") ||
|
if (System.getProperty("maven.test.skip", "false").equals("true")
|
||||||
System.getProperty("skipTests") != null) {
|
|| System.getProperty("skipTests") != null) {
|
||||||
getLog().info("Tests build skipped as specified by system property");
|
getLog().info("Tests build skipped as specified by system property");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
@ -127,8 +127,8 @@ public class BuildJavascriptTestMojo extends AbstractJavascriptMojo {
|
||||||
throw new MojoExecutionException("Adapter not found: " + adapterClass, e);
|
throw new MojoExecutionException("Adapter not found: " + adapterClass, e);
|
||||||
}
|
}
|
||||||
if (!TestAdapter.class.isAssignableFrom(adapterClsRaw)) {
|
if (!TestAdapter.class.isAssignableFrom(adapterClsRaw)) {
|
||||||
throw new MojoExecutionException("Adapter " + adapterClass + " does not implement " +
|
throw new MojoExecutionException("Adapter " + adapterClass + " does not implement "
|
||||||
TestAdapter.class.getName());
|
+ TestAdapter.class.getName());
|
||||||
}
|
}
|
||||||
Class<? extends TestAdapter> adapterCls = adapterClsRaw.asSubclass(TestAdapter.class);
|
Class<? extends TestAdapter> adapterCls = adapterClsRaw.asSubclass(TestAdapter.class);
|
||||||
Constructor<? extends TestAdapter> cons;
|
Constructor<? extends TestAdapter> cons;
|
||||||
|
|
|
@ -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;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -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;
|
package org.teavm.maven;
|
||||||
|
|
||||||
import org.apache.maven.plugin.logging.Log;
|
import org.apache.maven.plugin.logging.Log;
|
||||||
|
|
|
@ -53,28 +53,25 @@ public class RunTestsMojo extends AbstractMojo {
|
||||||
@Parameter
|
@Parameter
|
||||||
private int numThreads = 1;
|
private int numThreads = 1;
|
||||||
|
|
||||||
|
@Parameter
|
||||||
|
private boolean skip;
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void execute() throws MojoExecutionException, MojoFailureException {
|
public void execute() throws MojoExecutionException, MojoFailureException {
|
||||||
if (seleniumURL == null || seleniumURL.isEmpty()) {
|
if (skip) {
|
||||||
getLog().info("Tests build skipped as selenium URL was not specified");
|
getLog().info("Tests run skipped as specified by skip property");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (System.getProperty("maven.test.skip", "false").equals("true") ||
|
if (System.getProperty("maven.test.skip", "false").equals("true")
|
||||||
System.getProperty("skipTests") != null) {
|
|| System.getProperty("skipTests") != null) {
|
||||||
getLog().info("Tests build skipped as specified by system property");
|
getLog().info("Tests run skipped as specified by system property");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
SeleniumTestRunner runner = new SeleniumTestRunner();
|
TestRunner runner = new TestRunner(pickStrategy());
|
||||||
runner.setLog(getLog());
|
runner.setLog(getLog());
|
||||||
runner.setDirectory(testDirectory);
|
|
||||||
runner.setNumThreads(numThreads);
|
runner.setNumThreads(numThreads);
|
||||||
try {
|
|
||||||
runner.setUrl(new URL(seleniumURL));
|
|
||||||
} catch (MalformedURLException e) {
|
|
||||||
throw new MojoFailureException("Can't parse URL: " + seleniumURL, e);
|
|
||||||
}
|
|
||||||
|
|
||||||
TestPlan plan;
|
TestPlan plan;
|
||||||
ObjectMapper mapper = new ObjectMapper();
|
ObjectMapper mapper = new ObjectMapper();
|
||||||
|
@ -89,6 +86,18 @@ public class RunTestsMojo extends AbstractMojo {
|
||||||
processReport(runner.getReport());
|
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 {
|
private void processReport(TestReport report) throws MojoExecutionException, MojoFailureException {
|
||||||
if (report.getResults().isEmpty()) {
|
if (report.getResults().isEmpty()) {
|
||||||
getLog().info("No tests ran");
|
getLog().info("No tests ran");
|
||||||
|
|
|
@ -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> 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<Object> errors = (List<Object>) 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");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -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;
|
package org.teavm.maven;
|
||||||
|
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
|
|
|
@ -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;
|
||||||
|
}
|
|
@ -17,11 +17,7 @@ package org.teavm.maven;
|
||||||
|
|
||||||
import com.fasterxml.jackson.databind.ObjectMapper;
|
import com.fasterxml.jackson.databind.ObjectMapper;
|
||||||
import com.fasterxml.jackson.databind.node.ObjectNode;
|
import com.fasterxml.jackson.databind.node.ObjectNode;
|
||||||
import java.io.File;
|
|
||||||
import java.io.FileInputStream;
|
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
import java.io.InputStream;
|
|
||||||
import java.net.URL;
|
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.concurrent.BlockingQueue;
|
import java.util.concurrent.BlockingQueue;
|
||||||
|
@ -29,13 +25,7 @@ import java.util.concurrent.CopyOnWriteArrayList;
|
||||||
import java.util.concurrent.CountDownLatch;
|
import java.util.concurrent.CountDownLatch;
|
||||||
import java.util.concurrent.LinkedBlockingQueue;
|
import java.util.concurrent.LinkedBlockingQueue;
|
||||||
import java.util.concurrent.TimeUnit;
|
import java.util.concurrent.TimeUnit;
|
||||||
import org.apache.commons.io.IOUtils;
|
|
||||||
import org.apache.maven.plugin.logging.Log;
|
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.model.MethodReference;
|
||||||
import org.teavm.tooling.testing.TestCase;
|
import org.teavm.tooling.testing.TestCase;
|
||||||
import org.teavm.tooling.testing.TestGroup;
|
import org.teavm.tooling.testing.TestGroup;
|
||||||
|
@ -45,38 +35,24 @@ import org.teavm.tooling.testing.TestPlan;
|
||||||
*
|
*
|
||||||
* @author Alexey Andreev
|
* @author Alexey Andreev
|
||||||
*/
|
*/
|
||||||
public class SeleniumTestRunner {
|
public class TestRunner {
|
||||||
private URL url;
|
|
||||||
private int numThreads = 1;
|
private int numThreads = 1;
|
||||||
private ThreadLocal<WebDriver> webDriver = new ThreadLocal<>();
|
private TestRunStrategy strategy;
|
||||||
private BlockingQueue<Runnable> seleniumTaskQueue = new LinkedBlockingQueue<>();
|
private BlockingQueue<Runnable> taskQueue = new LinkedBlockingQueue<>();
|
||||||
private CountDownLatch latch;
|
private CountDownLatch latch;
|
||||||
private volatile boolean seleniumStopped = false;
|
private volatile boolean stopped;
|
||||||
private Log log;
|
private Log log;
|
||||||
private List<TestResult> report = new CopyOnWriteArrayList<>();
|
private List<TestResult> report = new CopyOnWriteArrayList<>();
|
||||||
private ThreadLocal<List<TestResult>> localReport = new ThreadLocal<>();
|
private ThreadLocal<List<TestResult>> localReport = new ThreadLocal<>();
|
||||||
private File directory = new File(".");
|
|
||||||
|
|
||||||
public URL getUrl() {
|
public TestRunner(TestRunStrategy strategy) {
|
||||||
return url;
|
this.strategy = strategy;
|
||||||
}
|
|
||||||
|
|
||||||
public void setUrl(URL url) {
|
|
||||||
this.url = url;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public void setLog(Log log) {
|
public void setLog(Log log) {
|
||||||
this.log = log;
|
this.log = log;
|
||||||
}
|
}
|
||||||
|
|
||||||
public File getDirectory() {
|
|
||||||
return directory;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void setDirectory(File directory) {
|
|
||||||
this.directory = directory;
|
|
||||||
}
|
|
||||||
|
|
||||||
public int getNumThreads() {
|
public int getNumThreads() {
|
||||||
return numThreads;
|
return numThreads;
|
||||||
}
|
}
|
||||||
|
@ -100,13 +76,12 @@ public class SeleniumTestRunner {
|
||||||
latch = new CountDownLatch(numThreads);
|
latch = new CountDownLatch(numThreads);
|
||||||
for (int i = 0; i < numThreads; ++i) {
|
for (int i = 0; i < numThreads; ++i) {
|
||||||
new Thread(() -> {
|
new Thread(() -> {
|
||||||
RemoteWebDriver driver = new RemoteWebDriver(DesiredCapabilities.chrome());
|
strategy.beforeThread();
|
||||||
webDriver.set(driver);
|
|
||||||
localReport.set(new ArrayList<>());
|
localReport.set(new ArrayList<>());
|
||||||
while (!seleniumStopped || !seleniumTaskQueue.isEmpty()) {
|
while (!stopped || !taskQueue.isEmpty()) {
|
||||||
Runnable task;
|
Runnable task;
|
||||||
try {
|
try {
|
||||||
task = seleniumTaskQueue.poll(100, TimeUnit.MILLISECONDS);
|
task = taskQueue.poll(100, TimeUnit.MILLISECONDS);
|
||||||
} catch (InterruptedException e) {
|
} catch (InterruptedException e) {
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
@ -116,19 +91,18 @@ public class SeleniumTestRunner {
|
||||||
}
|
}
|
||||||
report.addAll(localReport.get());
|
report.addAll(localReport.get());
|
||||||
localReport.remove();
|
localReport.remove();
|
||||||
webDriver.get().close();
|
strategy.afterThread();
|
||||||
webDriver.remove();
|
|
||||||
latch.countDown();
|
latch.countDown();
|
||||||
}).start();
|
}).start();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private void addSeleniumTask(Runnable runnable) {
|
private void addTask(Runnable runnable) {
|
||||||
seleniumTaskQueue.add(runnable);
|
taskQueue.add(runnable);
|
||||||
}
|
}
|
||||||
|
|
||||||
private void stopSelenium() {
|
private void stopSelenium() {
|
||||||
seleniumStopped = true;
|
stopped = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
private void waitForCompletion() {
|
private void waitForCompletion() {
|
||||||
|
@ -140,22 +114,20 @@ public class SeleniumTestRunner {
|
||||||
}
|
}
|
||||||
|
|
||||||
private void run(String runtimeScript, TestCase testCase) {
|
private void run(String runtimeScript, TestCase testCase) {
|
||||||
addSeleniumTask(() -> runImpl(runtimeScript, testCase));
|
addTask(() -> runImpl(runtimeScript, testCase));
|
||||||
}
|
}
|
||||||
|
|
||||||
private void runImpl(String runtimeScript, TestCase testCase) {
|
private void runImpl(String runtimeScript, TestCase testCase) {
|
||||||
webDriver.get().manage().timeouts().setScriptTimeout(2, TimeUnit.SECONDS);
|
MethodReference ref = MethodReference.parse(testCase.getTestMethod());
|
||||||
JavascriptExecutor js = (JavascriptExecutor) webDriver.get();
|
|
||||||
try {
|
try {
|
||||||
String result = (String) js.executeAsyncScript(
|
String result = strategy.runTest(log, runtimeScript, testCase);
|
||||||
readResource("teavm-selenium.js"),
|
if (result == null) {
|
||||||
readFile(new File(directory, runtimeScript)),
|
log.info("Test failed: " + testCase.getTestMethod());
|
||||||
readFile(new File(directory, testCase.getTestScript())),
|
localReport.get().add(TestResult.error(ref, null, null));
|
||||||
readResource("teavm-selenium-adapter.js"));
|
}
|
||||||
ObjectMapper mapper = new ObjectMapper();
|
ObjectMapper mapper = new ObjectMapper();
|
||||||
ObjectNode resultObject = (ObjectNode) mapper.readTree(result);
|
ObjectNode resultObject = (ObjectNode) mapper.readTree(result);
|
||||||
String status = resultObject.get("status").asText();
|
String status = resultObject.get("status").asText();
|
||||||
MethodReference ref = MethodReference.parse(testCase.getTestMethod());
|
|
||||||
switch (status) {
|
switch (status) {
|
||||||
case "ok":
|
case "ok":
|
||||||
if (testCase.getExpectedExceptions().isEmpty()) {
|
if (testCase.getExpectedExceptions().isEmpty()) {
|
||||||
|
@ -181,28 +153,6 @@ public class SeleniumTestRunner {
|
||||||
}
|
}
|
||||||
} catch (IOException e) {
|
} catch (IOException e) {
|
||||||
log.error(e);
|
log.error(e);
|
||||||
} catch (WebDriverException e) {
|
|
||||||
log.error("Error occured running test " + testCase.getTestMethod(), e);
|
|
||||||
@SuppressWarnings("unchecked")
|
|
||||||
List<Object> errors = (List<Object>) 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");
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -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;
|
||||||
|
}
|
Loading…
Reference in New Issue
Block a user