Improved Docker for Mac support (#568)

* Exit cleanly after invalid screenshot test name

This avoids waiting forever.

* Auto-detect host IP in Docker for Mac environment

This checks all available network addresses to find one which the Selenium
container can connect to.  That way we don't have to analyze network
settings or similar to figure out the main public IP address of the machine.

* Make server less sensitive to current working directory

That way it becomes possible to run screenshotter.js from within the
Screenshotter directory, and still server all files as intended.
This commit is contained in:
Martin von Gagern 2016-11-28 00:57:53 +01:00 committed by Kevin Barabash
parent 94dad8029d
commit be96695586
2 changed files with 98 additions and 29 deletions

View File

@ -6,6 +6,7 @@ var fs = require("fs");
var http = require("http");
var jspngopt = require("jspngopt");
var net = require("net");
var os = require("os");
var pako = require("pako");
var path = require("path");
var selenium = require("selenium-webdriver");
@ -130,12 +131,21 @@ function guessDockerIPs() {
process.exit(2);
}
katexIP = katexIP || config[1];
return;
} catch (e) {
var ip = cmd("docker", "inspect",
"-f", "{{.NetworkSettings.Gateway}}", opts.container);
seleniumIP = seleniumIP || ip;
katexIP = katexIP || ip;
// Apparently no boot2docker, continue
}
if (!process.env.DOCKER_HOST && os.type() === "Darwin") {
// Docker for Mac
seleniumIP = seleniumIP || "localhost";
katexIP = katexIP || "*any*"; // see findHostIP
return;
}
// Native Docker on Linux or remote Docker daemon or similar
var gatewayIP = cmd("docker", "inspect",
"-f", "{{.NetworkSettings.Gateway}}", opts.container);
seleniumIP = seleniumIP || gatewayIP;
katexIP = katexIP || gatewayIP;
}
if (!seleniumURL && opts.container) {
@ -192,13 +202,6 @@ function startServer() {
// Wait for container to become ready
function tryConnect() {
if (!katexIP) {
katexIP = "localhost";
}
if (!katexURL) {
katexURL = "http://" + katexIP + ":" + katexPort + "/";
console.log("KaTeX URL is " + katexURL);
}
if (!seleniumIP) {
process.nextTick(buildDriver);
return;
@ -253,7 +256,7 @@ function setSize(reqW, reqH) {
var actualW = img.width;
var actualH = img.height;
if (actualW === targetW && actualH === targetH) {
process.nextTick(takeScreenshots);
findHostIP();
return;
}
if (++attempts > 5) {
@ -272,6 +275,64 @@ function imageDimensions(img) {
};
}
//////////////////////////////////////////////////////////////////////
// Work out how to connect to host KaTeX server
function findHostIP() {
if (!katexIP) {
katexIP = "localhost";
}
if (katexIP !== "*any*" || katexURL) {
if (!katexURL) {
katexURL = "http://" + katexIP + ":" + katexPort + "/";
console.log("KaTeX URL is " + katexURL);
}
process.nextTick(takeScreenshots);
return;
}
// Now we need to find an IP the container can connect to.
// First, install a server component to get notified of successful connects
app.get("/ss-connect.js", function(req, res, next) {
if (!katexURL) {
katexIP = req.query.ip;
katexURL = "http://" + katexIP + ":" + katexPort + "/";
console.log("KaTeX URL is " + katexURL);
process.nextTick(takeScreenshots);
}
res.setHeader("Content-Type", "text/javascript");
res.send("//OK");
});
// Next, enumerate all network addresses
var ips = [];
var devs = os.networkInterfaces();
for (var dev in devs) {
if (devs.hasOwnProperty(dev)) {
var addrs = devs[dev];
for (var i = 0; i < addrs.length; ++i) {
var addr = addrs[i].address;
if (/:/.test(addr)) {
addr = "[" + addr + "]";
}
ips.push(addr);
}
}
}
console.log("Looking for host IP among " + ips.join(", "));
// Load a data: URI document which attempts to contact each of these IPs
var html = "<!doctype html>\n<html><body>\n";
html += ips.map(function(ip) {
return '<script src="http://' + ip + ':' + katexPort +
'/ss-connect.js?ip=' + encodeURIComponent(ip) +
'" defer></script>';
}).join("\n");
html += "\n</body></html>";
html = "data:text/html," + encodeURIComponent(html);
driver.get(html);
}
//////////////////////////////////////////////////////////////////////
// Take the screenshots
@ -288,6 +349,11 @@ function takeScreenshot(key) {
var itm = data[key];
if (!itm) {
console.error("Test case " + key + " not known!");
listOfFailed.push(key);
if (exitStatus === 0) {
exitStatus = 1;
}
oneDone();
return;
}
@ -303,15 +369,7 @@ function takeScreenshot(key) {
if (opts.wait) {
browserSideWait(1000 * opts.wait);
}
driver.takeScreenshot().then(haveScreenshot).then(function() {
if (--countdown === 0) {
if (listOfFailed.length) {
console.error("Failed: " + listOfFailed.join(" "));
}
// devServer.close(cb) will take too long.
process.exit(exitStatus);
}
}, check);
driver.takeScreenshot().then(haveScreenshot).then(oneDone, check);
function haveScreenshot(img) {
img = imageDimensions(img);
@ -360,6 +418,16 @@ function takeScreenshot(key) {
});
}
}
function oneDone() {
if (--countdown === 0) {
if (listOfFailed.length) {
console.error("Failed: " + listOfFailed.join(" "));
}
// devServer.close(cb) will take too long.
process.exit(exitStatus);
}
}
}
// Wait using a timeout call in the browser, to ensure that the wait

View File

@ -17,11 +17,11 @@ var serveBrowserified = function(file, standaloneName) {
return function(req, res, next) {
var files;
if (Array.isArray(file)) {
files = file;
files = file.map(function(f) { return path.join(__dirname, f); });
} else if (file.indexOf("*") !== -1) {
files = glob.sync(file);
files = glob.sync(file, {cwd: __dirname});
} else {
files = [file];
files = [path.join(__dirname, file)];
}
var options = {};
@ -41,7 +41,7 @@ var serveBrowserified = function(file, standaloneName) {
};
};
app.get("/katex.js", serveBrowserified("./katex", "katex"));
app.get("/katex.js", serveBrowserified("katex", "katex"));
app.use("/test/jasmine",
express["static"](
path.dirname(
@ -49,20 +49,21 @@ app.use("/test/jasmine",
)
)
);
app.get("/test/katex-spec.js", serveBrowserified("./test/*[Ss]pec.js"));
app.get("/test/katex-spec.js", serveBrowserified("test/*[Ss]pec.js"));
app.get("/contrib/auto-render/auto-render.js",
serveBrowserified("./contrib/auto-render/auto-render",
serveBrowserified("contrib/auto-render/auto-render",
"renderMathInElement"));
app.get("/katex.css", function(req, res, next) {
fs.readFile("static/katex.less", {encoding: "utf8"}, function(err, data) {
var lessfile = path.join(__dirname, "static", "katex.less");
fs.readFile(lessfile, {encoding: "utf8"}, function(err, data) {
if (err) {
next(err);
return;
}
less.render(data, {
paths: ["./static"],
paths: [path.join(__dirname, "static")],
filename: "katex.less",
}, function(err, output) {
if (err) {