mirror of https://github.com/mthenw/frontail.git
One level down
parent
4588a7a611
commit
317240d02f
|
@ -23,7 +23,7 @@
|
|||
"browser": true,
|
||||
|
||||
"globals": {
|
||||
"io": false,
|
||||
"io": true,
|
||||
"describe": false,
|
||||
"it": false,
|
||||
"beforeEach": false,
|
||||
|
|
238
index.js
238
index.js
|
@ -1,3 +1,5 @@
|
|||
'use strict';
|
||||
|
||||
var connect = require('connect');
|
||||
var cookieParser = require('cookie');
|
||||
var crypto = require('crypto');
|
||||
|
@ -10,132 +12,128 @@ var tail = require('./lib/tail');
|
|||
var connectBuilder = require('./lib/connect_builder');
|
||||
var serverBuilder = require('./lib/server_builder');
|
||||
|
||||
(function () {
|
||||
'use strict';
|
||||
program
|
||||
.version(require('./package.json').version)
|
||||
.usage('[options] [file ...]')
|
||||
.option('-h, --host <host>', 'listening host, default 0.0.0.0', String, '0.0.0.0')
|
||||
.option('-p, --port <port>', 'listening port, default 9001', Number, 9001)
|
||||
.option('-n, --number <number>', 'starting lines number, default 10', Number, 10)
|
||||
.option('-l, --lines <lines>', 'number on lines stored in browser, default 2000', Number, 2000)
|
||||
.option('-t, --theme <theme>', 'name of the theme (default, dark)', String, 'default')
|
||||
.option('-d, --daemonize', 'run as daemon')
|
||||
.option('-U, --user <username>',
|
||||
'Basic Authentication username, option works only along with -P option', String, false)
|
||||
.option('-P, --password <password>',
|
||||
'Basic Authentication password, option works only along with -U option', String, false)
|
||||
.option('-k, --key <key.pem>',
|
||||
'Private Key for HTTPS, option works only along with -c option',
|
||||
String, false)
|
||||
.option('-c, --certificate <cert.pem>',
|
||||
'Certificate for HTTPS, option works only along with -k option',
|
||||
String, false)
|
||||
.option('--pid-path <path>',
|
||||
'if run as daemon file that will store the process id, default /var/run/frontail.pid',
|
||||
String, '/var/run/frontail.pid')
|
||||
.option('--log-path <path>', 'if run as daemon file that will be used as a log, default /dev/null',
|
||||
String, '/dev/null')
|
||||
.parse(process.argv);
|
||||
|
||||
program
|
||||
.version(require('./package.json').version)
|
||||
.usage('[options] [file ...]')
|
||||
.option('-h, --host <host>', 'listening host, default 0.0.0.0', String, '0.0.0.0')
|
||||
.option('-p, --port <port>', 'listening port, default 9001', Number, 9001)
|
||||
.option('-n, --number <number>', 'starting lines number, default 10', Number, 10)
|
||||
.option('-l, --lines <lines>', 'number on lines stored in browser, default 2000', Number, 2000)
|
||||
.option('-t, --theme <theme>', 'name of the theme (default, dark)', String, 'default')
|
||||
.option('-d, --daemonize', 'run as daemon')
|
||||
.option('-U, --user <username>',
|
||||
'Basic Authentication username, option works only along with -P option', String, false)
|
||||
.option('-P, --password <password>',
|
||||
'Basic Authentication password, option works only along with -U option', String, false)
|
||||
.option('-k, --key <key.pem>',
|
||||
'Private Key for HTTPS, option works only along with -c option',
|
||||
String, false)
|
||||
.option('-c, --certificate <cert.pem>',
|
||||
'Certificate for HTTPS, option works only along with -k option',
|
||||
String, false)
|
||||
.option('--pid-path <path>',
|
||||
'if run as daemon file that will store the process id, default /var/run/frontail.pid',
|
||||
String, '/var/run/frontail.pid')
|
||||
.option('--log-path <path>', 'if run as daemon file that will be used as a log, default /dev/null',
|
||||
String, '/dev/null')
|
||||
.parse(process.argv);
|
||||
if (program.args.length === 0) {
|
||||
console.error('Arguments needed, use --help');
|
||||
process.exit();
|
||||
}
|
||||
|
||||
if (program.args.length === 0) {
|
||||
console.error('Arguments needed, use --help');
|
||||
process.exit();
|
||||
/**
|
||||
* Validate params
|
||||
*/
|
||||
var doAuthorization = !!(program.user && program.password);
|
||||
var doSecure = !!(program.key && program.certificate);
|
||||
var sessionSecret = String(+new Date()) + Math.random();
|
||||
var sessionKey = 'sid';
|
||||
var files = program.args.join(' ');
|
||||
var filesNamespace = crypto.createHash('md5').update(files).digest('hex');
|
||||
|
||||
if (program.daemonize) {
|
||||
/**
|
||||
* Daemonize process
|
||||
*/
|
||||
var logFile = fs.openSync(program.logPath, 'a');
|
||||
var args = ['-p', program.port, '-n', program.number, '-l', program.lines, '-t', program.theme];
|
||||
|
||||
if (doAuthorization) {
|
||||
args = args.concat(['-U', program.user, '-P', program.password]);
|
||||
}
|
||||
|
||||
args = args.concat(program.args);
|
||||
|
||||
var proc = daemon.daemon(
|
||||
__filename,
|
||||
args,
|
||||
{
|
||||
stdout: logFile,
|
||||
stderr: logFile
|
||||
}
|
||||
);
|
||||
fs.writeFileSync(program.pidPath, proc.pid);
|
||||
} else {
|
||||
/**
|
||||
* HTTP(s) server setup
|
||||
*/
|
||||
var appBuilder = connectBuilder();
|
||||
if (doAuthorization) {
|
||||
appBuilder.session(sessionSecret, sessionKey);
|
||||
appBuilder.authorize(program.user, program.password);
|
||||
}
|
||||
appBuilder
|
||||
.static(__dirname + '/lib/web/assets')
|
||||
.index(__dirname + '/lib/web/index.html', files, filesNamespace, program.theme);
|
||||
|
||||
var builder = serverBuilder();
|
||||
if (doSecure) {
|
||||
builder.secure(program.key, program.certificate);
|
||||
}
|
||||
var server = builder
|
||||
.use(appBuilder.build())
|
||||
.port(program.port)
|
||||
.host(program.host)
|
||||
.build();
|
||||
|
||||
/**
|
||||
* socket.io setup
|
||||
*/
|
||||
var io = socketio.listen(server, {log: false});
|
||||
|
||||
if (doAuthorization) {
|
||||
io.set('authorization', function (handshakeData, accept) {
|
||||
if (handshakeData.headers.cookie) {
|
||||
var cookie = cookieParser.parse(handshakeData.headers.cookie);
|
||||
var sessionId = connect.utils.parseSignedCookie(cookie[sessionKey], sessionSecret);
|
||||
if (sessionId) {
|
||||
return accept(null, true);
|
||||
}
|
||||
return accept('Invalid cookie', false);
|
||||
} else {
|
||||
return accept('No cookie in header', false);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Validate params
|
||||
* When connected send starting data
|
||||
*/
|
||||
var doAuthorization = !!(program.user && program.password);
|
||||
var doSecure = !!(program.key && program.certificate);
|
||||
var sessionSecret = String(+new Date()) + Math.random();
|
||||
var sessionKey = 'sid';
|
||||
var files = program.args.join(' ');
|
||||
var filesNamespace = crypto.createHash('md5').update(files).digest('hex');
|
||||
var tailer = tail(program.args, {buffer: program.number});
|
||||
var filesSocket = io.of('/' + filesNamespace).on('connection', function (socket) {
|
||||
socket.emit('options:lines', program.lines);
|
||||
|
||||
if (program.daemonize) {
|
||||
/**
|
||||
* Daemonize process
|
||||
*/
|
||||
var logFile = fs.openSync(program.logPath, 'a');
|
||||
var args = ['-p', program.port, '-n', program.number, '-l', program.lines, '-t', program.theme];
|
||||
|
||||
if (doAuthorization) {
|
||||
args = args.concat(['-U', program.user, '-P', program.password]);
|
||||
}
|
||||
|
||||
args = args.concat(program.args);
|
||||
|
||||
var proc = daemon.daemon(
|
||||
__filename,
|
||||
args,
|
||||
{
|
||||
stdout: logFile,
|
||||
stderr: logFile
|
||||
}
|
||||
);
|
||||
fs.writeFileSync(program.pidPath, proc.pid);
|
||||
} else {
|
||||
/**
|
||||
* HTTP(s) server setup
|
||||
*/
|
||||
var appBuilder = connectBuilder();
|
||||
if (doAuthorization) {
|
||||
appBuilder.session(sessionSecret, sessionKey);
|
||||
appBuilder.authorize(program.user, program.password);
|
||||
}
|
||||
appBuilder
|
||||
.static(__dirname + '/lib/web/assets')
|
||||
.index(__dirname + '/lib/web/index.html', files, filesNamespace, program.theme);
|
||||
|
||||
var builder = serverBuilder();
|
||||
if (doSecure) {
|
||||
builder.secure(program.key, program.certificate);
|
||||
}
|
||||
var server = builder
|
||||
.use(appBuilder.build())
|
||||
.port(program.port)
|
||||
.host(program.host)
|
||||
.build();
|
||||
|
||||
/**
|
||||
* socket.io setup
|
||||
*/
|
||||
var io = socketio.listen(server, {log: false});
|
||||
|
||||
if (doAuthorization) {
|
||||
io.set('authorization', function (handshakeData, accept) {
|
||||
if (handshakeData.headers.cookie) {
|
||||
var cookie = cookieParser.parse(handshakeData.headers.cookie);
|
||||
var sessionId = connect.utils.parseSignedCookie(cookie[sessionKey], sessionSecret);
|
||||
if (sessionId) {
|
||||
return accept(null, true);
|
||||
}
|
||||
return accept('Invalid cookie', false);
|
||||
} else {
|
||||
return accept('No cookie in header', false);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* When connected send starting data
|
||||
*/
|
||||
var tailer = tail(program.args, {buffer: program.number});
|
||||
var filesSocket = io.of('/' + filesNamespace).on('connection', function (socket) {
|
||||
socket.emit('options:lines', program.lines);
|
||||
|
||||
tailer.getBuffer().forEach(function (line) {
|
||||
socket.emit('line', line);
|
||||
});
|
||||
tailer.getBuffer().forEach(function (line) {
|
||||
socket.emit('line', line);
|
||||
});
|
||||
});
|
||||
|
||||
/**
|
||||
* Send incoming data
|
||||
*/
|
||||
tailer.on('line', function (line) {
|
||||
filesSocket.emit('line', sanitizer(line).xss());
|
||||
});
|
||||
}
|
||||
})();
|
||||
/**
|
||||
* Send incoming data
|
||||
*/
|
||||
tailer.on('line', function (line) {
|
||||
filesSocket.emit('line', sanitizer(line).xss());
|
||||
});
|
||||
}
|
||||
|
|
|
@ -1,55 +1,53 @@
|
|||
'use strict';
|
||||
|
||||
var connect = require('connect');
|
||||
var fs = require('fs');
|
||||
|
||||
(function () {
|
||||
'use strict';
|
||||
var ConnectBuilder = function () {
|
||||
this.app = connect();
|
||||
};
|
||||
|
||||
var ConnectBuilder = function () {
|
||||
this.app = connect();
|
||||
};
|
||||
ConnectBuilder.prototype.authorize = function (user, pass) {
|
||||
this.app.use(connect.basicAuth(function (incomingUser, incomingPass) {
|
||||
return user === incomingUser && pass === incomingPass;
|
||||
}));
|
||||
|
||||
ConnectBuilder.prototype.authorize = function (user, pass) {
|
||||
this.app.use(connect.basicAuth(function (incomingUser, incomingPass) {
|
||||
return user === incomingUser && pass === incomingPass;
|
||||
}));
|
||||
return this;
|
||||
};
|
||||
|
||||
return this;
|
||||
};
|
||||
ConnectBuilder.prototype.build = function () {
|
||||
return this.app;
|
||||
};
|
||||
|
||||
ConnectBuilder.prototype.build = function () {
|
||||
return this.app;
|
||||
};
|
||||
ConnectBuilder.prototype.index = function (path, files, filesNamespace, theme) {
|
||||
theme = theme || 'default';
|
||||
|
||||
ConnectBuilder.prototype.index = function (path, files, filesNamespace, theme) {
|
||||
theme = theme || 'default';
|
||||
|
||||
this.app.use(function (req, res) {
|
||||
fs.readFile(path, function (err, data) {
|
||||
res.writeHead(200, {'Content-Type': 'text/html'});
|
||||
res.end(data.toString('utf-8')
|
||||
.replace(/__TITLE__/g, files)
|
||||
.replace(/__THEME__/g, theme)
|
||||
.replace(/__NAMESPACE__/g, filesNamespace),
|
||||
'utf-8'
|
||||
);
|
||||
});
|
||||
this.app.use(function (req, res) {
|
||||
fs.readFile(path, function (err, data) {
|
||||
res.writeHead(200, {'Content-Type': 'text/html'});
|
||||
res.end(data.toString('utf-8')
|
||||
.replace(/__TITLE__/g, files)
|
||||
.replace(/__THEME__/g, theme)
|
||||
.replace(/__NAMESPACE__/g, filesNamespace),
|
||||
'utf-8'
|
||||
);
|
||||
});
|
||||
});
|
||||
|
||||
return this;
|
||||
};
|
||||
return this;
|
||||
};
|
||||
|
||||
ConnectBuilder.prototype.session = function (secret, key) {
|
||||
this.app.use(connect.cookieParser());
|
||||
this.app.use(connect.session({secret: secret, key: key}));
|
||||
return this;
|
||||
};
|
||||
ConnectBuilder.prototype.session = function (secret, key) {
|
||||
this.app.use(connect.cookieParser());
|
||||
this.app.use(connect.session({secret: secret, key: key}));
|
||||
return this;
|
||||
};
|
||||
|
||||
ConnectBuilder.prototype.static = function (path) {
|
||||
this.app.use(connect.static(path));
|
||||
return this;
|
||||
};
|
||||
ConnectBuilder.prototype.static = function (path) {
|
||||
this.app.use(connect.static(path));
|
||||
return this;
|
||||
};
|
||||
|
||||
module.exports = function () {
|
||||
return new ConnectBuilder();
|
||||
};
|
||||
})();
|
||||
module.exports = function () {
|
||||
return new ConnectBuilder();
|
||||
};
|
||||
|
|
|
@ -1,54 +1,52 @@
|
|||
'use strict';
|
||||
|
||||
var fs = require('fs');
|
||||
var http = require('http');
|
||||
var https = require('https');
|
||||
|
||||
(function () {
|
||||
'use strict';
|
||||
var ServerBuilder = function () {
|
||||
this._host = null;
|
||||
this._port = 9001;
|
||||
};
|
||||
|
||||
var ServerBuilder = function () {
|
||||
this._host = null;
|
||||
this._port = 9001;
|
||||
};
|
||||
ServerBuilder.prototype.build = function () {
|
||||
if (this._key && this._cert) {
|
||||
var options = {
|
||||
key: this._key,
|
||||
cert: this._cert
|
||||
};
|
||||
return https.createServer(options, this._callback).listen(this._port, this._host);
|
||||
} else {
|
||||
return http.createServer(this._callback).listen(this._port, this._host);
|
||||
}
|
||||
};
|
||||
|
||||
ServerBuilder.prototype.build = function () {
|
||||
if (this._key && this._cert) {
|
||||
var options = {
|
||||
key: this._key,
|
||||
cert: this._cert
|
||||
};
|
||||
return https.createServer(options, this._callback).listen(this._port, this._host);
|
||||
} else {
|
||||
return http.createServer(this._callback).listen(this._port, this._host);
|
||||
}
|
||||
};
|
||||
ServerBuilder.prototype.host = function (host) {
|
||||
this._host = host;
|
||||
return this;
|
||||
};
|
||||
|
||||
ServerBuilder.prototype.host = function (host) {
|
||||
this._host = host;
|
||||
return this;
|
||||
};
|
||||
ServerBuilder.prototype.port = function (port) {
|
||||
this._port = port;
|
||||
return this;
|
||||
};
|
||||
|
||||
ServerBuilder.prototype.port = function (port) {
|
||||
this._port = port;
|
||||
return this;
|
||||
};
|
||||
ServerBuilder.prototype.secure = function (keyPath, certPath) {
|
||||
try {
|
||||
this._key = fs.readFileSync(keyPath);
|
||||
this._cert = fs.readFileSync(certPath);
|
||||
} catch (e) {
|
||||
throw new Error('No key or certificate file found');
|
||||
}
|
||||
|
||||
ServerBuilder.prototype.secure = function (keyPath, certPath) {
|
||||
try {
|
||||
this._key = fs.readFileSync(keyPath);
|
||||
this._cert = fs.readFileSync(certPath);
|
||||
} catch (e) {
|
||||
throw new Error('No key or certificate file found');
|
||||
}
|
||||
return this;
|
||||
};
|
||||
|
||||
return this;
|
||||
};
|
||||
ServerBuilder.prototype.use = function (callback) {
|
||||
this._callback = callback;
|
||||
return this;
|
||||
};
|
||||
|
||||
ServerBuilder.prototype.use = function (callback) {
|
||||
this._callback = callback;
|
||||
return this;
|
||||
};
|
||||
|
||||
module.exports = function () {
|
||||
return new ServerBuilder();
|
||||
};
|
||||
})();
|
||||
module.exports = function () {
|
||||
return new ServerBuilder();
|
||||
};
|
||||
|
|
64
lib/tail.js
64
lib/tail.js
|
@ -1,45 +1,43 @@
|
|||
'use strict';
|
||||
|
||||
var EventEmitter = require('events').EventEmitter;
|
||||
var spawn = require('child_process').spawn;
|
||||
var util = require('util');
|
||||
|
||||
(function () {
|
||||
'use strict';
|
||||
var Tail = function (path, options) {
|
||||
EventEmitter.call(this);
|
||||
|
||||
var Tail = function (path, options) {
|
||||
EventEmitter.call(this);
|
||||
this.buffer = [];
|
||||
this.options = options || {buffer: 0};
|
||||
|
||||
this.buffer = [];
|
||||
this.options = options || {buffer: 0};
|
||||
var self = this;
|
||||
var tail = spawn('tail', ['-F'].concat(path));
|
||||
tail.stdout.on('data', function (data) {
|
||||
|
||||
var self = this;
|
||||
var tail = spawn('tail', ['-F'].concat(path));
|
||||
tail.stdout.on('data', function (data) {
|
||||
|
||||
var lines = data.toString('utf-8');
|
||||
lines = lines.split('\n');
|
||||
lines.pop();
|
||||
lines.forEach(function (line) {
|
||||
if (self.options.buffer) {
|
||||
if (self.buffer.length === self.options.buffer) {
|
||||
self.buffer.shift();
|
||||
}
|
||||
self.buffer.push(line);
|
||||
var lines = data.toString('utf-8');
|
||||
lines = lines.split('\n');
|
||||
lines.pop();
|
||||
lines.forEach(function (line) {
|
||||
if (self.options.buffer) {
|
||||
if (self.buffer.length === self.options.buffer) {
|
||||
self.buffer.shift();
|
||||
}
|
||||
self.emit('line', line);
|
||||
});
|
||||
self.buffer.push(line);
|
||||
}
|
||||
self.emit('line', line);
|
||||
});
|
||||
});
|
||||
|
||||
process.on('exit', function () {
|
||||
tail.kill();
|
||||
});
|
||||
};
|
||||
util.inherits(Tail, EventEmitter);
|
||||
process.on('exit', function () {
|
||||
tail.kill();
|
||||
});
|
||||
};
|
||||
util.inherits(Tail, EventEmitter);
|
||||
|
||||
Tail.prototype.getBuffer = function () {
|
||||
return this.buffer;
|
||||
};
|
||||
Tail.prototype.getBuffer = function () {
|
||||
return this.buffer;
|
||||
};
|
||||
|
||||
module.exports = function (path, options) {
|
||||
return new Tail(path, options);
|
||||
};
|
||||
})();
|
||||
module.exports = function (path, options) {
|
||||
return new Tail(path, options);
|
||||
};
|
|
@ -1,109 +1,107 @@
|
|||
'use strict';
|
||||
|
||||
var connectBuilder = require('../lib/connect_builder');
|
||||
var request = require('supertest');
|
||||
|
||||
(function () {
|
||||
'use strict';
|
||||
|
||||
describe('connectBuilder', function () {
|
||||
it('should build connect app', function () {
|
||||
connectBuilder().build().should.have.property('use');
|
||||
connectBuilder().build().should.have.property('listen');
|
||||
});
|
||||
|
||||
it('should build app requiring authorized user', function (done) {
|
||||
var app = connectBuilder().authorize('user', 'pass').build();
|
||||
|
||||
request(app)
|
||||
.get('/')
|
||||
.expect('www-authenticate', 'Basic realm="Authorization Required"')
|
||||
.expect(401, done);
|
||||
});
|
||||
|
||||
it('should build app allowing user to login', function (done) {
|
||||
var app = connectBuilder().authorize('user', 'pass').build();
|
||||
app.use(function (req, res) {
|
||||
res.end('secret!');
|
||||
});
|
||||
|
||||
request(app)
|
||||
.get('/')
|
||||
.set('Authorization', 'Basic dXNlcjpwYXNz')
|
||||
.expect(200, 'secret!', done);
|
||||
});
|
||||
|
||||
it('should build app that setup session', function (done) {
|
||||
var app = connectBuilder().session('secret', 'sessionkey').build();
|
||||
app.use(function (req, res) {
|
||||
res.end();
|
||||
});
|
||||
|
||||
request(app)
|
||||
.get('/')
|
||||
.expect('set-cookie', /^sessionkey/, done);
|
||||
});
|
||||
|
||||
it('should build app that serve static files', function (done) {
|
||||
var app = connectBuilder().static(__dirname + '/fixtures').build();
|
||||
|
||||
request(app)
|
||||
.get('/foo')
|
||||
.expect('bar', done);
|
||||
});
|
||||
|
||||
|
||||
it('should build app that serve index file', function (done) {
|
||||
var app = connectBuilder().index(__dirname + '/fixtures/index', '/testfile').build();
|
||||
|
||||
request(app)
|
||||
.get('/')
|
||||
.expect(200)
|
||||
.expect('Content-Type', 'text/html', done);
|
||||
});
|
||||
|
||||
it('should build app that replace index title', function (done) {
|
||||
var app = connectBuilder()
|
||||
.index(__dirname + '/fixtures/index_with_title', '/testfile')
|
||||
.build();
|
||||
|
||||
request(app)
|
||||
.get('/')
|
||||
.expect('<head><title>/testfile</title></head>', done);
|
||||
});
|
||||
|
||||
it('builds app that sets socket.io namespace based on files', function (done) {
|
||||
var app = connectBuilder()
|
||||
.index(__dirname + '/fixtures/index_with_ns', '/testfile', 'ns', 'dark')
|
||||
.build();
|
||||
|
||||
request(app)
|
||||
.get('/')
|
||||
.expect('ns', done);
|
||||
});
|
||||
|
||||
it('should build app that sets theme', function (done) {
|
||||
var app = connectBuilder()
|
||||
.index(__dirname + '/fixtures/index_with_theme', '/testfile', 'ns', 'dark')
|
||||
.build();
|
||||
|
||||
request(app)
|
||||
.get('/')
|
||||
.expect(
|
||||
'<head><title>/testfile</title><link href="dark.css" rel="stylesheet" type="text/css"/></head>',
|
||||
done
|
||||
);
|
||||
});
|
||||
|
||||
it('should build app that sets default theme', function (done) {
|
||||
var app = connectBuilder()
|
||||
.index(__dirname + '/fixtures/index_with_theme', '/testfile')
|
||||
.build();
|
||||
|
||||
request(app)
|
||||
.get('/')
|
||||
.expect(
|
||||
'<head><title>/testfile</title><link href="default.css" rel="stylesheet" type="text/css"/></head>',
|
||||
done
|
||||
);
|
||||
});
|
||||
describe('connectBuilder', function () {
|
||||
it('should build connect app', function () {
|
||||
connectBuilder().build().should.have.property('use');
|
||||
connectBuilder().build().should.have.property('listen');
|
||||
});
|
||||
})();
|
||||
|
||||
it('should build app requiring authorized user', function (done) {
|
||||
var app = connectBuilder().authorize('user', 'pass').build();
|
||||
|
||||
request(app)
|
||||
.get('/')
|
||||
.expect('www-authenticate', 'Basic realm="Authorization Required"')
|
||||
.expect(401, done);
|
||||
});
|
||||
|
||||
it('should build app allowing user to login', function (done) {
|
||||
var app = connectBuilder().authorize('user', 'pass').build();
|
||||
app.use(function (req, res) {
|
||||
res.end('secret!');
|
||||
});
|
||||
|
||||
request(app)
|
||||
.get('/')
|
||||
.set('Authorization', 'Basic dXNlcjpwYXNz')
|
||||
.expect(200, 'secret!', done);
|
||||
});
|
||||
|
||||
it('should build app that setup session', function (done) {
|
||||
var app = connectBuilder().session('secret', 'sessionkey').build();
|
||||
app.use(function (req, res) {
|
||||
res.end();
|
||||
});
|
||||
|
||||
request(app)
|
||||
.get('/')
|
||||
.expect('set-cookie', /^sessionkey/, done);
|
||||
});
|
||||
|
||||
it('should build app that serve static files', function (done) {
|
||||
var app = connectBuilder().static(__dirname + '/fixtures').build();
|
||||
|
||||
request(app)
|
||||
.get('/foo')
|
||||
.expect('bar', done);
|
||||
});
|
||||
|
||||
|
||||
it('should build app that serve index file', function (done) {
|
||||
var app = connectBuilder().index(__dirname + '/fixtures/index', '/testfile').build();
|
||||
|
||||
request(app)
|
||||
.get('/')
|
||||
.expect(200)
|
||||
.expect('Content-Type', 'text/html', done);
|
||||
});
|
||||
|
||||
it('should build app that replace index title', function (done) {
|
||||
var app = connectBuilder()
|
||||
.index(__dirname + '/fixtures/index_with_title', '/testfile')
|
||||
.build();
|
||||
|
||||
request(app)
|
||||
.get('/')
|
||||
.expect('<head><title>/testfile</title></head>', done);
|
||||
});
|
||||
|
||||
it('builds app that sets socket.io namespace based on files', function (done) {
|
||||
var app = connectBuilder()
|
||||
.index(__dirname + '/fixtures/index_with_ns', '/testfile', 'ns', 'dark')
|
||||
.build();
|
||||
|
||||
request(app)
|
||||
.get('/')
|
||||
.expect('ns', done);
|
||||
});
|
||||
|
||||
it('should build app that sets theme', function (done) {
|
||||
var app = connectBuilder()
|
||||
.index(__dirname + '/fixtures/index_with_theme', '/testfile', 'ns', 'dark')
|
||||
.build();
|
||||
|
||||
request(app)
|
||||
.get('/')
|
||||
.expect(
|
||||
'<head><title>/testfile</title><link href="dark.css" rel="stylesheet" type="text/css"/></head>',
|
||||
done
|
||||
);
|
||||
});
|
||||
|
||||
it('should build app that sets default theme', function (done) {
|
||||
var app = connectBuilder()
|
||||
.index(__dirname + '/fixtures/index_with_theme', '/testfile')
|
||||
.build();
|
||||
|
||||
request(app)
|
||||
.get('/')
|
||||
.expect(
|
||||
'<head><title>/testfile</title><link href="default.css" rel="stylesheet" type="text/css"/></head>',
|
||||
done
|
||||
);
|
||||
});
|
||||
});
|
||||
|
|
|
@ -1,115 +1,113 @@
|
|||
'use strict';
|
||||
|
||||
var fs = require('fs');
|
||||
var http = require('http');
|
||||
var https = require('https');
|
||||
var serverBuilder = require('../lib/server_builder');
|
||||
var sinon = require('sinon');
|
||||
|
||||
(function () {
|
||||
'use strict';
|
||||
describe('serverBuilder', function () {
|
||||
|
||||
describe('serverBuilder', function () {
|
||||
describe('http server', function () {
|
||||
var httpServer;
|
||||
var createServer;
|
||||
|
||||
describe('http server', function () {
|
||||
var httpServer;
|
||||
var createServer;
|
||||
|
||||
beforeEach(function () {
|
||||
httpServer = sinon.createStubInstance(http.Server);
|
||||
httpServer.listen.returns(httpServer);
|
||||
createServer = sinon.stub(http, 'createServer').returns(httpServer);
|
||||
});
|
||||
|
||||
afterEach(function () {
|
||||
createServer.restore();
|
||||
});
|
||||
|
||||
it('should build server', function () {
|
||||
var server = serverBuilder().build();
|
||||
|
||||
createServer.calledOnce.should.equal(true);
|
||||
server.should.be.an.instanceof(http.Server);
|
||||
});
|
||||
|
||||
it('should build server accepting requests', function () {
|
||||
var callback = function () {};
|
||||
|
||||
serverBuilder().use(callback).build();
|
||||
|
||||
createServer.calledWith(callback).should.equal(true);
|
||||
});
|
||||
|
||||
it('should build listening server', function () {
|
||||
serverBuilder().build();
|
||||
|
||||
httpServer.listen.calledOnce.should.equal(true);
|
||||
});
|
||||
|
||||
it('should build server listening on specified port', function () {
|
||||
serverBuilder().port(6666).build();
|
||||
|
||||
httpServer.listen.calledWith(6666).should.equal(true);
|
||||
});
|
||||
|
||||
it('should build server listening on default port', function () {
|
||||
serverBuilder().build();
|
||||
|
||||
httpServer.listen.calledWith(9001).should.equal(true);
|
||||
});
|
||||
|
||||
it('should build server listening on specified host', function () {
|
||||
serverBuilder().host('127.0.0.1').build();
|
||||
|
||||
httpServer.listen.calledWith(9001, '127.0.0.1').should.equal(true);
|
||||
});
|
||||
|
||||
it('should build server listening on default host', function () {
|
||||
serverBuilder().build();
|
||||
|
||||
httpServer.listen.calledWith(9001, null).should.equal(true);
|
||||
});
|
||||
beforeEach(function () {
|
||||
httpServer = sinon.createStubInstance(http.Server);
|
||||
httpServer.listen.returns(httpServer);
|
||||
createServer = sinon.stub(http, 'createServer').returns(httpServer);
|
||||
});
|
||||
|
||||
describe('https server', function () {
|
||||
var httpsServer;
|
||||
var createHttpsServer;
|
||||
var readFileSyncStub;
|
||||
afterEach(function () {
|
||||
createServer.restore();
|
||||
});
|
||||
|
||||
beforeEach(function () {
|
||||
httpsServer = sinon.createStubInstance(https.Server);
|
||||
httpsServer.listen.returns(httpsServer);
|
||||
createHttpsServer = sinon.stub(https, 'createServer').returns(httpsServer);
|
||||
readFileSyncStub = sinon.stub(fs, 'readFileSync');
|
||||
readFileSyncStub.withArgs('key.pem').returns('testkey');
|
||||
readFileSyncStub.withArgs('cert.pem').returns('testcert');
|
||||
});
|
||||
it('should build server', function () {
|
||||
var server = serverBuilder().build();
|
||||
|
||||
afterEach(function () {
|
||||
createHttpsServer.restore();
|
||||
readFileSyncStub.restore();
|
||||
});
|
||||
createServer.calledOnce.should.equal(true);
|
||||
server.should.be.an.instanceof(http.Server);
|
||||
});
|
||||
|
||||
it('should build server', function () {
|
||||
var server = serverBuilder().secure('key.pem', 'cert.pem').build();
|
||||
it('should build server accepting requests', function () {
|
||||
var callback = function () {};
|
||||
|
||||
server.should.be.an.instanceof(https.Server);
|
||||
createHttpsServer.calledWith({key: 'testkey', cert: 'testcert'}).should.equal(true);
|
||||
});
|
||||
serverBuilder().use(callback).build();
|
||||
|
||||
it('should build server accepting requests', function () {
|
||||
var callback = function () {};
|
||||
createServer.calledWith(callback).should.equal(true);
|
||||
});
|
||||
|
||||
serverBuilder().use(callback).secure('key.pem', 'cert.pem').build();
|
||||
it('should build listening server', function () {
|
||||
serverBuilder().build();
|
||||
|
||||
createHttpsServer.calledWith({key: 'testkey', cert: 'testcert'}, callback).should.equal(true);
|
||||
});
|
||||
httpServer.listen.calledOnce.should.equal(true);
|
||||
});
|
||||
|
||||
it('should throw error if key or cert not provided', function () {
|
||||
readFileSyncStub.restore();
|
||||
it('should build server listening on specified port', function () {
|
||||
serverBuilder().port(6666).build();
|
||||
|
||||
(function () {
|
||||
serverBuilder().secure('nofile', 'nofile');
|
||||
}).should.throw('No key or certificate file found');
|
||||
});
|
||||
httpServer.listen.calledWith(6666).should.equal(true);
|
||||
});
|
||||
|
||||
it('should build server listening on default port', function () {
|
||||
serverBuilder().build();
|
||||
|
||||
httpServer.listen.calledWith(9001).should.equal(true);
|
||||
});
|
||||
|
||||
it('should build server listening on specified host', function () {
|
||||
serverBuilder().host('127.0.0.1').build();
|
||||
|
||||
httpServer.listen.calledWith(9001, '127.0.0.1').should.equal(true);
|
||||
});
|
||||
|
||||
it('should build server listening on default host', function () {
|
||||
serverBuilder().build();
|
||||
|
||||
httpServer.listen.calledWith(9001, null).should.equal(true);
|
||||
});
|
||||
});
|
||||
})();
|
||||
|
||||
describe('https server', function () {
|
||||
var httpsServer;
|
||||
var createHttpsServer;
|
||||
var readFileSyncStub;
|
||||
|
||||
beforeEach(function () {
|
||||
httpsServer = sinon.createStubInstance(https.Server);
|
||||
httpsServer.listen.returns(httpsServer);
|
||||
createHttpsServer = sinon.stub(https, 'createServer').returns(httpsServer);
|
||||
readFileSyncStub = sinon.stub(fs, 'readFileSync');
|
||||
readFileSyncStub.withArgs('key.pem').returns('testkey');
|
||||
readFileSyncStub.withArgs('cert.pem').returns('testcert');
|
||||
});
|
||||
|
||||
afterEach(function () {
|
||||
createHttpsServer.restore();
|
||||
readFileSyncStub.restore();
|
||||
});
|
||||
|
||||
it('should build server', function () {
|
||||
var server = serverBuilder().secure('key.pem', 'cert.pem').build();
|
||||
|
||||
server.should.be.an.instanceof(https.Server);
|
||||
createHttpsServer.calledWith({key: 'testkey', cert: 'testcert'}).should.equal(true);
|
||||
});
|
||||
|
||||
it('should build server accepting requests', function () {
|
||||
var callback = function () {};
|
||||
|
||||
serverBuilder().use(callback).secure('key.pem', 'cert.pem').build();
|
||||
|
||||
createHttpsServer.calledWith({key: 'testkey', cert: 'testcert'}, callback).should.equal(true);
|
||||
});
|
||||
|
||||
it('should throw error if key or cert not provided', function () {
|
||||
readFileSyncStub.restore();
|
||||
|
||||
(function () {
|
||||
serverBuilder().secure('nofile', 'nofile');
|
||||
}).should.throw('No key or certificate file found');
|
||||
});
|
||||
});
|
||||
});
|
||||
|
|
56
test/tail.js
56
test/tail.js
|
@ -1,42 +1,40 @@
|
|||
'use strict';
|
||||
|
||||
var fs = require('fs');
|
||||
var tail = require('../lib/tail');
|
||||
var temp = require('temp');
|
||||
|
||||
(function () {
|
||||
'use strict';
|
||||
describe('tail', function () {
|
||||
temp.track();
|
||||
|
||||
describe('tail', function () {
|
||||
temp.track();
|
||||
|
||||
it('calls event line if new line appear in file', function (done) {
|
||||
temp.open('', function (err, info) {
|
||||
tail(info.path).on('line', function (line) {
|
||||
line.should.equal('testline');
|
||||
done();
|
||||
});
|
||||
|
||||
fs.writeSync(info.fd, 'testline\n');
|
||||
fs.closeSync(info.fd);
|
||||
it('calls event line if new line appear in file', function (done) {
|
||||
temp.open('', function (err, info) {
|
||||
tail(info.path).on('line', function (line) {
|
||||
line.should.equal('testline');
|
||||
done();
|
||||
});
|
||||
|
||||
fs.writeSync(info.fd, 'testline\n');
|
||||
fs.closeSync(info.fd);
|
||||
});
|
||||
});
|
||||
|
||||
it('buffers lines on start', function (done) {
|
||||
temp.open('', function (err, info) {
|
||||
fs.writeSync(info.fd, 'testline1\n');
|
||||
fs.writeSync(info.fd, 'testline2\n');
|
||||
fs.writeSync(info.fd, 'testline3\n');
|
||||
fs.closeSync(info.fd);
|
||||
it('buffers lines on start', function (done) {
|
||||
temp.open('', function (err, info) {
|
||||
fs.writeSync(info.fd, 'testline1\n');
|
||||
fs.writeSync(info.fd, 'testline2\n');
|
||||
fs.writeSync(info.fd, 'testline3\n');
|
||||
fs.closeSync(info.fd);
|
||||
|
||||
var calls = 0;
|
||||
var tailer = tail(info.path, {buffer: 2}).on('line', function () {
|
||||
calls += 1;
|
||||
var calls = 0;
|
||||
var tailer = tail(info.path, {buffer: 2}).on('line', function () {
|
||||
calls += 1;
|
||||
|
||||
if (calls === 3) {
|
||||
tailer.getBuffer().should.eql(['testline2', 'testline3']);
|
||||
done();
|
||||
}
|
||||
});
|
||||
if (calls === 3) {
|
||||
tailer.getBuffer().should.eql(['testline2', 'testline3']);
|
||||
done();
|
||||
}
|
||||
});
|
||||
});
|
||||
});
|
||||
})();
|
||||
});
|
||||
|
|
Loading…
Reference in New Issue