// Create and stop test servers. // // Usage: // s = new Server(name, config) // s.verbose() : optional // .start() // 'started' // // s.stop() : stops server is started. // 'stopped' // // Provide servers // // Servers are created in tmp/server/$server // var buster = require("buster"); var child = require("child_process"); var fs = require("fs"); var path = require("path"); var util = require("util"); var EventEmitter = require('events').EventEmitter; var config = require("./config"); var nodeutils = require("./nodeutils"); // Create a server object var Server = function (name, config, verbose) { this.name = name; this.config = config; this.started = false; this.quiet = !verbose; this.stopping = false; var nodejs_version = process.version.match(/^v(\d+)+\.(\d+)\.(\d+)$/).slice(1,4); var wanted_version = [ 0, 8, 18 ]; while (wanted_version.length && nodejs_version.length && nodejs_version[0] == wanted_version[0]) { nodejs_version.shift(); wanted_version.shift(); } var sgn = !nodejs_version.length && !wanted_version.length ? 0 : nodejs_version.length ? nodejs_version[0] - wanted_version[0] : -1; if (sgn < 0) { console.log("\n*** Node.js version is too low."); throw "Nodejs version is too low."; } }; util.inherits(Server, EventEmitter); Server.from_config = function (name, verbose) { return new Server(name, config.servers[name], verbose); }; Server.prototype.on = function (e, c) { EventEmitter.prototype.on.call(this, e, c); return this; }; Server.prototype.once = function (e, c) { EventEmitter.prototype.once.call(this, e, c); return this; }; Server.prototype.serverPath = function() { return path.resolve("tmp/server", this.name); }; Server.prototype.configPath = function() { return path.join(this.serverPath(), "rippled.cfg"); }; // Write a server's rippled.cfg. Server.prototype._writeConfig = function(done) { var self = this; fs.writeFile( this.configPath(), Object.keys(this.config).map(function(o) { return util.format("[%s]\n%s\n", o, self.config[o]); }).join(""), 'utf8', done); }; // Spawn the server. Server.prototype._serverSpawnSync = function() { var self = this; var args = [ "-a", "-v", "--conf=rippled.cfg" ]; // Spawn in standalone mode for now. this.child = child.spawn( config.rippled, args, { cwd: this.serverPath(), env: process.env, stdio: this.quiet ? 'ignore' : 'inherit' }); if (!this.quiet) console.log("server: start %s: %s --conf=%s", this.child.pid, config.rippled, args.join(" "), this.configPath()); // By default, just log exits. this.child.on('exit', function(code, signal) { if (!self.quiet) console.log("server: spawn: server exited code=%s: signal=%s", code, signal); self.emit('exited'); // Workaround for // https://github.com/busterjs/buster/issues/266 if (!self.stopping) { buster.assertions.throwOnFailure = true; } // If could not exec: code=127, signal=null // If regular exit: code=0, signal=null // Fail the test if the server has not called "stop". buster.assert(self.stopping, 'Server died with signal '+signal); }); }; // Prepare server's working directory. Server.prototype._makeBase = function (done) { var path = this.serverPath(); var self = this; // Reset the server directory, build it if needed. nodeutils.resetPath(path, '0777', function (e) { if (e) { throw e; } else { self._writeConfig(done); } }); }; Server.prototype.verbose = function () { this.quiet = false; return this; }; // Create a standalone server. // Prepare the working directory and spawn the server. Server.prototype.start = function () { var self = this; if (!this.quiet) console.log("server: start: %s: %s", this.name, JSON.stringify(this.config)); this._makeBase(function (e) { if (e) { throw e; } else { self._serverSpawnSync(); self.emit('started'); } }); return this; }; // Stop a standalone server. Server.prototype.stop = function () { var self = this; self.stopping = true; if (this.child) { // Update the on exit to invoke done. this.child.on('exit', function (code, signal) { if (!self.quiet) console.log("server: stop: server exited"); self.emit('stopped'); delete self.child; }); this.child.kill(); } else { buster.log("server: stop: can't stop"); } return this; }; exports.Server = Server; // vim:sw=2:sts=2:ts=8:et