From 976997103ee8cd446667e17616bba0e4323127c7 Mon Sep 17 00:00:00 2001 From: Eran Hammer Date: Thu, 1 Nov 2012 18:08:46 -0700 Subject: [PATCH 1/2] Fix response processing header order --- lib/request.js | 52 ++++++++++++++++++++++++-------------------------- 1 file changed, 25 insertions(+), 27 deletions(-) diff --git a/lib/request.js b/lib/request.js index 8c8ea62dd..d8503072f 100755 --- a/lib/request.js +++ b/lib/request.js @@ -568,14 +568,32 @@ internals.Request.prototype._respond = function () { var code = 200; var headers = this.response.options.headers || {}; - var contentType = ''; var payload = null; var review = function () { + // Set CORS and Cache headers + self._setCors(headers); self._setCache(headers); + // Set options + + if (self.response.options.created) { + code = 201; + headers.Location = self.response.options.created; + } + + if (self.response.options.contentType) { + headers['Content-Type'] = self.response.options.contentType; + } + + if (self.response.options.contentLength) { + headers['Content-Length'] = self.response.options.contentLength; + } + + // Empty response + var result = self.response.result; if (!result) { inject(null); @@ -595,37 +613,20 @@ internals.Request.prototype._respond = function () { code = errCode; result = errPayload; - contentType = errContentType; + headers['Content-Type'] = errContentType || headers['Content-Type']; // Override }); } else { var errResponse = (result instanceof Err ? result.toResponse() : Err.toResponse(result)); code = errResponse.code || 500; result = errResponse.payload || ''; - if (errResponse.contentType) { - contentType = errResponse.contentType; - } + headers['Content-Type'] = errResponse.contentType || headers['Content-Type']; // Override } } else { self.log(['http', 'response']); } - // Set options - - if (self.response.options.created) { - code = 201; - headers.Location = self.response.options.created; - } - - if (self.response.options.contentType) { - contentType = self.response.options.contentType; - } - - if (self.response.options.contentLength) { - headers['Content-Length'] = self.response.options.contentLength; - } - // Payload if (typeof result === 'object') { @@ -644,25 +645,22 @@ internals.Request.prototype._respond = function () { // Object payload = JSON.stringify(result); - contentType = contentType || 'application/json'; + headers['Content-Type'] = headers['Content-Type'] || 'application/json'; // If not defined } else { // Non-object (String, etc.) payload = (typeof result === 'string' ? result : JSON.stringify(result)); - contentType = contentType || 'text/html'; + headers['Content-Type'] = headers['Content-Type'] || 'text/html'; // If not defined } // Non-stream inject(result); - if (!headers['Content-Type']) { - headers['Content-Type'] = contentType; - } - if (payload !== null && - !headers['Content-Length']) { // payload can be empty string + if (payload !== null && // payload can be empty string + !headers['Content-Length']) { headers['Content-Length'] = Buffer.byteLength(payload); } From 029a5b8429652836c17114ea49a671d51b840261 Mon Sep 17 00:00:00 2001 From: Eran Hammer Date: Fri, 2 Nov 2012 00:09:14 -0700 Subject: [PATCH 2/2] Cache tests --- lib/cache/index.js | 79 ++++---- lib/cache/memory.js | 11 +- lib/cache/mongo.js | 78 +++++--- lib/cache/redis.js | 8 +- lib/log.js | 13 +- test/unit/cache.js | 431 +++++++++++++++++++++++++++++++------------- test/unit/log.js | 14 +- test/unit/mongo.js | 2 +- test/unit/redis.js | 17 -- 9 files changed, 435 insertions(+), 218 deletions(-) mode change 100644 => 100755 test/unit/mongo.js mode change 100644 => 100755 test/unit/redis.js diff --git a/lib/cache/index.js b/lib/cache/index.js index d077dd533..7033d4a11 100755 --- a/lib/cache/index.js +++ b/lib/cache/index.js @@ -27,24 +27,32 @@ exports.Client = internals.Client = function (options) { // Create internal connection - var implementation = null; - if (this.settings.engine === 'redis') { - implementation = Redis; - } - else if (this.settings.engine === 'mongodb') { - implementation = Mongo; - } - else if (this.settings.engine === 'memory') { - implementation = Memory; + var engine = self.settings.engine; + if (typeof engine === 'object') { + this.connection = engine; + engine = 'extension'; } + else { + var factory = null; + + if (engine === 'redis') { + factory = Redis; + } + else if (engine === 'mongodb') { + factory = Mongo; + } + else if (engine === 'memory') { + factory = Memory; + } - Utils.assert(implementation, 'Unknown cache engine type'); + Utils.assert(factory, 'Unknown cache engine type'); + this.connection = new factory.Connection(this.settings); + } - this.connection = new implementation.Connection(this.settings); this.connection.start(function (err) { if (err) { - Log.event(['cache', 'error', self.settings.engine], 'Failed initializing cache engine'); + Log.event(['cache', 'error', engine], 'Failed initializing cache engine'); } }); @@ -54,25 +62,23 @@ exports.Client = internals.Client = function (options) { internals.Client.prototype.stop = function () { - if (this.connection) { - this.connection.stop(); - } + this.connection.stop(); }; internals.Client.prototype.start = function (callback) { - if (this.connection) { - this.connection.start(callback); - } + this.connection.start(callback); }; -internals.Client.prototype.validateSegmentName = function (name) { +internals.Client.prototype.isReady = function () { - if (!this.connection) { - return new Error('Disconnected'); - } + return this.connection.isReady(); +}; + + +internals.Client.prototype.validateSegmentName = function (name) { return this.connection.validateSegmentName(name); }; @@ -82,17 +88,16 @@ internals.Client.prototype.get = function (key, callback) { var self = this; + if (!this.connection.isReady()) { + // Disconnected + return callback(new Error('Disconnected')); + } if (key === null) { // null key not allowed return callback(null, null); } - if (!this.connection) { - // Disconnected - return callback(new Error('Disconnected')); - } - this.connection.get(key, function (err, result) { if (err) { @@ -130,16 +135,16 @@ internals.Client.prototype.get = function (key, callback) { internals.Client.prototype.set = function (key, value, ttl, callback) { + if (!this.connection.isReady()) { + // Disconnected + return callback(new Error('Disconnected')); + } + if (key === null) { // null key not allowed return callback(new Error('null key not allowed')); } - if (!this.connection) { - // Disconnected - return callback(new Error('Disconnected')); - } - if (ttl <= 0) { // Not cachable (or bad rules) return callback(); @@ -151,16 +156,16 @@ internals.Client.prototype.set = function (key, value, ttl, callback) { internals.Client.prototype.drop = function (key, callback) { + if (!this.connection.isReady()) { + // Disconnected + return callback(new Error('Disconnected')); + } + if (key === null) { // null key not allowed return callback(new Error('null key not allowed')); } - if (!this.connection) { - // Disconnected - return callback(new Error('Disconnected')); - } - this.connection.drop(key, callback); // Always drop, regardless of caching rules }; diff --git a/lib/cache/memory.js b/lib/cache/memory.js index 9a27aa080..02e184b07 100755 --- a/lib/cache/memory.js +++ b/lib/cache/memory.js @@ -20,11 +20,10 @@ exports.Connection = internals.Connection = function (options) { internals.Connection.prototype.start = function (callback) { - if (this.cache) { - return callback(new Error('Connection already established')); + if (!this.cache) { + this.cache = {}; } - this.cache = {}; return callback(); }; @@ -36,6 +35,12 @@ internals.Connection.prototype.stop = function () { }; +internals.Connection.prototype.isReady = function () { + + return (!!this.cache); +}; + + internals.Connection.prototype.validateSegmentName = function (name) { if (!name) { diff --git a/lib/cache/mongo.js b/lib/cache/mongo.js index 04822ba5e..f47772a24 100755 --- a/lib/cache/mongo.js +++ b/lib/cache/mongo.js @@ -29,8 +29,9 @@ exports.Connection = internals.Connection = function (options) { this.settings = options; this.client = null; - this.isReady = false; + this.isConnected = false; this.collections = {}; + this.startPending = null; // Set to an array of callbacks if start pending return this; }; @@ -39,19 +40,50 @@ internals.Connection.prototype.start = function (callback) { var self = this; - if (this.client) { - return callback(new Error('Connection already established')); + // Check if already connected + + if (this.isConnected) { + + return callback(); + } + + // Check if start already pending + + if (this.startPending) { + this.startPending.push(callback); + return; } + // Set start pending state + + this.startPending = [callback]; + + var connected = function (err) { + + self.isConnected = !err; + + for (var i = 0, il = self.startPending.length; i < il; ++i) { + self.startPending[i](err); + } + + self.startPending = null; + }; + + // Create client + var server = new MongoDB.Server(this.settings.host, this.settings.port, { auto_reconnect: true, poolSize: this.settings.poolSize }); this.client = new MongoDB.Db(this.settings.partition, server, { safe: true }); + // Open connection + this.client.open(function (err, client) { if (err) { - return callback(new Error('Failed opening connection')); + return connected(new Error('Failed opening connection')); } + // Authenticate + if (self.settings.username) { self.client.authenticate(self.settings.username, self.settings.password, function (err, result) { @@ -59,21 +91,36 @@ internals.Connection.prototype.start = function (callback) { !result) { self.stop(); - return callback(new Error('Database authentication error: ' + (err ? JSON.stringify(err) : 'failed'))); + return connected(new Error('Database authentication error: ' + (err ? JSON.stringify(err) : 'failed'))); } - self.isReady = true; - return callback(); + return connected(); }); } else { - self.isReady = true; - return callback(); + return connected(); } }); }; +internals.Connection.prototype.stop = function () { + + if (this.client) { + this.client.close(); + this.client = null; + this.collections = {}; + this.isConnected = false; + } +}; + + +internals.Connection.prototype.isReady = function () { + + return this.isConnected; +}; + + internals.Connection.prototype.validateSegmentName = function (name) { /* @@ -114,7 +161,7 @@ internals.Connection.prototype.getCollection = function (name, callback) { var self = this; - if (!this.isReady) { + if (!this.isConnected) { return callback(new Error('Connection not ready')); } @@ -142,17 +189,6 @@ internals.Connection.prototype.getCollection = function (name, callback) { }; -internals.Connection.prototype.stop = function () { - - if (this.client) { - this.client.close(); - this.client = null; - this.collections = {}; - this.isReady = false; - } -}; - - internals.Connection.prototype.get = function (key, callback) { if (!this.client) { diff --git a/lib/cache/redis.js b/lib/cache/redis.js index 23a47c64b..6b509f7a8 100755 --- a/lib/cache/redis.js +++ b/lib/cache/redis.js @@ -22,7 +22,7 @@ exports.Connection = internals.Connection = function (options) { internals.Connection.prototype.start = function (callback) { if (this.client) { - return callback(new Error('Connection already established')); + return callback(); } this.client = Redis.createClient(this.settings.port, this.settings.host); @@ -60,6 +60,12 @@ internals.Connection.prototype.stop = function () { }; +internals.Connection.prototype.isReady = function () { + + return (!!this.client); +}; + + internals.Connection.prototype.validateSegmentName = function (name) { if (!name) { diff --git a/lib/log.js b/lib/log.js index e948850d0..c78fe5b9a 100755 --- a/lib/log.js +++ b/lib/log.js @@ -22,11 +22,6 @@ NodeUtil.inherits(internals.Logger, Events.EventEmitter); internals.Logger.prototype.event = function (tags, data, timestamp) { - if (process.env.NODE_ENV === 'test') { - - return; // Silence log output during test execution - } - tags = (tags instanceof Array ? tags : [tags]); var now = (timestamp ? (timestamp instanceof Date ? timestamp : new Date(timestamp)) : new Date()); @@ -43,7 +38,13 @@ internals.Logger.prototype.event = function (tags, data, timestamp) { }; -internals.Logger.prototype.print = function (event, _isBypass) { +internals.Logger.prototype.print = function (event, _isBypass, _isTest) { + + if (process.env.NODE_ENV === 'test' && + !_isTest) { + + return; // Silence log output during test execution + } var pad = function (value) { diff --git a/test/unit/cache.js b/test/unit/cache.js index a04e229ad..964a1717d 100755 --- a/test/unit/cache.js +++ b/test/unit/cache.js @@ -5,6 +5,7 @@ var libPath = process.env.TEST_COV ? '../../lib-cov/' : '../../lib/'; var Cache = require(libPath + 'cache/index'); var Server = require(libPath + 'server'); var Defaults = require(libPath + 'defaults'); +var Log = require(libPath + 'log'); var Sinon = require('sinon'); @@ -13,6 +14,7 @@ require('../suite')(function (useRedis, useMongo) { describe('Client', function () { it('throws an error if using an unknown engine type', function (done) { + var fn = function () { var options = { engine: 'bob' @@ -25,36 +27,67 @@ require('../suite')(function (useRedis, useMongo) { done(); }); - if (useRedis) { - it('creates a new connection when using redis', function (done) { - var client = new Cache.Client(Defaults.cache('redis')); - expect(client).to.exist; - done(); - }); - } + var testEngine = function (engine) { - if (useMongo) { - it('creates a new connection when using mongodb', function (done) { - var client = new Cache.Client(Defaults.cache('mongodb')); + it('creates a new connection using ' + engine, function (done) { - expect(client.connection.client).to.exist; - done(); + var client = new Cache.Client(Defaults.cache(engine)); + client.start(function (err) { + + expect(client.isReady()).to.equal(true); + done(); + }); }); - } - if (useRedis) { - it('returns not found on get when using null key', function (done) { - var client = new Cache.Client(Defaults.cache('redis')); - client.get(null, function (err, result) { + it('closes the connection using ' + engine, function (done) { - expect(err).to.equal(null); - expect(result).to.equal(null); + var client = new Cache.Client(Defaults.cache(engine)); + client.start(function (err) { + + expect(client.isReady()).to.equal(true); + client.stop(); + expect(client.isReady()).to.equal(false); done(); }); }); - it('returns error on set when using null key', function (done) { - var client = new Cache.Client(Defaults.cache('redis')); + it('ignored starting a connection twice using ' + engine, function (done) { + + var client = new Cache.Client(Defaults.cache(engine)); + var x = 2; + var start = function () { + + client.start(function (err) { + + expect(client.isReady()).to.equal(true); + --x; + if (!x) { + done(); + } + }); + }; + + start(); + start(); + }); + + it('returns not found on get when using null key using ' + engine, function (done) { + + var client = new Cache.Client(Defaults.cache(engine)); + client.start(function (err) { + + client.get(null, function (err, result) { + + expect(err).to.equal(null); + expect(result).to.equal(null); + done(); + }); + }); + }); + + it('returns error on set when using null key using ' + engine, function (done) { + + var client = new Cache.Client(Defaults.cache(engine)); client.set(null, {}, 1000, function (err) { expect(err instanceof Error).to.equal(true); @@ -62,76 +95,217 @@ require('../suite')(function (useRedis, useMongo) { }); }); - it('returns error on drop when using null key', function (done) { - var client = new Cache.Client(Defaults.cache('redis')); + it('ignores set when using non-positive ttl value using ' + engine, function (done) { + + var client = new Cache.Client(Defaults.cache(engine)); + client.start(function (err) { + + client.set('x', 'y', 0, function (err) { + + expect(err).to.not.exist; + done(); + }); + }); + }); + + it('returns error on drop when using null key using ' + engine, function (done) { + + var client = new Cache.Client(Defaults.cache(engine)); client.drop(null, function (err) { expect(err instanceof Error).to.equal(true); done(); }); }); - } - if (useMongo) { - it('creates a new connection when using mongodb', function (done) { - var client = new Cache.Client(Defaults.cache('mongodb')); + it('returns error on get when stopped using ' + engine, function (done) { - expect(client).to.exist; - done(); - }); - } + var client = new Cache.Client(Defaults.cache(engine)); + client.stop(); + client.connection.get('x', function (err, result) { - describe('#stop', function() { + expect(err).to.exist; + expect(result).to.not.exist; + done(); + }); + }); - if (useMongo) { - it('closes the connection when using mongodb', function (done) { - var client = new Cache.Client(Defaults.cache('mongodb')); + it('returns error on set when stopped using ' + engine, function (done) { - expect(client.connection.client).to.exist; + var client = new Cache.Client(Defaults.cache(engine)); + client.stop(); + client.connection.set('x', 'y', 1, function (err) { - client.stop(); - expect(client.connection.client).to.not.exist; + expect(err).to.exist; done(); }); - } + }); - if (useRedis) { - it('closes the connection when using redis', function (done) { - var client = new Cache.Client(Defaults.cache('redis')); + it('returns error on drop when stopped using ' + engine, function (done) { - expect(client.connection.client).to.exist; + var client = new Cache.Client(Defaults.cache(engine)); + client.stop(); + client.connection.drop('x', function (err) { - client.stop(); - expect(client.connection.client).to.not.exist; + expect(err).to.exist; done(); }); - } - }); + }); - describe('#stop', function() { + it('returns error on missing segment name using ' + engine, function (done) { - if (useMongo) { - it('closes the connection when using mongodb', function (done) { - var client = new Cache.Client(Defaults.cache('mongodb')); + var config = { + expiresIn: 50000, + segment: '' + }; + var fn = function () { + var client = new Cache.Client(Defaults.cache(engine)); + var cache = new Cache.Policy(config, client); + }; + expect(fn).to.throw(Error); + done(); + }); - expect(client.connection.client).to.exist; + it('returns error on bad segment name using ' + engine, function (done) { - client.stop(); - expect(client.connection.client).to.not.exist; + var config = { + expiresIn: 50000, + segment: 'a\0b' + }; + var fn = function () { + var client = new Cache.Client(Defaults.cache(engine)); + var cache = new Cache.Policy(config, client); + }; + expect(fn).to.throw(Error); + done(); + }); + + it('returns error when cache item dropped while stopped using ' + engine, function (done) { + + var client = new Cache.Client(Defaults.cache(engine)); + client.stop(); + client.drop('a', function (err) { + + expect(err).to.exist; done(); }); - } + }); + }; - it('closes the connection when using redis', function (done) { - var client = new Cache.Client(Defaults.cache('redis')); + testEngine('memory'); - expect(client.connection.client).to.exist; + if (useMongo) { + testEngine('mongodb'); + } - client.stop(); - expect(client.connection.client).to.not.exist; + if (useRedis) { + testEngine('redis'); + } + + // Error engine + + var failOn = function (method) { + + var err = new Error('FAIL'); + var errorEngineImp = { + + start: function (callback) { callback(method === 'start' ? err : null); }, + stop: function () { }, + isReady: function () { return method !== 'isReady'; }, + validateSegmentName: function () { return method === 'validateSegmentName' ? err : null; }, + get: function (key, callback) { return callback(method === 'get' ? err : null); }, + set: function (key, value, ttl, callback) { return callback(method === 'set' ? err : null); }, + drop: function (key, callback) { return callback(method === 'drop' ? err : null); } + }; + + var options = { + engine: errorEngineImp, + partition: 'hapi-cache' + }; + + return new Cache.Client(options); + }; + + it('returns error when calling get on a bad connection', function (done) { + + var client = failOn('get'); + client.get('x', function (err, result) { + + expect(err).to.exist; + expect(err.message).to.equal('FAIL'); + done(); + }); + }); + + it('logs an error when fails to start on bad connection', function (done) { + + Log.once('log', function (event) { + expect(event).to.exist; + expect(event.tags).to.exist; + expect(event.tags[0]).to.equal('cache'); + done(); + }); + var client = failOn('start'); + }); + }); + + describe('Policy', function () { + + var getCache = function () { + + var config = { + mode: 'client', + expiresIn: 1 + }; + var client = new Cache.Client(Defaults.cache('memory')); + var cache = new Cache.Policy(config, client); + return cache; + }; + + it('returns null on get when cache mode is not server', function (done) { + + getCache().get('x', function (err, result) { + + expect(err).to.not.exist; + expect(result).to.not.exist; + done(); + }); + }); + + it('returns null on set when cache mode is not server', function (done) { + + getCache().set('x', 'y', 100, function (err) { + + expect(err).to.not.exist; + done(); + }); + }); + + it('returns null on drop when cache mode is not server', function (done) { + + getCache().drop('x', function (err) { + + expect(err).to.not.exist; done(); }); }); + + it('returns null on get when item expired', function (done) { + + var client = new Cache.Client(Defaults.cache('memory')); + client.set('x', 'y', 1, function (err) { + + setTimeout(function () { + + client.get('x', function (err, result) { + + expect(err).to.not.exist; + expect(result).to.not.exist; + done(); + }); + }, 2); + }); + }); }); describe('Cache Rules', function () { @@ -139,6 +313,7 @@ require('../suite')(function (useRedis, useMongo) { describe('#compile', function () { it('compiles a single rule', function (done) { + var config = { expiresIn: 50000 }; @@ -150,11 +325,12 @@ require('../suite')(function (useRedis, useMongo) { }); it('is enabled for both client and server by defaults', function (done) { + var config = { expiresIn: 50000, segment: 'test' }; - var client = new Cache.Client(Defaults.cache('redis')); + var client = new Cache.Client(Defaults.cache('memory')); var cache = new Cache.Policy(config, client); expect(cache.isMode('server')).to.equal(true); @@ -165,10 +341,11 @@ require('../suite')(function (useRedis, useMongo) { }); it('is disabled when mode is none', function (done) { + var config = { mode: 'none' }; - var client = new Cache.Client(Defaults.cache('redis')); + var client = new Cache.Client(Defaults.cache('memory')); var cache = new Cache.Policy(config, client); expect(cache.isEnabled()).to.equal(false); @@ -178,11 +355,13 @@ require('../suite')(function (useRedis, useMongo) { }); it('throws an error when mode is none and config has other options set', function (done) { + var config = { mode: 'none', expiresIn: 50000 }; var fn = function () { + var cache = new Cache.Policy(config, {}); }; @@ -192,11 +371,13 @@ require('../suite')(function (useRedis, useMongo) { }); it('throws an error when segment is missing', function (done) { + var config = { expiresIn: 50000 }; var fn = function () { - var client = new Cache.Client(Defaults.cache('redis')); + + var client = new Cache.Client(Defaults.cache('memory')); var cache = new Cache.Policy(config, client); }; @@ -218,11 +399,13 @@ require('../suite')(function (useRedis, useMongo) { }); it('throws an error when parsing a rule with both expiresAt and expiresIn', function (done) { + var config = { expiresAt: 50, expiresIn: '02:00' }; var fn = function () { + Cache.compile(config); }; @@ -232,9 +415,11 @@ require('../suite')(function (useRedis, useMongo) { }); it('throws an error when parsing a rule with niether expiresAt or expiresIn', function (done) { + var config = { }; var fn = function () { + Cache.compile(config); }; @@ -244,10 +429,12 @@ require('../suite')(function (useRedis, useMongo) { }); it('throws an error when parsing a bad expiresAt value', function (done) { + var config = { expiresAt: function () { } }; var fn = function () { + Cache.compile(config); }; @@ -257,11 +444,13 @@ require('../suite')(function (useRedis, useMongo) { }); it('throws an error when staleIn is used without staleTimeout', function (done) { + var config = { expiresAt: '03:00', staleIn: 1000000 }; var fn = function () { + Cache.compile(config); }; @@ -271,11 +460,13 @@ require('../suite')(function (useRedis, useMongo) { }); it('throws an error when staleTimeout is used without staleIn', function (done) { + var config = { expiresAt: '03:00', staleTimeout: 100 }; var fn = function () { + Cache.compile(config); }; @@ -285,12 +476,14 @@ require('../suite')(function (useRedis, useMongo) { }); it('throws an error when staleIn is greater than a day and using expiresAt', function (done) { + var config = { expiresAt: '03:00', staleIn: 100000000, staleTimeout: 500 }; var fn = function () { + Cache.compile(config); }; @@ -300,12 +493,14 @@ require('../suite')(function (useRedis, useMongo) { }); it('throws an error when staleIn is greater than expiresIn', function (done) { + var config = { expiresIn: 500000, staleIn: 1000000, staleTimeout: 500 }; var fn = function () { + Cache.compile(config); }; @@ -315,12 +510,14 @@ require('../suite')(function (useRedis, useMongo) { }); it('throws an error when staleTimeout is greater than expiresIn', function (done) { + var config = { expiresIn: 500000, staleIn: 100000, staleTimeout: 500000 }; var fn = function () { + Cache.compile(config); }; @@ -330,12 +527,14 @@ require('../suite')(function (useRedis, useMongo) { }); it('throws an error when staleTimeout is greater than expiresIn - staleIn', function (done) { + var config = { expiresIn: 30000, staleIn: 20000, staleTimeout: 10000 }; var fn = function () { + Cache.compile(config); }; @@ -345,6 +544,7 @@ require('../suite')(function (useRedis, useMongo) { }); it('throws an error when staleTimeout is used without server mode', function (done) { + var config = { mode: 'client', expiresIn: 1000000, @@ -352,6 +552,7 @@ require('../suite')(function (useRedis, useMongo) { staleTimeout: 500 }; var fn = function () { + var cache = new Cache.Policy(config, {}); }; @@ -361,6 +562,7 @@ require('../suite')(function (useRedis, useMongo) { }); it('returns rule when staleIn is less than expiresIn', function (done) { + var config = { expiresIn: 1000000, staleIn: 500000, @@ -375,6 +577,7 @@ require('../suite')(function (useRedis, useMongo) { }); it('returns rule when staleIn is less than 24 hours and using expiresAt', function (done) { + var config = { expiresAt: '03:00', staleIn: 5000000, @@ -388,6 +591,7 @@ require('../suite')(function (useRedis, useMongo) { }); it('throws an error if has only staleTimeout or staleIn', function (done) { + var config = { mode: 'server', staleIn: 30000, @@ -395,6 +599,7 @@ require('../suite')(function (useRedis, useMongo) { }; var fn = function () { + Cache.compile(config); }; @@ -403,6 +608,7 @@ require('../suite')(function (useRedis, useMongo) { }); it('doesn\'t throw an error if has both staleTimeout and staleIn', function (done) { + var config = { mode: 'server', staleIn: 30000, @@ -411,6 +617,7 @@ require('../suite')(function (useRedis, useMongo) { }; var fn = function () { + Cache.compile(config); }; expect(fn).to.not.throw(Error); @@ -418,6 +625,7 @@ require('../suite')(function (useRedis, useMongo) { }); it('throws an error if trying to use stale caching on the client', function (done) { + var config = { mode: 'client', staleIn: 30000, @@ -426,6 +634,7 @@ require('../suite')(function (useRedis, useMongo) { }; var fn = function () { + Cache.compile(config); }; @@ -434,6 +643,7 @@ require('../suite')(function (useRedis, useMongo) { }); it('converts the stale time to ms', function (done) { + var config = { mode: 'server+client', staleIn: 30000, @@ -448,6 +658,7 @@ require('../suite')(function (useRedis, useMongo) { }); it('throws an error if staleTimeout is greater than expiresIn', function (done) { + var config = { mode: 'client', staleIn: 2000, @@ -456,6 +667,7 @@ require('../suite')(function (useRedis, useMongo) { }; var fn = function () { + Cache.compile(config); }; @@ -464,6 +676,7 @@ require('../suite')(function (useRedis, useMongo) { }); it('throws an error if staleIn is greater than expiresIn', function (done) { + var config = { mode: 'client', staleIn: 1000000, @@ -472,6 +685,7 @@ require('../suite')(function (useRedis, useMongo) { }; var fn = function () { + Cache.compile(config); }; @@ -483,6 +697,7 @@ require('../suite')(function (useRedis, useMongo) { describe('#ttl', function () { it('returns zero when a rule is expired', function (done) { + var config = { expiresIn: 50000 }; @@ -496,6 +711,7 @@ require('../suite')(function (useRedis, useMongo) { }); it('returns a positive number when a rule is not expired', function (done) { + var config = { expiresIn: 50000 }; @@ -508,6 +724,7 @@ require('../suite')(function (useRedis, useMongo) { }); it('returns the correct expires time when no created time is provided', function (done) { + var config = { expiresIn: 50000 }; @@ -519,6 +736,7 @@ require('../suite')(function (useRedis, useMongo) { }); it('returns 0 when created several days ago and expiresAt is used', function (done) { + var config = { expiresAt: '13:00' }; @@ -530,7 +748,29 @@ require('../suite')(function (useRedis, useMongo) { done(); }); + it('returns 0 when created in the future', function (done) { + + var config = { + expiresIn: '100' + }; + var created = Date.now() + 1000; + var rule = Cache.compile(config); + + var ttl = Cache.ttl(rule, created); + expect(ttl).to.equal(0); + done(); + }); + + it('returns 0 for bad rule', function (done) { + + var created = Date.now() - 1000; + var ttl = Cache.ttl({}, created); + expect(ttl).to.equal(0); + done(); + }); + it('returns 0 when created 60 hours ago and expiresAt is used with an hour before the created hour', function (done) { + var config = { expiresAt: '12:00' }; @@ -543,6 +783,7 @@ require('../suite')(function (useRedis, useMongo) { }); it('returns a positive number when using a future expiresAt', function (done) { + var hour = new Date(Date.now() + 60 * 60 * 1000).getHours(); var config = { @@ -557,6 +798,7 @@ require('../suite')(function (useRedis, useMongo) { }); it('returns the correct number when using a future expiresAt', function (done) { + var twoHoursAgo = new Date(Date.now() - 2 * 60 * 60 * 1000); var hours = twoHoursAgo.getHours(); var minutes = '' + twoHoursAgo.getMinutes(); @@ -575,6 +817,7 @@ require('../suite')(function (useRedis, useMongo) { }); it('returns correct number when using an expiresAt time tomorrow', function (done) { + var hour = new Date(Date.now() - 60 * 60 * 1000).getHours(); var config = { @@ -589,6 +832,7 @@ require('../suite')(function (useRedis, useMongo) { }); it('returns correct number when using a created time from yesterday and expires in 2 hours', function (done) { + var hour = new Date(Date.now() + 2 * 60 * 60 * 1000).getHours(); var config = { @@ -606,66 +850,6 @@ require('../suite')(function (useRedis, useMongo) { }); }); - describe('Memory', function () { - - it('returns error when cache started twice', function (done) { - - var config = { - expiresIn: 50000, - segment: 'test' - }; - var client = new Cache.Client(Defaults.cache('memory')); - client.start(function (err) { - - expect(err).to.exist; - done(); - }); - }); - - it('returns error on missing segment name', function (done) { - - var config = { - expiresIn: 50000, - segment: '' - }; - var fn = function () { - var client = new Cache.Client(Defaults.cache('memory')); - var cache = new Cache.Policy(config, client); - }; - expect(fn).to.throw(Error); - done(); - }); - - it('returns error on bad segment name', function (done) { - - var config = { - expiresIn: 50000, - segment: 'a\0b' - }; - var fn = function () { - var client = new Cache.Client(Defaults.cache('memory')); - var cache = new Cache.Policy(config, client); - }; - expect(fn).to.throw(Error); - done(); - }); - - it('returns error when cache item dropped while stopped', function (done) { - - var config = { - expiresIn: 50000, - segment: 'test' - }; - var client = new Cache.Client(Defaults.cache('memory')); - client.stop(); - client.drop('a', function (err) { - - expect(err).to.exist; - done(); - }); - }); - }); - describe('Stale', function () { before(function() { @@ -875,3 +1059,4 @@ require('../suite')(function (useRedis, useMongo) { }); }); }); + diff --git a/test/unit/log.js b/test/unit/log.js index 1756a7e65..7abaff57c 100755 --- a/test/unit/log.js +++ b/test/unit/log.js @@ -20,11 +20,9 @@ describe('Log', function () { describe('#event', function () { - it('fires an event with the passed in tags', function(done) { - var env = process.env.NODE_ENV; - var tags = ['hello']; - process.env.NODE_ENV = 'nottatest'; + it('fires an event with the passed in tags', function (done) { + var tags = ['hello']; Log.once('log', function(event) { expect(event).to.exist; expect(event.tags).to.exist; @@ -32,19 +30,17 @@ describe('Log', function () { done(); }); Log.event(tags, null, Date.now()); - - process.env.NODE_ENV = env; }); it('outputs to stdout if no listeners exist', function(done) { var env = process.env.NODE_ENV; - var tags = ['hello']; process.env.NODE_ENV = 'nottatest'; var unhookStdout = stdoutIntercept(function(output) { expect(output).to.contain('hello'); }); + var tags = ['hello']; Log.event(tags, null, Date.now()); process.env.NODE_ENV = env; @@ -65,7 +61,7 @@ describe('Log', function () { expect(output).to.contain('tag1'); }); - Log.print(event, false); + Log.print(event, false, true); unhookStdout(); done(); }); @@ -81,7 +77,7 @@ describe('Log', function () { expect(output).to.contain('JSON Error'); }); - Log.print(event, false); + Log.print(event, false, true); unhookStdout(); done(); }); diff --git a/test/unit/mongo.js b/test/unit/mongo.js old mode 100644 new mode 100755 index 26ff87963..38895b91b --- a/test/unit/mongo.js +++ b/test/unit/mongo.js @@ -63,7 +63,7 @@ require('../suite')(function (useRedis, useMongo) { mongo.start(function(err, result) { expect(err).to.not.exist; expect(result).to.not.exist; - expect(mongo.isReady).to.be.true; + expect(mongo.isReady()).to.be.true; done(); }); }); diff --git a/test/unit/redis.js b/test/unit/redis.js old mode 100644 new mode 100755 index bd83cb25b..c3f546c8f --- a/test/unit/redis.js +++ b/test/unit/redis.js @@ -36,23 +36,6 @@ require('../suite')(function (useRedis, useMongo) { done(); }); }); - - it('returns an error when the connection is already started', function(done) { - var options = { - host: '127.0.0.1', - port: 6379 - }; - - var redis = new Redis.Connection(options); - - redis.start(function() { - redis.start(function(err) { - expect(err).to.exist; - expect(err).to.be.instanceOf(Error); - done(); - }); - }); - }); }); describe('#validateSegmentName', function() {