mirror of
https://github.com/Eaglercraft-TeaVM-Fork/eagler-teavm.git
synced 2024-12-22 08:14:09 -08:00
JS: remove old node-based test runner, use new JUnit browser runner in travis
This commit is contained in:
parent
bc9ad315ff
commit
707d11d9d8
24
.travis.yml
24
.travis.yml
|
@ -20,7 +20,6 @@ branches:
|
||||||
|
|
||||||
before_install:
|
before_install:
|
||||||
- export MVN_CMD="mvn -Dmaven.repo.local=$HOME/mvn_repo -B"
|
- export MVN_CMD="mvn -Dmaven.repo.local=$HOME/mvn_repo -B"
|
||||||
- nvm install 7
|
|
||||||
- OLD_VERSION=`$MVN_CMD help:evaluate -Dexpression=project.version 2>/dev/null | grep -Ev "(^\[|Download)"`
|
- OLD_VERSION=`$MVN_CMD help:evaluate -Dexpression=project.version 2>/dev/null | grep -Ev "(^\[|Download)"`
|
||||||
- BASE_VERSION=${OLD_VERSION%-SNAPSHOT}
|
- BASE_VERSION=${OLD_VERSION%-SNAPSHOT}
|
||||||
- NEW_VERSION=${BASE_VERSION}-dev-`printf %d $TRAVIS_BUILD_NUMBER`
|
- NEW_VERSION=${BASE_VERSION}-dev-`printf %d $TRAVIS_BUILD_NUMBER`
|
||||||
|
@ -34,29 +33,8 @@ before_install:
|
||||||
- rm -rf $HOME/.rvm
|
- rm -rf $HOME/.rvm
|
||||||
- rm -rf $HOME/.m2
|
- rm -rf $HOME/.m2
|
||||||
|
|
||||||
install:
|
|
||||||
- pushd tests/src/test/js
|
|
||||||
- npm config set prefix=$HOME/.node_modules
|
|
||||||
- npm install
|
|
||||||
- npm run build
|
|
||||||
- google-chrome-stable --headless --disable-gpu --remote-debugging-port=9222 index.html &
|
|
||||||
- BROWSER_PID=$!
|
|
||||||
- node start.js test
|
|
||||||
- node ./bin/test-chrome.js
|
|
||||||
- kill $BROWSER_PID
|
|
||||||
- popd
|
|
||||||
- rm -rf tools/idea/idea-artifacts/dependencies
|
|
||||||
|
|
||||||
script:
|
script:
|
||||||
- $MVN_CMD -e install -Dteavm.junit.optimized=false -Dteavm.junit.js.decodeStack=false -P with-idea -P with-cli -Dteavm.junit.js.runner=none -V
|
- $MVN_CMD -e install -Dteavm.junit.optimized=false -Dteavm.junit.js.decodeStack=false -P with-idea -P with-cli -Dteavm.junit.threads=2 -Dteavm.junit.js.runner=browser-chrome -V
|
||||||
- BASE_PATH=`pwd`
|
|
||||||
- pushd tests/src/test/js
|
|
||||||
- google-chrome-stable --headless --disable-gpu --remote-debugging-port=9222 index.html &
|
|
||||||
- BROWSER_PID=$!
|
|
||||||
- node start.js $BASE_PATH/tests/target/js-tests
|
|
||||||
- node start.js $BASE_PATH/html4j/target/js-tests
|
|
||||||
- kill $BROWSER_PID
|
|
||||||
- popd
|
|
||||||
- rm -rf $BASE_PATH/tests/target/js-tests
|
- rm -rf $BASE_PATH/tests/target/js-tests
|
||||||
- rm -rf $BASE_PATH/html4j/target/js-tests
|
- rm -rf $BASE_PATH/html4j/target/js-tests
|
||||||
- du -sh $HOME/.[!.]* /home/travis/* | sort -h
|
- du -sh $HOME/.[!.]* /home/travis/* | sort -h
|
||||||
|
|
|
@ -1,7 +0,0 @@
|
||||||
{
|
|
||||||
"presets": [["env", {
|
|
||||||
"targets": {
|
|
||||||
"node": "current"
|
|
||||||
}
|
|
||||||
}]]
|
|
||||||
}
|
|
4
tests/src/test/js/.gitignore
vendored
4
tests/src/test/js/.gitignore
vendored
|
@ -1,4 +0,0 @@
|
||||||
/node_modules/
|
|
||||||
/bin/
|
|
||||||
/tmp/
|
|
||||||
package-lock.json
|
|
|
@ -1,84 +0,0 @@
|
||||||
/*
|
|
||||||
* Copyright 2017 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.
|
|
||||||
*/
|
|
||||||
|
|
||||||
"use strict";
|
|
||||||
|
|
||||||
function tryConnect() {
|
|
||||||
let ws = new WebSocket("ws://localhost:9090");
|
|
||||||
|
|
||||||
ws.onopen = () => {
|
|
||||||
console.log("Connection established");
|
|
||||||
listen(ws);
|
|
||||||
};
|
|
||||||
|
|
||||||
ws.onclose = () => {
|
|
||||||
ws.close();
|
|
||||||
setTimeout(() => {
|
|
||||||
tryConnect();
|
|
||||||
}, 500);
|
|
||||||
};
|
|
||||||
|
|
||||||
ws.onerror = err => {
|
|
||||||
console.log("Could not connect WebSocket", err);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
function listen(ws) {
|
|
||||||
ws.onmessage = (event) => {
|
|
||||||
let request = JSON.parse(event.data);
|
|
||||||
console.log("Request #" + request.id + " received");
|
|
||||||
runTests(ws, request.id, request.tests, 0);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
function runTests(ws, suiteId, tests, index) {
|
|
||||||
if (index === tests.length) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
let test = tests[index];
|
|
||||||
runSingleTest(test, result => {
|
|
||||||
console.log("Sending response #" + suiteId);
|
|
||||||
ws.send(JSON.stringify({
|
|
||||||
id: suiteId,
|
|
||||||
index: index,
|
|
||||||
result: result
|
|
||||||
}));
|
|
||||||
runTests(ws, suiteId, tests, index + 1);
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
function runSingleTest(test, callback) {
|
|
||||||
console.log("Running test " + test.name + " consisting of " + test.files);
|
|
||||||
let iframe = document.createElement("iframe");
|
|
||||||
document.body.appendChild(iframe);
|
|
||||||
let handshakeListener = () => {
|
|
||||||
window.removeEventListener("message", handshakeListener);
|
|
||||||
|
|
||||||
let listener = event => {
|
|
||||||
window.removeEventListener("message", listener);
|
|
||||||
document.body.removeChild(iframe);
|
|
||||||
callback(event.data);
|
|
||||||
};
|
|
||||||
window.addEventListener("message", listener);
|
|
||||||
|
|
||||||
iframe.contentWindow.postMessage(test, "*");
|
|
||||||
};
|
|
||||||
window.addEventListener("message", handshakeListener);
|
|
||||||
iframe.src = "about:blank";
|
|
||||||
iframe.src = "frame.html";
|
|
||||||
}
|
|
||||||
|
|
||||||
tryConnect();
|
|
|
@ -1,25 +0,0 @@
|
||||||
<!--
|
|
||||||
~ Copyright 2017 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.
|
|
||||||
-->
|
|
||||||
|
|
||||||
<!DOCTYPE html>
|
|
||||||
<html>
|
|
||||||
<head>
|
|
||||||
<meta charset="utf-8">
|
|
||||||
<script src="frame.js"></script>
|
|
||||||
</head>
|
|
||||||
<body onload="start()">
|
|
||||||
</body>
|
|
||||||
</html>
|
|
|
@ -1,127 +0,0 @@
|
||||||
/*
|
|
||||||
* Copyright 2017 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.
|
|
||||||
*/
|
|
||||||
|
|
||||||
"use strict";
|
|
||||||
|
|
||||||
window.addEventListener("message", event => {
|
|
||||||
let request = event.data;
|
|
||||||
switch (request.type) {
|
|
||||||
case "JAVASCRIPT":
|
|
||||||
appendFiles([request.file], 0, () => {
|
|
||||||
launchTest(request.argument, response => {
|
|
||||||
event.source.postMessage(response, "*");
|
|
||||||
});
|
|
||||||
}, error => {
|
|
||||||
event.source.postMessage({ status: "failed", errorMessage: error }, "*");
|
|
||||||
});
|
|
||||||
break;
|
|
||||||
|
|
||||||
case "WASM":
|
|
||||||
const runtimeFile = request.file + "-runtime.js";
|
|
||||||
appendFiles([runtimeFile], 0, () => {
|
|
||||||
launchWasmTest(request.file, equest.argument, response => {
|
|
||||||
event.source.postMessage(response, "*");
|
|
||||||
});
|
|
||||||
}, error => {
|
|
||||||
event.source.postMessage({ status: "failed", errorMessage: error }, "*");
|
|
||||||
});
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
function appendFiles(files, index, callback, errorCallback) {
|
|
||||||
if (index === files.length) {
|
|
||||||
callback();
|
|
||||||
} else {
|
|
||||||
let fileName = files[index];
|
|
||||||
let script = document.createElement("script");
|
|
||||||
script.onload = () => {
|
|
||||||
appendFiles(files, index + 1, callback, errorCallback);
|
|
||||||
};
|
|
||||||
script.onerror = () => {
|
|
||||||
errorCallback("failed to load script " + fileName);
|
|
||||||
};
|
|
||||||
script.src = fileName;
|
|
||||||
document.body.appendChild(script);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
function launchTest(argument, callback) {
|
|
||||||
main(argument ? [argument] : [], result => {
|
|
||||||
if (result instanceof Error) {
|
|
||||||
callback({
|
|
||||||
status: "failed",
|
|
||||||
errorMessage: buildErrorMessage(result)
|
|
||||||
});
|
|
||||||
} else {
|
|
||||||
callback({ status: "OK" });
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
function buildErrorMessage(e) {
|
|
||||||
let stack = "";
|
|
||||||
let je = main.javaException(e);
|
|
||||||
if (je && je.constructor.$meta) {
|
|
||||||
stack = je.constructor.$meta.name + ": ";
|
|
||||||
stack += je.getMessage();
|
|
||||||
stack += "\n";
|
|
||||||
}
|
|
||||||
stack += e.stack;
|
|
||||||
return stack;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
function launchWasmTest(path, argument, callback) {
|
|
||||||
let output = [];
|
|
||||||
let outputBuffer = "";
|
|
||||||
|
|
||||||
function putwchar(charCode) {
|
|
||||||
if (charCode === 10) {
|
|
||||||
switch (outputBuffer) {
|
|
||||||
case "SUCCESS":
|
|
||||||
callback({status: "OK"});
|
|
||||||
break;
|
|
||||||
case "FAILURE":
|
|
||||||
callback({
|
|
||||||
status: "failed",
|
|
||||||
errorMessage: output.join("\n")
|
|
||||||
});
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
output.push(outputBuffer);
|
|
||||||
outputBuffer = "";
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
outputBuffer += String.fromCharCode(charCode);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
TeaVM.wasm.run(path, {
|
|
||||||
installImports: function(o) {
|
|
||||||
o.teavm.putwchar = putwchar;
|
|
||||||
},
|
|
||||||
errorCallback: function(err) {
|
|
||||||
callback({
|
|
||||||
status: "failed",
|
|
||||||
errorMessage: err.message + '\n' + err.stack
|
|
||||||
});
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
function start() {
|
|
||||||
window.parent.postMessage("ready", "*");
|
|
||||||
}
|
|
|
@ -1,25 +0,0 @@
|
||||||
<!--
|
|
||||||
~ Copyright 2017 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.
|
|
||||||
-->
|
|
||||||
|
|
||||||
<!DOCTYPE html>
|
|
||||||
<html>
|
|
||||||
<head>
|
|
||||||
<meta charset="utf-8">
|
|
||||||
<script src="client.js"></script>
|
|
||||||
</head>
|
|
||||||
<body>
|
|
||||||
</body>
|
|
||||||
</html>
|
|
|
@ -1,13 +0,0 @@
|
||||||
{
|
|
||||||
"name": "teavm-tests",
|
|
||||||
"devDependencies": {
|
|
||||||
"babel-cli": "6.24.1",
|
|
||||||
"babel-core": "6.24.1",
|
|
||||||
"babel-polyfill": "6.23.0",
|
|
||||||
"babel-preset-env": "1.4.0",
|
|
||||||
"websocket": "1.0.24"
|
|
||||||
},
|
|
||||||
"scripts": {
|
|
||||||
"build": "babel src -d bin --source-maps"
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,4 +0,0 @@
|
||||||
#!/bin/bash
|
|
||||||
|
|
||||||
npm run build
|
|
||||||
node start.js ../../../target/js-tests/
|
|
|
@ -1,118 +0,0 @@
|
||||||
/*
|
|
||||||
* Copyright 2019 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.
|
|
||||||
*/
|
|
||||||
|
|
||||||
"use strict";
|
|
||||||
|
|
||||||
import * as http from "http";
|
|
||||||
import { client as WebSocketClient } from "websocket";
|
|
||||||
|
|
||||||
function httpGetJson(url) {
|
|
||||||
return new Promise((resolve, reject) => {
|
|
||||||
http.request(url, resp => {
|
|
||||||
if (resp.statusCode !== 200) {
|
|
||||||
reject(new Error(`HTTP status: ${resp.statusCode}`));
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
let data = "";
|
|
||||||
resp.on('data', (chunk) => {
|
|
||||||
data += chunk;
|
|
||||||
});
|
|
||||||
resp.on('end', () => {
|
|
||||||
resolve(JSON.parse(data));
|
|
||||||
});
|
|
||||||
}).on("error", err => {
|
|
||||||
reject(new Error(`HTTP error: ${err.message}`));
|
|
||||||
}).end();
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
function connectWs(url) {
|
|
||||||
return new Promise((resolve, reject) => {
|
|
||||||
const client = new WebSocketClient();
|
|
||||||
client.on("connectFailed", error => reject(new Error('Connect Error: ' + error)));
|
|
||||||
client.on("connect", resolve);
|
|
||||||
client.connect(url);
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
class CDP {
|
|
||||||
constructor(conn) {
|
|
||||||
this.idGenerator = 1;
|
|
||||||
this.pendingCalls = Object.create(null);
|
|
||||||
this.eventHandlers = Object.create(null);
|
|
||||||
this.conn = conn;
|
|
||||||
}
|
|
||||||
|
|
||||||
start() {
|
|
||||||
this.conn.on("message", message => {
|
|
||||||
if (message.type === 'utf8') {
|
|
||||||
const messageObj = JSON.parse(message.utf8Data);
|
|
||||||
if (messageObj.id !== void 0) {
|
|
||||||
const pendingCall = this.pendingCalls[messageObj.id];
|
|
||||||
delete this.pendingCalls[messageObj.id];
|
|
||||||
if (messageObj.error) {
|
|
||||||
pendingCall.reject(new Error(`Error calling CDP method ${messageObj.error}`));
|
|
||||||
} else {
|
|
||||||
pendingCall.resolve(messageObj.result);
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
const handlers = this.eventHandlers[messageObj.method];
|
|
||||||
if (handlers) {
|
|
||||||
for (const handler of handlers) {
|
|
||||||
handler(messageObj.params);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
});
|
|
||||||
this.conn.on("close", () => {
|
|
||||||
for (const key in Object.getOwnPropertyNames(this.pendingCalls)) {
|
|
||||||
this.pendingCalls[key].reject(new Error("Connection closed before result received"));
|
|
||||||
}
|
|
||||||
});
|
|
||||||
this.conn.on("error", err => {
|
|
||||||
console.error("WS error: %j", err);
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
call(method, params = undefined) {
|
|
||||||
return new Promise((resolve, reject) => {
|
|
||||||
const id = this.idGenerator++;
|
|
||||||
this.pendingCalls[id] = { resolve, reject };
|
|
||||||
this.conn.send(JSON.stringify({ id, method, params }));
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
async on(eventName, handler) {
|
|
||||||
let handlers = this.eventHandlers[eventName];
|
|
||||||
if (handlers === void 0) {
|
|
||||||
handlers = [];
|
|
||||||
this.eventHandlers[eventName] = handlers;
|
|
||||||
}
|
|
||||||
handlers.push(handler);
|
|
||||||
}
|
|
||||||
|
|
||||||
static async connect(url) {
|
|
||||||
const targets = await httpGetJson(url + "/json/list");
|
|
||||||
const wsUrl = targets.find(target => target.type === "page").webSocketDebuggerUrl;
|
|
||||||
console.log("Connected to Chrome");
|
|
||||||
const wsConn = await connectWs(wsUrl);
|
|
||||||
console.log(`Connected to WS endpoint: ${wsUrl}`);
|
|
||||||
return wsConn;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
export { CDP };
|
|
|
@ -1,48 +0,0 @@
|
||||||
/*
|
|
||||||
* Copyright 2019 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.
|
|
||||||
*/
|
|
||||||
|
|
||||||
"use strict";
|
|
||||||
|
|
||||||
import { CDP } from "./cdp.js";
|
|
||||||
|
|
||||||
async function run() {
|
|
||||||
const wsConn = await CDP.connect("http://localhost:9222");
|
|
||||||
const cdp = new CDP(wsConn);
|
|
||||||
const waitForLog = new Promise(resolve => {
|
|
||||||
let timeout = setTimeout(resolve, 500);
|
|
||||||
cdp.on("Runtime.consoleAPICalled", event => {
|
|
||||||
const value = event.args.filter(arg => arg.type === "string").map(arg => arg.value).join("");
|
|
||||||
if (value !== "") {
|
|
||||||
console.log("[LOG] " + new Date(event.timestamp) + ": " + value);
|
|
||||||
}
|
|
||||||
clearTimeout(timeout);
|
|
||||||
timeout = setTimeout(resolve, 500);
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
cdp.start();
|
|
||||||
|
|
||||||
try {
|
|
||||||
await cdp.call("Runtime.enable");
|
|
||||||
await waitForLog;
|
|
||||||
} finally {
|
|
||||||
wsConn.close();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
run().catch(e => {
|
|
||||||
console.error("Error", e);
|
|
||||||
});
|
|
|
@ -1,42 +0,0 @@
|
||||||
/*
|
|
||||||
* Copyright 2017 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.
|
|
||||||
*/
|
|
||||||
|
|
||||||
"use strict";
|
|
||||||
|
|
||||||
import * as fs from "fs";
|
|
||||||
|
|
||||||
function wrapFsFunction(fsFunction) {
|
|
||||||
return function() {
|
|
||||||
const self = this;
|
|
||||||
const args = Array.prototype.slice.call(arguments);
|
|
||||||
return new Promise((resolve, reject) => {
|
|
||||||
args.push((error, result) => {
|
|
||||||
if (!error) {
|
|
||||||
resolve(result);
|
|
||||||
} else {
|
|
||||||
reject(error);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
fsFunction.apply(self, args);
|
|
||||||
})
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
export let
|
|
||||||
readdir = wrapFsFunction(fs.readdir),
|
|
||||||
readFile = wrapFsFunction(fs.readFile),
|
|
||||||
stat = wrapFsFunction(fs.stat),
|
|
||||||
open = wrapFsFunction(fs.open);
|
|
|
@ -1,318 +0,0 @@
|
||||||
/*
|
|
||||||
* Copyright 2017 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.
|
|
||||||
*/
|
|
||||||
|
|
||||||
"use strict";
|
|
||||||
import * as fs from "./promise-fs.js";
|
|
||||||
import * as http from "http";
|
|
||||||
import {server as WebSocketServer} from "websocket";
|
|
||||||
|
|
||||||
let totalTests = 0;
|
|
||||||
|
|
||||||
class TestSuite {
|
|
||||||
constructor(name) {
|
|
||||||
this.name = name;
|
|
||||||
this.testSuites = [];
|
|
||||||
this.testCases = [];
|
|
||||||
}
|
|
||||||
}
|
|
||||||
class TestCase {
|
|
||||||
constructor(type, file, argument) {
|
|
||||||
this.type = type;
|
|
||||||
this.file = file;
|
|
||||||
this.argument = argument
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
let rootDir = process.argv[2];
|
|
||||||
if (rootDir.endsWith("/")) {
|
|
||||||
rootDir = rootDir.substring(0, rootDir.length - 1);
|
|
||||||
}
|
|
||||||
|
|
||||||
async function runAll() {
|
|
||||||
const rootSuite = new TestSuite("root");
|
|
||||||
console.log("Searching tests");
|
|
||||||
await walkDir("", rootSuite);
|
|
||||||
|
|
||||||
console.log("Running tests");
|
|
||||||
|
|
||||||
const server = http.createServer((request, response) => {
|
|
||||||
if (request.url.endsWith(".js") || request.url.endsWith(".wasm")) {
|
|
||||||
serveFile(rootDir + "/" + request.url, response);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
response.writeHead(404);
|
|
||||||
response.end();
|
|
||||||
});
|
|
||||||
server.listen({ host: "localhost", port: 9090 }, () => {
|
|
||||||
console.log((new Date()) + ' Server is listening on port 9090');
|
|
||||||
});
|
|
||||||
|
|
||||||
const wsServer = new WebSocketServer({
|
|
||||||
httpServer: server,
|
|
||||||
autoAcceptConnections: true
|
|
||||||
});
|
|
||||||
|
|
||||||
const startTime = new Date().getTime();
|
|
||||||
const connectPromise = new Promise(resolve => wsServer.on("connect", resolve));
|
|
||||||
const timeoutPromise = new Promise((_, reject) => {
|
|
||||||
setTimeout(() => reject(new Error("Connection time out")), 15000)
|
|
||||||
});
|
|
||||||
const conn = await Promise.race([connectPromise, timeoutPromise]);
|
|
||||||
|
|
||||||
const runner = new TestRunner(conn);
|
|
||||||
await runner.runTests(rootSuite, "", 0);
|
|
||||||
|
|
||||||
wsServer.unmount();
|
|
||||||
server.close();
|
|
||||||
|
|
||||||
const endTime = new Date().getTime();
|
|
||||||
for (let i = 0; i < runner.testsFailed.length; i++) {
|
|
||||||
const failedTest = runner.testsFailed[i];
|
|
||||||
console.log("(" + (i + 1) + ") " + failedTest.path +":");
|
|
||||||
console.log(failedTest.message);
|
|
||||||
console.log();
|
|
||||||
}
|
|
||||||
|
|
||||||
console.log("Tests run: " + runner.testsRun + ", failed: " + runner.testsFailed.length
|
|
||||||
+ ", elapsed " + ((endTime - startTime) / 1000) + " seconds");
|
|
||||||
|
|
||||||
if (runner.testsFailed.length > 0) {
|
|
||||||
process.exit(1);
|
|
||||||
} else {
|
|
||||||
process.exit(0);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
async function serveFile(path, response) {
|
|
||||||
const stat = await fs.stat(path);
|
|
||||||
const contentType = path.endsWith(".wasm") ? "application/octet-stream" : "text/javascript";
|
|
||||||
if (stat.isFile()) {
|
|
||||||
const content = await fs.readFile(path);
|
|
||||||
response.writeHead(200, { 'Content-Type': contentType, 'Access-Control-Allow-Origin': "*" });
|
|
||||||
response.end(content, 'utf-8');
|
|
||||||
} else {
|
|
||||||
response.writeHead(404);
|
|
||||||
response.end();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
async function walkDir(path, suite) {
|
|
||||||
const files = await fs.readdir(rootDir + "/" + path);
|
|
||||||
if (files.includes("tests.json")) {
|
|
||||||
const descriptor = JSON.parse(await fs.readFile(`${rootDir}/${path}/tests.json`));
|
|
||||||
for (const { baseDir, fileName, kind, argument } of descriptor) {
|
|
||||||
switch (kind) {
|
|
||||||
case "JAVASCRIPT":
|
|
||||||
case "WASM":
|
|
||||||
suite.testCases.push(new TestCase(kind, `${baseDir}/${fileName}`, argument));
|
|
||||||
totalTests++;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
await Promise.all(files.map(async file => {
|
|
||||||
const filePath = path + "/" + file;
|
|
||||||
const stat = await fs.stat(rootDir + "/" + filePath);
|
|
||||||
if (stat.isDirectory()) {
|
|
||||||
const childSuite = new TestSuite(file);
|
|
||||||
suite.testSuites.push(childSuite);
|
|
||||||
await walkDir(filePath, childSuite);
|
|
||||||
}
|
|
||||||
}));
|
|
||||||
}
|
|
||||||
|
|
||||||
class TestRunner {
|
|
||||||
constructor(ws) {
|
|
||||||
this.ws = ws;
|
|
||||||
this.testsRun = 0;
|
|
||||||
this.testsFailed = [];
|
|
||||||
|
|
||||||
this.pendingRequests = Object.create(null);
|
|
||||||
this.requestIdGen = 0;
|
|
||||||
|
|
||||||
this.timeout = null;
|
|
||||||
|
|
||||||
this.ws.on("message", (message) => {
|
|
||||||
const response = JSON.parse(message.utf8Data);
|
|
||||||
const pendingRequest = this.pendingRequests[response.id + "-" + response.index];
|
|
||||||
delete this.pendingRequests[response.id];
|
|
||||||
if (this.timeout) {
|
|
||||||
this.timeout.refresh();
|
|
||||||
}
|
|
||||||
pendingRequest(response.result);
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
async runTests(suite, path, depth) {
|
|
||||||
if (suite.testCases.length > 0) {
|
|
||||||
console.log("Running " + path);
|
|
||||||
let testsFailedInSuite = 0;
|
|
||||||
const startTime = new Date().getTime();
|
|
||||||
let request = { id: this.requestIdGen++ };
|
|
||||||
request.tests = suite.testCases.map(testCase => {
|
|
||||||
const result = {
|
|
||||||
type: testCase.type,
|
|
||||||
name: testCase.name,
|
|
||||||
file: testCase.file
|
|
||||||
};
|
|
||||||
if (testCase.argument) {
|
|
||||||
result.argument = testCase.argument;
|
|
||||||
}
|
|
||||||
return result;
|
|
||||||
});
|
|
||||||
this.testsRun += suite.testCases.length;
|
|
||||||
|
|
||||||
const resultPromises = [];
|
|
||||||
|
|
||||||
this.timeout = createRefreshableTimeoutPromise(20000);
|
|
||||||
for (let i = 0; i < suite.testCases.length; ++i) {
|
|
||||||
resultPromises.push(new Promise(resolve => {
|
|
||||||
this.pendingRequests[request.id + "-" + i] = resolve;
|
|
||||||
}));
|
|
||||||
}
|
|
||||||
|
|
||||||
this.ws.send(JSON.stringify(request));
|
|
||||||
const result = await Promise.race([Promise.all(resultPromises), this.timeout.promise]);
|
|
||||||
|
|
||||||
for (let i = 0; i < suite.testCases.length; i++) {
|
|
||||||
const testCase = suite.testCases[i];
|
|
||||||
const testResult = result[i];
|
|
||||||
switch (testResult.status) {
|
|
||||||
case "OK":
|
|
||||||
break;
|
|
||||||
case "failed":
|
|
||||||
this.logFailure(path, testCase, testResult.errorMessage);
|
|
||||||
testsFailedInSuite++;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
const endTime = new Date().getTime();
|
|
||||||
const percentComplete = (this.testsRun / totalTests * 100).toFixed(1);
|
|
||||||
console.log("Tests run: " + suite.testCases.length + ", failed: " + testsFailedInSuite
|
|
||||||
+ ", elapsed: " + ((endTime - startTime) / 1000) + " seconds "
|
|
||||||
+ "(" + percentComplete + "% complete)");
|
|
||||||
console.log();
|
|
||||||
}
|
|
||||||
|
|
||||||
for (const childSuite of suite.testSuites) {
|
|
||||||
await this.runTests(childSuite, path + "/" + childSuite.name, depth + 1);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
logFailure(path, testCase, message) {
|
|
||||||
console.log(" " + testCase.name + " failure (" + (this.testsFailed.length + 1) + ")");
|
|
||||||
this.testsFailed.push({
|
|
||||||
path: path + "/" + testCase.name,
|
|
||||||
message: message
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
async runTeaVMTest(testCase) {
|
|
||||||
await this.page.reload();
|
|
||||||
|
|
||||||
const fileContents = await Promise.all(testCase.files.map(async (file) => {
|
|
||||||
return fs.readFile(file, 'utf8');
|
|
||||||
}));
|
|
||||||
for (let i = 0; i < testCase.files.length; i++) {
|
|
||||||
const fileName = testCase.files[i];
|
|
||||||
const contents = fileContents[i];
|
|
||||||
const { scriptId } = await this.runtime.compileScript({
|
|
||||||
expression: contents,
|
|
||||||
sourceURL: fileName,
|
|
||||||
persistScript: true
|
|
||||||
});
|
|
||||||
TestRunner.checkScriptResult(await this.runtime.runScript({ scriptId : scriptId }), fileName);
|
|
||||||
}
|
|
||||||
|
|
||||||
const { scriptId: runScriptId } = await this.runtime.compileScript({
|
|
||||||
expression: "(" + runTeaVM.toString() + ")()",
|
|
||||||
sourceURL: " ",
|
|
||||||
persistScript: true
|
|
||||||
});
|
|
||||||
const result = TestRunner.checkScriptResult(await this.runtime.runScript({
|
|
||||||
scriptId: runScriptId,
|
|
||||||
awaitPromise: true,
|
|
||||||
returnByValue: true
|
|
||||||
}));
|
|
||||||
|
|
||||||
return result.result.value;
|
|
||||||
}
|
|
||||||
|
|
||||||
static checkScriptResult(scriptResult, scriptUrl) {
|
|
||||||
if (scriptResult.result.subtype === "error") {
|
|
||||||
throw new Error("Exception caught from script " + scriptUrl + ":\n" + scriptResult.result.description);
|
|
||||||
}
|
|
||||||
return scriptResult;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
function runTeaVM() {
|
|
||||||
return new Promise(resolve => {
|
|
||||||
main([], result => {
|
|
||||||
const message = {};
|
|
||||||
if (result instanceof Error) {
|
|
||||||
makeErrorMessage(message, result);
|
|
||||||
} else {
|
|
||||||
message.status = "OK";
|
|
||||||
}
|
|
||||||
resolve(message);
|
|
||||||
});
|
|
||||||
|
|
||||||
function makeErrorMessage(message, e) {
|
|
||||||
message.status = "failed";
|
|
||||||
var je = main.javaException(e);
|
|
||||||
if (je) {
|
|
||||||
message.className = je.constructor.name;
|
|
||||||
message.message = je.getMessage();
|
|
||||||
} else {
|
|
||||||
message.className = Object.getPrototypeOf(e).name;
|
|
||||||
message.message = e.message;
|
|
||||||
}
|
|
||||||
message.exception = e;
|
|
||||||
message.stack = e.stack;
|
|
||||||
}
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
function createRefreshableTimeoutPromise(timeout) {
|
|
||||||
const obj = {
|
|
||||||
currentId: 0,
|
|
||||||
resolveFun: () => {},
|
|
||||||
refresh: () => {
|
|
||||||
const expectedId = ++obj.currentId;
|
|
||||||
setTimeout(() => {
|
|
||||||
if (expectedId === obj.currentId) {
|
|
||||||
obj.resolveFun(new Error("Connection timeout"))
|
|
||||||
}
|
|
||||||
}, timeout);
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
const result = {
|
|
||||||
promise: new Promise((_, reject) => {
|
|
||||||
obj.resolveFun = reject;
|
|
||||||
}),
|
|
||||||
refresh: () => obj.refresh()
|
|
||||||
};
|
|
||||||
obj.refresh();
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
|
|
||||||
runAll().catch(e => {
|
|
||||||
console.log(e.stack);
|
|
||||||
process.exit(1);
|
|
||||||
});
|
|
|
@ -1,95 +0,0 @@
|
||||||
/*
|
|
||||||
* Copyright 2019 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.
|
|
||||||
*/
|
|
||||||
|
|
||||||
"use strict";
|
|
||||||
|
|
||||||
import { CDP } from "./cdp.js";
|
|
||||||
|
|
||||||
function waitForTest(cdp) {
|
|
||||||
return new Promise(resolve => {
|
|
||||||
let stage = 'initial';
|
|
||||||
let requestId = null;
|
|
||||||
cdp.on("Runtime.consoleAPICalled", event => {
|
|
||||||
const value = event.args.filter(arg => arg.type === "string").map(arg => arg.value).join("");
|
|
||||||
switch (stage) {
|
|
||||||
case 'initial':
|
|
||||||
if (value === 'Connection established') {
|
|
||||||
stage = 'connected';
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
case 'connected': {
|
|
||||||
const result = /Request #([0-9]+) received/.exec(value);
|
|
||||||
if (result) {
|
|
||||||
requestId = result[1];
|
|
||||||
stage = 'sent';
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
case 'sent':
|
|
||||||
if (value === "Running test only simple consisting of http://localhost:9090//only/test.js") {
|
|
||||||
stage = 'ran';
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
case 'ran':
|
|
||||||
if (value === "Sending response #" + requestId) {
|
|
||||||
stage = 'received';
|
|
||||||
resolve();
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
});
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
function timeout(time) {
|
|
||||||
let timer;
|
|
||||||
return {
|
|
||||||
promise: new Promise((resolve, reject) => {
|
|
||||||
timer = setTimeout(() => { reject(new Error("Timeout expired")); }, time);
|
|
||||||
}),
|
|
||||||
cancel: () => clearTimeout(timer)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
async function run() {
|
|
||||||
const wsConn = await CDP.connect("http://localhost:9222");
|
|
||||||
const cdp = new CDP(wsConn);
|
|
||||||
cdp.on("Runtime.consoleAPICalled", event => {
|
|
||||||
const value = event.args.filter(arg => arg.type === "string").map(arg => arg.value).join("");
|
|
||||||
if (value !== "") {
|
|
||||||
console.log("[LOG] " + new Date(event.timestamp) + ": " + value);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
const wait = waitForTest(cdp);
|
|
||||||
let timer;
|
|
||||||
cdp.start();
|
|
||||||
|
|
||||||
try {
|
|
||||||
await cdp.call("Runtime.enable");
|
|
||||||
timer = timeout(10000);
|
|
||||||
await Promise.race([wait, timer.promise]);
|
|
||||||
} finally {
|
|
||||||
if (timer) {
|
|
||||||
timer.cancel();
|
|
||||||
}
|
|
||||||
wsConn.close();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
run().catch(e => {
|
|
||||||
console.error("Error", e);
|
|
||||||
});
|
|
|
@ -1,20 +0,0 @@
|
||||||
/*
|
|
||||||
* Copyright 2017 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.
|
|
||||||
*/
|
|
||||||
|
|
||||||
require("babel-core/register");
|
|
||||||
require("babel-polyfill");
|
|
||||||
|
|
||||||
require("./bin/run-tests");
|
|
|
@ -1,19 +0,0 @@
|
||||||
/*
|
|
||||||
* Copyright 2019 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.
|
|
||||||
*/
|
|
||||||
|
|
||||||
function main(args, callback) {
|
|
||||||
callback();
|
|
||||||
}
|
|
|
@ -1,18 +0,0 @@
|
||||||
/*
|
|
||||||
* Copyright 2017 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.
|
|
||||||
*/
|
|
||||||
|
|
||||||
user_pref("browser.dom.window.dump.enabled", true);
|
|
||||||
user_pref("browser.shell.checkDefaultBrowser", false);
|
|
Loading…
Reference in New Issue
Block a user