diff --git a/lib/multi_caching.js b/lib/multi_caching.js index b384a50..d128bf3 100644 --- a/lib/multi_caching.js +++ b/lib/multi_caching.js @@ -23,7 +23,7 @@ var multiCaching = function(caches) { async.eachSeries(caches, function(cache, next) { var callback = function(err, result) { if (err) { - return cb(err); + return next(err); } if (result) { // break out of async loop. @@ -31,8 +31,9 @@ var multiCaching = function(caches) { } i += 1; - next(err); + next(); }; + if (typeof options === 'object') { cache.store.get(key, options, callback); } else { @@ -43,10 +44,10 @@ var multiCaching = function(caches) { function setInMultipleCaches(caches, opts, cb) { async.each(caches, function(cache, next) { - if (typeof opts.options !== 'object') { - cache.store.set(opts.key, opts.value, opts.ttl, next); - } else { + if (typeof opts.options === 'object') { cache.store.set(opts.key, opts.value, opts.options, next); + } else { + cache.store.set(opts.key, opts.value, opts.ttl, next); } }, cb); } @@ -96,6 +97,20 @@ var multiCaching = function(caches) { options = undefined; } + function getOptsForSet(result) { + var opts = { + key: key, + value: result, + options: options + }; + + if (typeof options !== 'object') { + opts.ttl = options; + } + + return opts; + } + var hasKey = callbackFiller.has(key); callbackFiller.add(key, {cb: cb, domain: process.domain}); if (hasKey) { return; } @@ -105,45 +120,26 @@ var multiCaching = function(caches) { return callbackFiller.fill(key, err); } else if (result) { var cachesToUpdate = caches.slice(0, index); - var opts = { - key: key, - value: result, - options: options - }; - - if (typeof options !== 'object') { - opts.ttl = options; - } + var opts = getOptsForSet(result); setInMultipleCaches(cachesToUpdate, opts, function(err) { callbackFiller.fill(key, err, result); }); } else { domain - .create() - .on('error', function(err) { - callbackFiller.fill(key, err); - }) - .bind(work)(function(err, data) { + .create() + .on('error', function(err) { + callbackFiller.fill(key, err); + }) + .bind(work)(function(err, data) { if (err) { - callbackFiller.fill(key, err); - return; - } - var opts = { - key: key, - value: data, - options: options - }; - - if (typeof options !== 'object') { - opts.ttl = options; + return callbackFiller.fill(key, err); } + + var opts = getOptsForSet(data); + setInMultipleCaches(caches, opts, function(err) { - if (err) { - callbackFiller.fill(key, err); - } else { - callbackFiller.fill(key, null, data); - } + callbackFiller.fill(key, err, data); }); }); } diff --git a/test/multi_caching.unit.js b/test/multi_caching.unit.js index ce24e19..a664ef0 100644 --- a/test/multi_caching.unit.js +++ b/test/multi_caching.unit.js @@ -47,7 +47,9 @@ describe("multiCaching", function() { it("lets us set data in all caches", function(done) { multiCache.set(key, value, ttl, function(err) { checkErr(err); + memoryCache.get(key, function(err, result) { + checkErr(err); assert.equal(result, value); memoryCache2.get(key, function(err, result) { @@ -68,8 +70,11 @@ describe("multiCaching", function() { multiCache.set(key, value, ttl); setTimeout(function() { multiCache.get(key, function(err, result) { + checkErr(err); assert.equal(result, value); + memoryCache.get(key, function(err, result) { + checkErr(err); assert.equal(result, value); memoryCache2.get(key, function(err, result) { @@ -91,8 +96,11 @@ describe("multiCaching", function() { multiCache.set(key, value); setTimeout(function() { multiCache.get(key, function(err, result) { + checkErr(err); assert.equal(result, value); + memoryCache.get(key, function(err, result) { + checkErr(err); assert.equal(result, value); memoryCache2.get(key, function(err, result) { @@ -159,6 +167,7 @@ describe("multiCaching", function() { setTimeout(function() { memoryCache.get(key, function(err, result) { + checkErr(err); assert.ok(!result); memoryCache2.get(key, function(err, result) { @@ -263,6 +272,32 @@ describe("multiCaching", function() { }); }); }); + + context("when a cache store calls back with an error", function() { + var fakeError; + var memoryStoreStub; + + beforeEach(function() { + memoryStoreStub = memoryStore.create({ttl: ttl}); + sinon.stub(memoryStore, 'create').returns(memoryStoreStub); + memoryCache = caching({store: 'memory', ttl: ttl}); + multiCache = multiCaching([memoryCache]); + fakeError = new Error(support.random.string()); + sinon.stub(memoryStoreStub, 'get').yields(fakeError); + }); + + afterEach(function() { + memoryStore.create.restore(); + }); + + it("bubbles up errors from caches", function(done) { + multiCache.getAndPassUp(key, function(err) { + assert.ok(memoryStoreStub.get.called); + assert.equal(err, fakeError); + done(); + }); + }); + }); }); }); @@ -281,7 +316,7 @@ describe("multiCaching", function() { memoryCache3.store.set.restore(); }); - it('when a ttl is passed in', function(done) { + it('when a ttl number is passed in', function(done) { multiCache.wrap(key, function(cb) { methods.getWidget(name, cb); }, ttl, function(err, widget) { @@ -292,6 +327,17 @@ describe("multiCaching", function() { }); }); + it('when a ttl option is passed in', function(done) { + multiCache.wrap(key, function(cb) { + methods.getWidget(name, cb); + }, {ttl: ttl}, function(err, widget) { + checkErr(err); + assert.deepEqual(widget, {name: name}); + sinon.assert.calledWith(memoryCache3.store.set, key, {name: name}, {ttl: ttl}); + done(); + }); + }); + it('when a ttl is not passed in', function(done) { multiCache.wrap(key, function(cb) { methods.getWidget(name, cb);