Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with HTTPS or Subversion.

Download ZIP
Browse files

[refactor] Significant refactor to how forever works in the rewrite

  • Loading branch information...
commit 8f9f0adb9976d8f87948c03d6101ea43f58d0dca 1 parent 2ead453
@indexzero indexzero authored
View
1  .gitignore
@@ -3,3 +3,4 @@ node_modules/
node_modules/*
npm-debug.log
.*.sw[op]
+test/fixtures/*.log
View
23 lib/forever.js
@@ -40,6 +40,7 @@ forever.log.cli();
// Export `version` and important Prototypes from `lib/forever/*`
//
forever.initialized = false;
+forever.plugins = utile.requireDirLazy(path.join(__dirname, '/forever/plugins'));
forever.root = path.join(process.env.HOME || '/root', '.forever');
forever.config = new nconf.File({ file: path.join(forever.root, 'config.json') });
forever.Forever = forever.Monitor = require('./forever/monitor').Monitor;
@@ -98,15 +99,24 @@ function getAllProcesses(callback) {
socket.connect(fullPath, function (err) {
if (err) {
- return next(err);
+ next(err);
}
- socket.data(['data'], function (data) {
+ socket.dataOnce(['data'], function (data) {
next(null, data);
socket.end();
});
+
socket.send(['data']);
});
+
+ socket.on('error', function (err) {
+ if (err.code === 'ECONNREFUSED') {
+ fs.unlink(fullPath, function () {
+ next();
+ });
+ }
+ });
}
getSockets(sockPath, function (err, sockets) {
@@ -115,7 +125,7 @@ function getAllProcesses(callback) {
}
async.map(sockets, getProcess, function (err, processes) {
- callback(processes);
+ callback(processes.filter(Boolean));
});
});
}
@@ -331,12 +341,15 @@ forever.startServer = function () {
}
});
- async.forEach(monitors, function (monitor, next) {
+ async.map(monitors, function (monitor, next) {
var worker = new forever.Worker({
monitor: monitor,
sockPath: forever.config.get('sockPath')
});
- worker.start(next);
+
+ worker.start(function (err) {
+ return err ? next(err) : next(null, worker);
+ });
}, callback || function () {});
};
View
1  lib/forever/cli.js
@@ -11,7 +11,6 @@ var fs = require('fs'),
path = require('path'),
flatiron = require('flatiron'),
cliff = require('cliff'),
- daemon = require('daemon'),
forever = require('../forever');
var cli = exports;
View
109 lib/forever/monitor.js
@@ -6,13 +6,13 @@
*
*/
-var util = require('util'),
+var events = require('events'),
fs = require('fs'),
path = require('path'),
spawn = require('child_process').spawn,
- winston = require('winston'),
broadway = require('broadway'),
psTree = require('ps-tree'),
+ winston = require('winston'),
utile = require('utile'),
forever = require('../forever');
@@ -20,11 +20,23 @@ var util = require('util'),
// ### function Monitor (script, options)
// #### @script {string} Location of the target script to run.
// #### @options {Object} Configuration for this instance.
-// Creates a new instance of forever with specified params.
+// Creates a new instance of forever with specified `options`.
//
var Monitor = exports.Monitor = function (script, options) {
+ //
+ // Simple bootstrapper for attaching logger
+ // and watch plugins by default. Other plugins
+ // can be attached through `monitor.use(plugin, options)`.
+ //
+ function bootstrap(monitor) {
+ forever.plugins.logger.attach.call(monitor, options);
+
+ if (options.watch) {
+ forever.plugins.watch.attach.call(monitor, options);
+ }
+ }
+
var self = this;
- broadway.App.call(this);
//
// Setup basic configuration options
@@ -40,6 +52,22 @@ var Monitor = exports.Monitor = function (script, options) {
this.times = 0;
//
+ // Setup log files and logger for this instance.
+ //
+ this.logFile = options.logFile || path.join(forever.config.get('root'), this.uid + '.log');
+ this.outFile = options.outFile;
+ this.errFile = options.errFile;
+ this.logger = options.logger || new (winston.Logger)({
+ transports: [new winston.transports.Console({ silent: this.silent })]
+ });
+
+ //
+ // Extend from the winston logger.
+ //
+ this.logger.extend(this);
+ this.log = fs.createWriteStream(this.logFile, { flags: 'a+', encoding: 'utf8', mode: '0666' });
+
+ //
// Setup restart timing. These options control how quickly forever restarts
// a child process as well as when to kill a "spinning" process
//
@@ -51,15 +79,22 @@ var Monitor = exports.Monitor = function (script, options) {
// to that command.
//
this.command = options.command || 'node';
- this.options = options.options || [];
+ this.args = options.options || [];
this.spawnWith = options.spawnWith || {};
this.sourceDir = options.sourceDir;
this.cwd = options.cwd || null;
- this.env = options.env || {};
this.hideEnv = options.hideEnv || [];
+ this._env = options.env || {};
this._hideEnv = {};
//
+ // Setup watch configuration options
+ //
+ this.watchIgnoreDotFiles = options.watchIgnoreDotFiles || true;
+ this.watchIgnorePatterns = options.watchIgnorePatterns || [];
+ this.watchDirectory = options.watchDirectory || this.sourceDir;
+
+ //
// Create a simple mapping of `this.hideEnv` to an easily indexable
// object
//
@@ -67,47 +102,27 @@ var Monitor = exports.Monitor = function (script, options) {
self._hideEnv[key] = true;
});
- //
- // Setup logger for this instance.
- //
- this.logger = options.logger || new (winston.Logger)({
- transports: [new winston.transports.Console({ silent: this.silent })]
- });
-
- //
- // Extend from the winston logger.
- //
- this.logger.extend(this);
-
if (Array.isArray(script)) {
this.command = script[0];
- this.options = script.slice(1);
+ this.args = script.slice(1);
}
else {
- this.options.unshift(script);
+ this.args.unshift(script);
}
-
+
if (this.sourceDir) {
- this.options[0] = path.join(this.sourceDir, this.options[0]);
+ this.args[0] = path.join(this.sourceDir, this.args[0]);
}
-
+
//
- // Last if any hooks have been passed in attach
- // this instance to them
+ // Bootstrap this instance now that options
+ // have been set
//
- if (options.hooks && options.hooks.length > 0) {
- options.hooks.forEach(function (hook) {
- if (typeof hook === 'function') {
- return hook(self);
- }
-
- hook.attach(self);
- });
- }
+ broadway.App.call(this, { bootstrapper: { bootstrap: bootstrap } });
};
// Inherit from events.EventEmitter
-util.inherits(Monitor, broadway.App);
+utile.inherits(Monitor, broadway.App);
//
// ### function start ([restart])
@@ -128,7 +143,7 @@ Monitor.prototype.start = function (restart) {
child = this.trySpawn();
if (!child) {
process.nextTick(function () {
- self.emit('error', new Error('Target script does not exist: ' + self.options[0]));
+ self.emit('error', new Error('Target script does not exist: ' + self.args[0]));
});
return this;
}
@@ -140,7 +155,7 @@ Monitor.prototype.start = function (restart) {
process.nextTick(function () {
self.emit(restart ? 'restart' : 'start', self, self.data);
});
-
+
child.on('exit', function (code) {
var spinning = Date.now() - self.ctime < self.minUptime;
self.warn('Forever detected script exited with code: ' + code);
@@ -148,7 +163,6 @@ Monitor.prototype.start = function (restart) {
function letChildDie() {
self.running = false;
self.forceStop = false;
-
self.emit('exit', self, spinning);
}
@@ -187,7 +201,7 @@ Monitor.prototype.start = function (restart) {
Monitor.prototype.trySpawn = function () {
if (this.command === 'node' || (this.checkFile && !this.childExists)) {
try {
- var stats = fs.statSync(this.options[0]);
+ var stats = fs.statSync(this.args[0]);
this.childExists = true;
}
catch (ex) {
@@ -198,7 +212,7 @@ Monitor.prototype.trySpawn = function () {
this.spawnWith.cwd = this.cwd || this.spawnWith.cwd;
this.spawnWith.env = this._getEnv();
- return spawn(this.command, this.options, this.spawnWith);
+ return spawn(this.command, this.args, this.spawnWith);
};
//
@@ -221,10 +235,10 @@ Monitor.prototype.__defineGetter__('data', function () {
childData = {
ctime: this.ctime,
command: this.command,
- file: this.options[0],
+ file: this.args[0],
foreverPid: process.pid,
logFile: this.logFile,
- options: this.options.slice(1),
+ options: this.args.slice(1),
pid: this.child.pid,
silent: this.silent,
uid: this.uid,
@@ -320,8 +334,10 @@ Monitor.prototype.kill = function (forceStop) {
//these should be ignored, and then we should emit that it is dead
}
});
+
self.emit('stop', this.childData);
}, this.killTTL);
+
child.on('exit', function () {
clearTimeout(timer);
});
@@ -351,7 +367,7 @@ Monitor.prototype._getEnv = function () {
//
// Mixin the key:value pairs from `process.env` and the custom
- // environment variables in `this.env`.
+ // environment variables in `this._env`.
//
Object.keys(process.env).forEach(function (key) {
if (!self._hideEnv[key]) {
@@ -359,10 +375,9 @@ Monitor.prototype._getEnv = function () {
}
});
- Object.keys(this.env).forEach(function (key) {
- addKey(key, self.env);
+ Object.keys(this._env).forEach(function (key) {
+ addKey(key, self._env);
});
return merged;
-};
-
+};
View
103 lib/forever/plugins/logger.js
@@ -1,53 +1,90 @@
-var Logger = module.exports;
-Logger.name = 'logger';
+var fs = require('fs');
-Logger.attach = function (options) {
- var self = this;
+exports.name = 'logger';
- this.on('start', function () {
- startLogging('stdout');
- startLogging('stderr');
-
- function startLogging(stream) {
- self.child[stream].on('data', onData);
-
- if (options[stream]) {
- self[stream] = options[stream]
- }
+exports.attach = function (options) {
+ options = options || {};
+ var monitor = this;
+
+ // If we should log stdout, open a file buffer
+ if (this.outFile || options['stdout']) {
+ this.stdout = options['stdout'] || fs.createWriteStream(this.outFile, {
+ flags: 'a+',
+ encoding: 'utf8',
+ mode: '0666'
+ });
+ }
+
+ // If we should log stderr, open a file buffer
+ if (this.errFile || options['stderr']) {
+ this.stderr = options['stderr'] || fs.createWriteStream(this.errFile, {
+ flags: 'a+',
+ encoding: 'utf8',
+ mode: '0666'
+ });
+ }
+ function startLogging() {
+ //
+ // Helper function to log output.
+ //
+ function logStream(stream) {
+ //
+ // Logs the specified `data` to the `stream`.
+ //
function onData(data) {
- if (!self.silent && !self[stream]) {
+ try {
+ monitor.log.write(data);
+ }
+ catch (ex) {
+ console.dir(ex);
+ }
+ if (!monitor.silent && !monitor[stream]) {
//
// If we haven't been silenced, and we don't have a file stream
// to output to write to the process stdout stream
//
process[stream].write(data);
}
- else if (self[stream]) {
+ else if (monitor[stream]) {
//
// If we have been given an output file for the stream, write to it
//
- self[stream].write(data);
+ monitor[stream].write(data);
}
+
+ monitor.emit(stream, data);
}
-
- function stopLogging() {
- if (self[stream] && !options[stream]) {
- //
- // Close the stream only if it wasn't provided in `options`. If it was,
- // caller is responsible for closing it.
- //
- self[stream].close();
- }
- };
-
- self.on('exit', stopLogging);
+
+ monitor.child[stream].on('data', onData);
+ monitor.child.once('exit', function () {
+ monitor.child[stream].removeListener('data', logStream);
+ });
}
- });
-};
+
+ logStream('stdout');
+ logStream('stderr');
+ }
+
+ function stopLogging() {
+ function closeStream(stream) {
+ if (monitor[stream]) {
+ //
+ // Close the stream only if it wasn't provided in `options`. If it was,
+ // caller is responsible for closing it.
+ //
+ monitor[stream].end();
+ }
+ }
+
+ closeStream('stdout');
+ closeStream('stderr');
+ monitor.log.end();
+ }
-Logger.init = function (done) {
- done();
+ this.on('start', startLogging);
+ this.on('restart', startLogging);
+ this.on('exit', stopLogging);
};
View
55 lib/forever/plugins/watch.js
@@ -0,0 +1,55 @@
+
+var fs = require('fs'),
+ path = require('path'),
+ minimatch = require('minimatch'),
+ watch = require('watch');
+
+exports.name = 'watch';
+
+//
+// ### @private function _watchFilter
+// #### @file {string} File name
+// Determines whether we should restart if `file` change (@mikeal's filtering
+// is pretty messed up).
+//
+function watchFilter(fileName) {
+ if (this.watchIgnoreDotFiles && path.basename(fileName)[0] === '.') {
+ return false;
+ }
+
+ for (var key in this.watchIgnorePatterns) {
+ if (minimatch(fileName, this.watchIgnorePatterns[key], { matchBase: this.watchDirectory })) {
+ return false;
+ }
+ }
+
+ return true;
+};
+
+exports.attach = function () {
+ var monitor = this;
+
+ fs.readFile(path.join(this.watchDirectory, '.foreverignore'), 'utf8', function (err, data) {
+ if (err) {
+ forever.log.warn('Could not read .foreverignore file.');
+ return forever.log.silly(err.message);
+ }
+
+ Array.prototype.push.apply(monitor.watchIgnorePatterns, data.split('\n'));
+ });
+
+ watch.watchTree(this.watchDirectory, function (f, curr, prev) {
+ if (!(curr === null && prev === null && typeof f === 'object')) {
+ //
+ // `curr` == null && `prev` == null && typeof f == "object" when watch
+ // finishes walking the tree to add listeners. We don't need to know
+ // about it, so we simply ignore it (anything different means that
+ // some file changed/was removed/created - that's what we want to know).
+ //
+ if (watchFilter.call(monitor, f)) {
+ forever.log.info('restaring script because ' + f + ' changed');
+ monitor.restart();
+ }
+ }
+ });
+};
View
8 lib/forever/service/adapters/adapter.js
@@ -12,15 +12,15 @@ var Adapter = module.exports = function Adapter(service) {
//
// This should install assets to appropriate places for initialization,
-// configuration, and storage
+// configuration, and storage
//
// The script will be used on startup to load Service
//
// Service should listen on something that the management events
-// can respond to in full duplex
+// can respond to in full duplex
//
-// The installed adapter should send the following events in dnode protocol
-// to the Service and invoke methods as appropriate
+// The installed adapter should send the following events in nssocket protocol
+// to the Service and invoke methods as appropriate
//
Adapter.prototype.install = function install() {
throw new Error('not implemented');
View
3  lib/forever/service/adapters/systemv/index.js
@@ -10,8 +10,7 @@ var fs = require('fs'),
util = require('util'),
path = require('path'),
spawn = require('child_process').spawn,
- daemon = require('daemon'),
- dnode = require('dnode'),
+ nssocket = require('nssocket'),
forever = require('../../../../forever'),
Adapter = require('../adapter');
View
23 lib/forever/worker.js
@@ -13,11 +13,11 @@ function findSocket(sockPath, startAt, callback) {
var sock = path.join(sockPath, 'worker.' + startAt + '.sock');
fs.stat(sock, function (err, stat) {
if (err) {
- if (err.code == 'ENOENT') {
- return callback(null, sock)
- }
- return callback(err);
+ return err.code == 'ENOENT'
+ ? callback(null, sock)
+ : callback(err);
}
+
return findSocket(sockPath, ++startAt, callback);
});
}
@@ -32,7 +32,7 @@ var Worker = exports.Worker = function (options) {
this._socket = null;
};
-Worker.prototype.start = function (cb) {
+Worker.prototype.start = function (callback) {
var self = this;
if (this._socket) throw new Error("Can't start already started worker");
@@ -68,25 +68,22 @@ Worker.prototype.start = function (cb) {
socket.send(['kill', 'stop']);
this.exitOnKill && process.exit();
});
+
self.monitor.kill();
});
});
findSocket(self.sockPath, function (err, sock) {
if (err) {
- return cb && cb(err);
+ return callback && callback(err);
}
+
+ self._sockFile = sock;
self._socket.listen(sock, function () {
//
// `listening` listener doesn't take error as the first parameter
//
- cb && cb(null, sock);
-
- //
- // If we're a fork, notify master that server is set up and waiting for
- // commands.
- //
- process.send && process.send('listening', sock);
+ callback && callback(null, sock);
});
});
};
View
16 package.json
@@ -22,13 +22,12 @@
"tools"
],
"dependencies": {
+ "broadway": "0.1.x",
"cliff": "0.x.x",
- "clip": "0.x.x",
- "dnode": "0.8.x",
- "daemon": "0.3.x >=0.3.2",
"flatiron": "0.1.x",
"minimatch": "0.0.x",
"nconf": "0.5.x",
+ "nssocket": "0.3.x",
"optimist": "0.2.x",
"pkginfo": "0.x.x",
"portfinder": "0.x.x",
@@ -36,12 +35,13 @@
"timespan": "2.0.x",
"watch": "0.4.x",
"utile": "0.0.x",
- "winston": "0.5.x",
- "broadway": "0.1.x"
+ "winston": "0.5.x"
},
"devDependencies": {
- "vows": "0.5.x",
- "eventemitter2": "0.4.x"
+ "daemon": "0.3.x >=0.3.2",
+ "eventemitter2": "0.4.x",
+ "request": "2.x.x",
+ "vows": "0.5.x"
},
"bin": {
"forever": "./bin/forever",
@@ -49,7 +49,7 @@
},
"main": "./lib/forever",
"scripts": {
- "test": "vows --spec --isolate"
+ "test": "vows test/**/*-test.js --spec -i"
},
"engines": {
"node": ">= 0.4.0"
View
37 test/core/check-process-test.js
@@ -0,0 +1,37 @@
+/*
+ * check-process-test.js: Tests for forever.checkProcess(pid)
+ *
+ * (C) 2010 Nodejitsu Inc.
+ * MIT LICENCE
+ *
+ */
+
+var assert = require('assert'),
+ path = require('path'),
+ vows = require('vows'),
+ forever = require('../../lib/forever'),
+ macros = require('../helpers/macros');
+
+vows.describe('forever/core/check-process').addBatch({
+ "When using forever": {
+ "checking if process exists": {
+ "if process process exists": {
+ topic: forever.checkProcess(process.pid),
+ "should return true": function (result) {
+ assert.isTrue(result);
+ }
+ },
+ "if process doesn't exist": {
+ topic: forever.checkProcess(255 * 255 * 255),
+ //
+ // This is insanely large value. On most systems there'll be no process
+ // with such PID. Also, there's no multiplatform way to check for
+ // PID limit.
+ //
+ "should return false": function (result) {
+ assert.isFalse(result);
+ }
+ }
+ }
+ }
+}).export(module);
View
13 test/tail-test.js → test/core/tail-stopall-test.js
@@ -1,5 +1,5 @@
/*
- * forever-test.js: Tests for forever module
+ * tail-stopall-test.js: Tests for forever.tail() and forever.stopAll()
*
* (C) 2010 Nodejitsu Inc.
* MIT LICENCE
@@ -10,15 +10,15 @@ var assert = require('assert'),
path = require('path'),
spawn = require('child_process').spawn,
vows = require('vows'),
- forever = require('../lib/forever');
+ forever = require('../../lib/forever');
-vows.describe('forever/tail').addBatch({
+vows.describe('forever/core/tail').addBatch({
"When using forever": {
"the tail() method": {
topic: function () {
var that = this;
- that.child = spawn('node', [path.join(__dirname, 'fixtures', 'start-daemon.js')]);
+ that.child = spawn('node', [path.join(__dirname, '..', 'fixtures', 'start-daemon.js')]);
setTimeout(function () {
forever.tail(0, that.callback);
}, 2000);
@@ -30,7 +30,10 @@ vows.describe('forever/tail').addBatch({
assert.isArray(proc.logs);
assert.isTrue(!!proc.logs.length);
assert.isTrue(proc.logs.length > 10);
- })
+ proc.logs.forEach(function (line) {
+ assert.match(line, /^Logging at/);
+ });
+ });
}
}
}
View
23 test/fixtures/test-hook.js
@@ -1,23 +0,0 @@
-/*
- * test-hook.js: Test hook fixture for raising an event on forever.Monitor `exit`
- *
- * (C) 2010 Nodejitsu Inc.
- * MIT LICENCE
- *
- */
-
-var events = require('events'),
- util = require('util');
-
-var TestHook = exports.TestHook = function () {
- events.EventEmitter.call(this);
-};
-
-util.inherits(TestHook, events.EventEmitter);
-
-TestHook.prototype.attach = function (monitor) {
- var self = this;
- monitor.on('exit', function () {
- self.emit.apply(self, ['hook-exit'].concat(arguments));
- });
-};
View
2  test/helpers/mocks/stream.js
@@ -13,7 +13,7 @@ StreamMock.prototype.write = function (data) {
this.contents.push(data);
};
-StreamMock.prototype.close = function () {
+StreamMock.prototype.close = StreamMock.prototype.end = function () {
this.closed = true;
};
View
39 test/hook-test.js
@@ -1,39 +0,0 @@
-/*
- * hook-test.js: Tests for forever-based hooks
- *
- * (C) 2010 Nodejitsu Inc.
- * MIT LICENCE
- *
- */
-
- var assert = require('assert'),
- path = require('path'),
- vows = require('vows'),
- forever = require('../lib/forever'),
- TestHook = require('./fixtures/test-hook').TestHook;
-
- vows.describe('forever/spin-restart').addBatch({
- "When using forever": {
- "and spawning a script that spin restarts": {
- "with a simple hook": {
- topic: function () {
- var script = path.join(__dirname, '..', 'examples', 'always-throw.js'),
- hook = new TestHook(),
- child;
-
- child = new (forever.Monitor)(script, {
- silent: true,
- max: 1,
- hooks: [hook]
- });
-
- hook.on('hook-exit', this.callback.bind(null, null));
- child.start();
- },
- "should raise the `hook-exit` event": function (err, child, spinning) {
- assert.isNull(err);
- }
- }
- }
- }
- }).export(module);
View
10 test/env-spawn-test.js → test/monitor/env-spawn-test.js
@@ -9,9 +9,9 @@
var assert = require('assert'),
path = require('path'),
vows = require('vows'),
- forever = require('../lib/forever');
+ forever = require('../../lib/forever');
-vows.describe('forever/spawn-options').addBatch({
+vows.describe('forever/monitor/spawn-options').addBatch({
"When using forever": {
"an instance of forever.Monitor with valid options": {
"passing environment variables to env-vars.js": {
@@ -23,7 +23,7 @@ vows.describe('forever/spawn-options').addBatch({
BAR: 'bar'
};
- child = new (forever.Monitor)(path.join(__dirname, '..', 'examples', 'env-vars.js'), {
+ child = new (forever.Monitor)(path.join(__dirname, '..', '..', 'examples', 'env-vars.js'), {
max: 1,
silent: true,
minUptime: 0,
@@ -48,7 +48,7 @@ vows.describe('forever/spawn-options').addBatch({
this.cwd = path.join(__dirname, '..');
- child = new (forever.Monitor)(path.join(__dirname, '..', 'examples', 'custom-cwd.js'), {
+ child = new (forever.Monitor)(path.join(__dirname, '..', '..', 'examples', 'custom-cwd.js'), {
max: 1,
silent: true,
minUptime: 0,
@@ -76,7 +76,7 @@ vows.describe('forever/spawn-options').addBatch({
'OLDPWD'
];
- child = new (forever.Monitor)(path.join(__dirname, '..', 'examples', 'all-env-vars.js'), {
+ child = new (forever.Monitor)(path.join(__dirname, '..', '..', 'examples', 'all-env-vars.js'), {
max: 1,
silent: true,
minUptime: 0,
View
6 test/signal-test.js → test/monitor/signal-test.js
@@ -9,14 +9,14 @@
var assert = require('assert'),
path = require('path'),
vows = require('vows'),
- forever = require('../lib/forever');
+ forever = require('../../lib/forever');
-vows.describe('forever/signal').addBatch({
+vows.describe('forever/monitor/signal').addBatch({
"When using forever": {
"and spawning a script that ignores signals SIGINT and SIGTERM": {
"with killTTL defined": {
topic: function () {
- var script = path.join(__dirname, '..', 'examples', 'signal-ignore.js'),
+ var script = path.join(__dirname, '..', '..', 'examples', 'signal-ignore.js'),
child = new (forever.Monitor)(script, { silent: true, killTTL: 1000 }),
callback = this.callback,
timer;
View
45 test/forever-test.js → test/monitor/simple-test.js
@@ -1,5 +1,5 @@
/*
- * forever-test.js: Tests for forever module
+ * simple-test.js: Simple tests for using forever.Monitor instances.
*
* (C) 2010 Nodejitsu Inc.
* MIT LICENCE
@@ -9,19 +9,21 @@
var assert = require('assert'),
path = require('path'),
vows = require('vows'),
- forever = require('../lib/forever'),
- macros = require('./helpers/macros');
+ forever = require('../../lib/forever'),
+ macros = require('../helpers/macros');
-vows.describe('forever').addBatch({
+var examplesDir = path.join(__dirname, '..', '..', 'examples');
+
+vows.describe('forever/monitor/simple').addBatch({
"When using forever": {
"an instance of forever.Monitor with valid options": {
- topic: new (forever.Monitor)(path.join(__dirname, '..', 'examples', 'server.js'), {
+ topic: new (forever.Monitor)(path.join(examplesDir, 'server.js'), {
max: 10,
silent: true,
options: ['-p', 8090]
}),
"should have correct properties set": function (child) {
- assert.isArray(child.options);
+ assert.isArray(child.args);
assert.equal(child.max, 10);
assert.isTrue(child.silent);
assert.isFunction(child.start);
@@ -44,24 +46,24 @@ vows.describe('forever').addBatch({
}
},
"running error-on-timer sample three times": macros.assertTimes(
- path.join(__dirname, '..', 'examples', 'error-on-timer.js'),
+ path.join(examplesDir, 'error-on-timer.js'),
3,
{
minUptime: 200,
silent: true,
- outFile: 'test/stdout.log',
- errFile: 'test/stderr.log',
+ outFile: 'test/fixtures/stdout.log',
+ errFile: 'test/fixtures/stderr.log',
options: []
}
),
"running error-on-timer sample once": macros.assertTimes(
- path.join(__dirname, '..', 'examples', 'error-on-timer.js'),
+ path.join(examplesDir, 'error-on-timer.js'),
1,
{
minUptime: 200,
silent: true,
- outFile: 'test/stdout.log',
- errFile: 'test/stderr.log',
+ outFile: 'test/fixtures/stdout.log',
+ errFile: 'test/fixtures/stderr.log',
options: []
}
),
@@ -89,25 +91,6 @@ vows.describe('forever').addBatch({
assert.isNotNull(err);
assert.isTrue(err.message.indexOf('does not exist') !== -1);
}
- },
- "checking if process exists": {
- "if process process exists": {
- topic: forever.checkProcess(process.pid),
- "should return true": function (result) {
- assert.isTrue(result);
- }
- },
- "if process doesn't exist": {
- topic: forever.checkProcess(255 * 255 * 255),
- //
- // This is insanely large value. On most systems there'll be no process
- // with such PID. Also, there's no multiplatform way to check for
- // PID limit.
- //
- "should return false": function (result) {
- assert.isFalse(result);
- }
- }
}
}
}).export(module);
View
8 test/spin-test.js → test/monitor/spin-test.js
@@ -9,14 +9,14 @@
var assert = require('assert'),
path = require('path'),
vows = require('vows'),
- forever = require('../lib/forever');
+ forever = require('../../lib/forever');
-vows.describe('forever/spin-restart').addBatch({
+vows.describe('forever/monitor/spin-restart').addBatch({
"When using forever": {
"and spawning a script that spin restarts": {
"with no spinSleepTime specified": {
topic: function () {
- var script = path.join(__dirname, '..', 'examples', 'always-throw.js'),
+ var script = path.join(__dirname, '..', '..', 'examples', 'always-throw.js'),
child = new (forever.Monitor)(script, { silent: true, minUptime: 2000, max: 3 });
child.on('exit', this.callback.bind({}, null));
@@ -31,7 +31,7 @@ vows.describe('forever/spin-restart').addBatch({
},
"with a spinSleepTime specified": {
topic: function () {
- var script = path.join(__dirname, '..', 'examples', 'always-throw.js'),
+ var script = path.join(__dirname, '..', '..', 'examples', 'always-throw.js'),
child = new (forever.Monitor)(script, { silent: true, max: 3, spinSleepTime: 1 });
child.on('exit', this.callback.bind({}, null));
View
22 test/watch-test.js → test/monitor/watch-test.js
@@ -10,49 +10,49 @@ var assert = require('assert'),
path = require('path'),
fs = require('fs'),
vows = require('vows'),
- forever = require('../lib/forever');
+ forever = require('../../lib/forever');
-vows.describe('forever/watch').addBatch({
+vows.describe('forever/monitor/watch').addBatch({
'When using forever with watch enabled': {
'forever should': {
topic: forever.start('daemon.js', {
silent: true,
options: ['-p', '8090'],
watch: true,
- sourceDir: path.join(__dirname, 'fixtures', 'watch')
+ sourceDir: path.join(__dirname, '..', 'fixtures', 'watch')
}),
'have correct options set': function (child) {
assert.isTrue(child.watchIgnoreDotFiles);
- assert.equal(fs.realpathSync(path.join(__dirname, 'fixtures', 'watch')),
+ assert.equal(fs.realpathSync(path.join(__dirname, '..', 'fixtures', 'watch')),
fs.realpathSync(child.watchDirectory));
},
'when file changes': {
topic: function (child) {
child.once('restart', this.callback);
- fs.writeFileSync(path.join(__dirname, 'fixtures', 'watch', 'file'),
+ fs.writeFileSync(path.join(__dirname, '..', 'fixtures', 'watch', 'file'),
'// hello, I know nodejitsu.');
},
'restart the script': function (child, _) {
- fs.writeFileSync(path.join(__dirname, 'fixtures', 'watch', 'file'),
+ fs.writeFileSync(path.join(__dirname, '..', 'fixtures', 'watch', 'file'),
'/* hello, I know nodejitsu. */');
}
},
'when file is added': {
topic: function (child) {
child.once('restart', this.callback);
- fs.writeFileSync(path.join(__dirname, 'fixtures', 'watch', 'newFile'), '');
+ fs.writeFileSync(path.join(__dirname, '..', 'fixtures', 'watch', 'newFile'), '');
},
'restart the script': function (child, _) {
- fs.unlinkSync(path.join(__dirname, 'fixtures', 'watch', 'newFile'));
+ fs.unlinkSync(path.join(__dirname, '..', 'fixtures', 'watch', 'newFile'));
}
},
'when file is removed': {
topic: function (child) {
child.once('restart', this.callback);
- fs.unlinkSync(path.join(__dirname, 'fixtures', 'watch', 'removeMe'));
+ fs.unlinkSync(path.join(__dirname, '..', 'fixtures', 'watch', 'removeMe'));
},
'restart the script': function (child, _) {
- fs.writeFileSync(path.join(__dirname, 'fixtures', 'watch', 'removeMe'), '');
+ fs.writeFileSync(path.join(__dirname, '..', 'fixtures', 'watch', 'removeMe'), '');
}
},
'read .foreverignore file': {
@@ -60,7 +60,7 @@ vows.describe('forever/watch').addBatch({
assert.deepEqual(
child.watchIgnorePatterns,
fs.readFileSync(
- path.join(__dirname, 'fixtures', 'watch', '.foreverignore'),
+ path.join(__dirname, '..', 'fixtures', 'watch', '.foreverignore'),
'utf8'
).split("\n")
);
View
73 test/multiple-processes-test.js
@@ -1,73 +0,0 @@
-/*
- * multiple-processes-test.js: Tests for spawning multiple processes with forever
- *
- * (C) 2010 Nodejitsu Inc.
- * MIT LICENCE
- *
- */
-
-var assert = require('assert'),
- net = require('net'),
- path = require('path'),
- vows = require('vows'),
- forever = require('../lib/forever');
-
-vows.describe('forever/multiple-processes').addBatch({
- "When using forever": {
- "and spawning two processes using the same script": {
- topic: function () {
- var that = this,
- output = ''
- script = path.join(__dirname, '..', 'examples', 'server.js');
-
- this.child1 = new (forever.Monitor)(script, {
- silent: true,
- maxRestart: 1,
- options: [ "--port=8080"]
- });
-
- that.child1.on('start', function () {
- that.child2 = new (forever.Monitor)(script, {
- silent: true,
- maxRestart: 1,
- options: [ "--port=8081"]
- });
-
- function buildJson (data) {
- var json;
-
- try {
- output += data;
- json = JSON.parse(output.toString());
- that.callback(null, json);
- }
- catch (ex) {
- //
- // Do nothing here
- //
- }
- }
-
- that.child2.on('start', function () {
- forever.startServer(that.child1, that.child2, function (err, server, socketPath) {
- var socket = new net.Socket();
- socket.on('data', buildJson);
- socket.on('error', that.callback);
- socket.connect(socketPath);
- });
- });
-
- that.child2.start();
- });
-
- that.child1.start();
- },
- "should spawn both processes appropriately": function (err, data) {
- assert.isNull(err);
- assert.equal(data.monitors.length, 2);
- this.child1.stop();
- this.child2.stop();
- }
- }
- },
-}).export(module);
View
2  test/plugins/logger-test.js
@@ -41,7 +41,7 @@ vows.describe('forever/plugins/logger').addBatch({
topic: function (mocks) {
var self = this;
- mocks.monitor.emit('exit');
+ mocks.monitor.child.emit('exit');
process.nextTick(function () {
self.callback(null, mocks);
});
View
4 test/service-test.js → test/service/simple-test.js
@@ -9,9 +9,9 @@
var assert = require('assert'),
path = require('path'),
vows = require('vows'),
- forever = require('../lib/forever');
+ forever = require('../../lib/forever');
-vows.describe('forever/service').addBatch({
+vows.describe('forever/service/simple').addBatch({
"When using forever": {
"the service module": {
"should have the correct exports": function () {
View
73 test/worker/multiple-workers-test.js
@@ -0,0 +1,73 @@
+/*
+ * multiple-workers-test.js: Tests for spawning multiple workers with forever
+ *
+ * (C) 2010 Nodejitsu Inc.
+ * MIT LICENCE
+ *
+ */
+
+var assert = require('assert'),
+ net = require('net'),
+ path = require('path'),
+ request = require('request'),
+ vows = require('vows'),
+ forever = require('../../lib/forever');
+
+function assertRunning(port) {
+ return {
+ topic: function () {
+ request('http://127.0.0.1:' + port, this.callback);
+ },
+ "should respond with `i know nodejitsu`": function (err, res, body) {
+ assert.isNull(err);
+ assert.equal(res.statusCode, 200);
+ assert.equal(body, 'hello, i know nodejitsu.');
+ }
+ }
+}
+
+vows.describe('forever/workers/multiple').addBatch({
+ "When using forever": {
+ "and spawning two processes using the same script": {
+ topic: function () {
+ var that = this,
+ script = path.join(__dirname, '..', '..', 'examples', 'server.js');
+
+ this.child1 = new (forever.Monitor)(script, {
+ silent: true,
+ maxRestart: 1,
+ options: [ "--port=8080"]
+ });
+
+ this.child2 = new (forever.Monitor)(script, {
+ silent: true,
+ maxRestart: 1,
+ options: [ "--port=8081"]
+ });
+
+ this.child1.on('start', function () {
+ that.child2.on('start', function () {
+ setTimeout(function () {
+ forever.startServer(that.child1, that.child2, that.callback);
+ }, 1000);
+ });
+
+ that.child2.start()
+ });
+
+ this.child1.start();
+ },
+ "should respond with no error": function (err, workers) {
+ assert.isTrue(!err);
+ assert.lengthOf(workers, 2);
+ assert.equal(workers[0].monitor, this.child1);
+ assert.equal(workers[1].monitor, this.child2);
+ workers.forEach(function (worker) {
+ assert.instanceOf(worker, forever.Worker);
+ });
+ },
+ "requests against the first child": assertRunning(8080),
+ "requests against the second child": assertRunning(8081)
+ }
+ },
+}).export(module);
View
8 test/worker-test.js → test/worker/simple-test.js
@@ -2,12 +2,12 @@ var path = require('path'),
assert = require('assert'),
vows = require('vows'),
nssocket = require('nssocket'),
- macros = require('./helpers/macros'),
- MonitorMock = require('./helpers/mocks/monitor').MonitorMock;
+ macros = require('../helpers/macros'),
+ MonitorMock = require('../helpers/mocks/monitor').MonitorMock;
-var SOCKET_PATH = path.join(__dirname, 'fixtures');
+var SOCKET_PATH = path.join(__dirname, '..', 'fixtures');
-vows.describe('forever/worker').addBatch({
+vows.describe('forever/worker/simple').addBatch({
'When using forever worker': {
'and starting it and pinging it': macros.assertWorkerConnected({
monitor: new MonitorMock(),

1 comment on commit 8f9f0ad

Please sign in to comment.
Something went wrong with that request. Please try again.