UNPKG

kinto-node-test-server

Version:

A node API for operating a Kinto test server.

133 lines (132 loc) 5.1 kB
"use strict"; var __importDefault = (this && this.__importDefault) || function (mod) { return (mod && mod.__esModule) ? mod : { "default": mod }; }; Object.defineProperty(exports, "__esModule", { value: true }); const node_fetch_1 = __importDefault(require("node-fetch")); const child_process_1 = require("child_process"); const path_1 = __importDefault(require("path")); const server_1 = __importDefault(require("./server")); exports.KintoProxyServer = server_1.default; const DEFAULT_OPTIONS = { maxAttempts: 50, kintoConfigPath: path_1.default.resolve(path_1.default.join(__dirname, "../kinto.ini")), pservePath: process.env.KINTO_PSERVE_EXECUTABLE || "pserve", }; function copyExisting(obj, keys) { const ret = {}; for (const key of keys) { if (obj.hasOwnProperty(key)) { ret[key] = obj[key]; } } return ret; } function checkForPserve(pservePath) { try { child_process_1.execSync(`${pservePath} --help`, { stdio: "ignore" }); } catch (err) { throw new Error(pservePath === "pserve" ? "Unable to find pserve in PATH. Have you installed kinto or activated your virtualenv?" : `Unable to find or execute ${pservePath}.`); } } class KintoServer { constructor(url, options = {}) { this.url = url; this.process = null; this._logs = []; this.http_api_version = null; this.options = Object.assign({}, DEFAULT_OPTIONS, options); } async _retryRequest(url, options, attempt = 1) { const { maxAttempts } = this.options; try { const res = await node_fetch_1.default(url, options); if ([200, 202, 410].indexOf(res.status) === -1) { throw new Error("Unable to start server, HTTP " + res.status); } return res; } catch (err) { if (maxAttempts && attempt < maxAttempts) { return new Promise((resolve) => { setTimeout(() => { resolve(this._retryRequest(url, options, attempt + 1)); }, 100); }); } throw new Error(`Max attempts number reached (${maxAttempts}); ${err}`); } } async loadConfig(pathToConfig) { this.options.kintoConfigPath = pathToConfig; } start(env) { if (this.process) { throw new Error("Server is already started."); } // Keeping parent's environment is needed so that pserve's executable // can be found (with PATH) if KINTO_PSERVE_EXECUTABLE env variable was // not provided. // However, Kinto's config parsing logic tries to interpolate any // %-code in any environment variable, so rather than polluting // the environment with everything, just copy the variables we // think will be necessary. const sanitizedEnv = copyExisting(process.env, [ "PATH", "VIRTUAL_ENV", "PYTHONPATH", ]); // Add the provided environment variables to the child process environment. env = Object.assign({}, sanitizedEnv, env); checkForPserve(this.options.pservePath); this.process = child_process_1.spawn(this.options.pservePath, [this.options.kintoConfigPath], { env, detached: true }); this.process.stderr.on("data", (data) => { this._logs.push(data); }); this.process.on("close", (code) => { if (code && code > 0) { console.error(new Error("Server errors encountered:\n" + this._logs.map((line) => line.toString()).join(""))); console.error(new Error().stack); } }); return this.ping(); } async ping() { const endpoint = `${this.url}/`; const res = await this._retryRequest(endpoint, {}, 1); const json = await res.json(); this.http_api_version = json.http_api_version; return this.http_api_version; } async flush() { const endpoint = `${this.url}/__flush__`; const res = await this._retryRequest(endpoint, { method: "POST" }, 1); return { status: res.status }; } stop() { if (this.process) this.process.kill(); this.process = null; return new Promise((resolve) => { setTimeout(() => resolve(), 500); }); } killAll() { return new Promise((resolve) => { if (process.platform === "win32") { child_process_1.spawn("taskkill", ["/im", "pserve.exe"]).on("close", () => resolve()); } else { child_process_1.spawn("killall", ["pserve"]).on("close", () => resolve()); } }); } logs() { return Promise.resolve(this._logs.map((line) => line.toString()).join("")); } } exports.default = KintoServer;