From be966955865b24b48c46ce6ae6b7695742d2d29a Mon Sep 17 00:00:00 2001 From: Martin von Gagern Date: Mon, 28 Nov 2016 00:57:53 +0100 Subject: [PATCH] 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. --- dockers/Screenshotter/screenshotter.js | 110 ++++++++++++++++++++----- server.js | 17 ++-- 2 files changed, 98 insertions(+), 29 deletions(-) diff --git a/dockers/Screenshotter/screenshotter.js b/dockers/Screenshotter/screenshotter.js index 1665ec1..e49a4b2 100644 --- a/dockers/Screenshotter/screenshotter.js +++ b/dockers/Screenshotter/screenshotter.js @@ -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 = "\n\n"; + html += ips.map(function(ip) { + return ''; + }).join("\n"); + html += "\n"; + 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 diff --git a/server.js b/server.js index 08eacf1..979561f 100644 --- a/server.js +++ b/server.js @@ -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) {