mirror of
https://github.com/Eaglercraft-TeaVM-Fork/eagler-teavm.git
synced 2024-12-22 08:14:09 -08:00
JS: allow running tests in multiple browser tabs
This commit is contained in:
parent
4ab706f128
commit
fb81153ad2
|
@ -30,13 +30,13 @@ import java.io.Reader;
|
|||
import java.io.StringReader;
|
||||
import java.nio.charset.StandardCharsets;
|
||||
import java.util.Map;
|
||||
import java.util.concurrent.BlockingQueue;
|
||||
import java.util.concurrent.ConcurrentHashMap;
|
||||
import java.util.concurrent.ConcurrentMap;
|
||||
import java.util.concurrent.CountDownLatch;
|
||||
import java.util.concurrent.LinkedBlockingQueue;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
import java.util.concurrent.atomic.AtomicBoolean;
|
||||
import java.util.concurrent.atomic.AtomicInteger;
|
||||
import java.util.concurrent.atomic.AtomicReference;
|
||||
import java.util.function.Function;
|
||||
import javax.servlet.ServletConfig;
|
||||
import javax.servlet.ServletException;
|
||||
|
@ -62,9 +62,8 @@ public class BrowserRunStrategy implements TestRunStrategy {
|
|||
private Server server;
|
||||
private int port;
|
||||
private AtomicInteger idGenerator = new AtomicInteger(0);
|
||||
private AtomicReference<Session> wsSession = new AtomicReference<>();
|
||||
private CountDownLatch wsSessionReady = new CountDownLatch(1);
|
||||
private ConcurrentMap<Integer, TestRunCallback> awaitingRuns = new ConcurrentHashMap<>();
|
||||
private BlockingQueue<Session> wsSessionQueue = new LinkedBlockingQueue<>();
|
||||
private ConcurrentMap<Integer, CallbackWrapper> awaitingRuns = new ConcurrentHashMap<>();
|
||||
private ObjectMapper objectMapper = new ObjectMapper();
|
||||
|
||||
public BrowserRunStrategy(File baseDir, String type, Function<String, Process> browserRunner) {
|
||||
|
@ -122,36 +121,57 @@ public class BrowserRunStrategy implements TestRunStrategy {
|
|||
public void afterThread() {
|
||||
}
|
||||
|
||||
static class CallbackWrapper implements TestRunCallback {
|
||||
private final CountDownLatch latch;
|
||||
private final TestRun run;
|
||||
volatile boolean shouldRepeat;
|
||||
|
||||
CallbackWrapper(CountDownLatch latch, TestRun run) {
|
||||
this.latch = latch;
|
||||
this.run = run;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void complete() {
|
||||
latch.countDown();
|
||||
run.getCallback().complete();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void error(Throwable e) {
|
||||
latch.countDown();
|
||||
run.getCallback().error(e);
|
||||
}
|
||||
|
||||
void repeat() {
|
||||
latch.countDown();
|
||||
shouldRepeat = true;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void runTest(TestRun run) throws IOException {
|
||||
while (!runTestOnce(run)) {
|
||||
// repeat
|
||||
}
|
||||
}
|
||||
|
||||
private boolean runTestOnce(TestRun run) {
|
||||
Session ws;
|
||||
try {
|
||||
while (!wsSessionReady.await(1L, TimeUnit.SECONDS)) {
|
||||
// keep waiting
|
||||
}
|
||||
do {
|
||||
ws = wsSessionQueue.poll(1, TimeUnit.SECONDS);
|
||||
} while (ws == null || !ws.isOpen());
|
||||
} catch (InterruptedException e) {
|
||||
run.getCallback().error(e);
|
||||
return;
|
||||
return true;
|
||||
}
|
||||
|
||||
Session ws = wsSession.get();
|
||||
if (ws == null) {
|
||||
return;
|
||||
}
|
||||
int id = idGenerator.incrementAndGet();
|
||||
CountDownLatch latch = new CountDownLatch(1);
|
||||
awaitingRuns.put(id, new TestRunCallback() {
|
||||
@Override
|
||||
public void complete() {
|
||||
latch.countDown();
|
||||
run.getCallback().complete();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void error(Throwable e) {
|
||||
latch.countDown();
|
||||
run.getCallback().error(e);
|
||||
}
|
||||
});
|
||||
CallbackWrapper callbackWrapper = new CallbackWrapper(latch, run);
|
||||
awaitingRuns.put(id, callbackWrapper);
|
||||
|
||||
JsonNodeFactory nf = objectMapper.getNodeFactory();
|
||||
ObjectNode node = nf.objectNode();
|
||||
|
@ -179,6 +199,12 @@ public class BrowserRunStrategy implements TestRunStrategy {
|
|||
} catch (InterruptedException e) {
|
||||
// do nothing
|
||||
}
|
||||
|
||||
if (ws.isOpen()) {
|
||||
wsSessionQueue.offer(ws);
|
||||
}
|
||||
|
||||
return !callbackWrapper.shouldRepeat;
|
||||
}
|
||||
|
||||
class TestCodeServlet extends HttpServlet {
|
||||
|
@ -295,34 +321,20 @@ public class BrowserRunStrategy implements TestRunStrategy {
|
|||
}
|
||||
|
||||
class TestCodeSocket extends WebSocketAdapter {
|
||||
private AtomicBoolean ready = new AtomicBoolean(false);
|
||||
|
||||
@Override
|
||||
public void onWebSocketConnect(Session sess) {
|
||||
if (wsSession.compareAndSet(null, sess)) {
|
||||
ready.set(true);
|
||||
wsSessionReady.countDown();
|
||||
} else {
|
||||
System.err.println("Link opened in multiple browsers");
|
||||
}
|
||||
wsSessionQueue.offer(sess);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onWebSocketClose(int statusCode, String reason) {
|
||||
if (ready.get()) {
|
||||
System.err.println("Browser has disconnected");
|
||||
for (TestRunCallback run : awaitingRuns.values()) {
|
||||
run.error(new RuntimeException("Browser disconnected unexpectedly"));
|
||||
}
|
||||
for (CallbackWrapper run : awaitingRuns.values()) {
|
||||
run.repeat();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onWebSocketText(String message) {
|
||||
if (!ready.get()) {
|
||||
return;
|
||||
}
|
||||
|
||||
JsonNode node;
|
||||
try {
|
||||
node = objectMapper.readTree(new StringReader(message));
|
||||
|
|
|
@ -43,6 +43,7 @@ import java.util.concurrent.CountDownLatch;
|
|||
import java.util.concurrent.ScheduledFuture;
|
||||
import java.util.concurrent.ScheduledThreadPoolExecutor;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
import java.util.function.BiConsumer;
|
||||
import java.util.function.Consumer;
|
||||
import java.util.function.Supplier;
|
||||
import java.util.stream.Stream;
|
||||
|
@ -196,63 +197,50 @@ public class TeaVMTestRunner extends Runner implements Filterable {
|
|||
}
|
||||
|
||||
private Process chromeBrowser(String url) {
|
||||
File temp;
|
||||
try {
|
||||
temp = File.createTempFile("teavm", "teavm");
|
||||
temp.delete();
|
||||
temp.mkdirs();
|
||||
Runtime.getRuntime().addShutdownHook(new Thread(() -> {
|
||||
deleteDir(temp);
|
||||
}));
|
||||
System.out.println("Running chrome with user data dir: " + temp.getAbsolutePath());
|
||||
ProcessBuilder pb = new ProcessBuilder(
|
||||
return browserTemplate("chrome", url, (profile, params) -> {
|
||||
params.addAll(Arrays.asList(
|
||||
"google-chrome-stable",
|
||||
"--headless",
|
||||
"--disable-gpu",
|
||||
"--remote-debugging-port=9222",
|
||||
"--no-first-run",
|
||||
"--user-data-dir=" + temp.getAbsolutePath(),
|
||||
url
|
||||
);
|
||||
Process process = pb.start();
|
||||
logStream(process.getInputStream(), "Chrome stdout");
|
||||
logStream(process.getErrorStream(), "Chrome stderr");
|
||||
new Thread(() -> {
|
||||
try {
|
||||
System.out.println("Chrome process terminated with code: " + process.waitFor());
|
||||
} catch (InterruptedException e) {
|
||||
// ignore
|
||||
}
|
||||
});
|
||||
return process;
|
||||
} catch (IOException e) {
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
"--user-data-dir=" + profile
|
||||
));
|
||||
});
|
||||
}
|
||||
|
||||
private Process firefoxBrowser(String url) {
|
||||
return browserTemplate("firefox", url, (profile, params) -> {
|
||||
params.addAll(Arrays.asList(
|
||||
"firefox",
|
||||
"--headless",
|
||||
"--profile",
|
||||
profile
|
||||
));
|
||||
});
|
||||
}
|
||||
|
||||
private Process browserTemplate(String name, String url, BiConsumer<String, List<String>> paramsBuilder) {
|
||||
File temp;
|
||||
try {
|
||||
temp = File.createTempFile("teavm", "teavm");
|
||||
temp.delete();
|
||||
temp.mkdirs();
|
||||
Runtime.getRuntime().addShutdownHook(new Thread(() -> {
|
||||
deleteDir(temp);
|
||||
}));
|
||||
System.out.println("Running firefox with user data dir: " + temp.getAbsolutePath());
|
||||
ProcessBuilder pb = new ProcessBuilder(
|
||||
"firefox",
|
||||
"--headless",
|
||||
"--profile",
|
||||
temp.getAbsolutePath(),
|
||||
url
|
||||
);
|
||||
Runtime.getRuntime().addShutdownHook(new Thread(() -> deleteDir(temp)));
|
||||
System.out.println("Running " + name + " with user data dir: " + temp.getAbsolutePath());
|
||||
List<String> params = new ArrayList<>();
|
||||
paramsBuilder.accept(temp.getAbsolutePath(), params);
|
||||
int tabs = Integer.parseInt(System.getProperty(THREAD_COUNT, "1"));
|
||||
for (int i = 0; i < tabs; ++i) {
|
||||
params.add(url);
|
||||
}
|
||||
ProcessBuilder pb = new ProcessBuilder(params.toArray(new String[0]));
|
||||
Process process = pb.start();
|
||||
logStream(process.getInputStream(), "Firefox stdout");
|
||||
logStream(process.getErrorStream(), "Firefox stderr");
|
||||
logStream(process.getInputStream(), name + " stdout");
|
||||
logStream(process.getErrorStream(), name + " stderr");
|
||||
new Thread(() -> {
|
||||
try {
|
||||
System.out.println("Firefox process terminated with code: " + process.waitFor());
|
||||
System.out.println(name + " process terminated with code: " + process.waitFor());
|
||||
} catch (InterruptedException e) {
|
||||
// ignore
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue
Block a user