New Case Study:See how Anthropic automated 95% of dependency reviews with Socket.Learn More
Socket
Sign inDemoInstall
Socket

catbox

Package Overview
Dependencies
Maintainers
4
Versions
67
Alerts
File Explorer

Advanced tools

Socket logo

Install Socket

Detect and block malicious and high-risk dependencies

Install

catbox - npm Package Compare versions

Comparing version 3.1.0 to 3.2.0

CONTRIBUTING.md

20

examples/policy.js

@@ -27,13 +27,3 @@ // After starting this example load http://localhost:8080 and hit refresh, you will notice that it loads the response from cache for the first 5 seconds and then reloads the cache. Look at the console to see it setting and getting items from cache.

var logFunc = function (item) {
console.log(item);
};
var generateFunc = function (next) {
next(null, 'my example');
};
internals.policy.getOrGenerate('myExample', logFunc, generateFunc, callback);
internals.policy.get('myExample', callback);
};

@@ -49,3 +39,9 @@

var policyOptions = {
expiresIn: 5000
expiresIn: 5000,
generateFunc: function (id, next) {
var item = 'example';
console.log(item);
return next(null, item);
}
};

@@ -52,0 +48,0 @@

241

lib/policy.js

@@ -19,2 +19,3 @@ // Load modules

this.rule = internals.Policy.compile(options, !!cache);
this._pendings = {}; // id -> [callbacks]

@@ -31,16 +32,21 @@ if (cache) {

internals.Policy.prototype.get = function (id, callback) {
internals.Policy.prototype.get = function (key, callback) { // key: string or { id: 'id' }
var self = this;
if (!this._cache) {
return callback(null, null);
// Check if request is already pending
var id = (key && typeof key === 'object') ? key.id : key;
if (this._pendings[id]) {
this._pendings[id].push(callback);
return;
}
this._cache.get({ segment: this._segment, id: id }, function (err, cached) {
this._pendings[id] = [callback];
if (err) {
return callback(err);
}
// Lookup in cache
var timer = new Hoek.Timer();
this._get(id, function (err, cached) {
if (cached) {

@@ -50,64 +56,12 @@ cached.isStale = (self.rule.staleIn ? (Date.now() - cached.stored) >= self.rule.staleIn : false);

return callback(null, cached);
});
};
// No generate method
internals.Policy.prototype.set = function (id, value, ttl, callback) {
callback = callback || Hoek.ignore;
if (!this._cache) {
return callback(null);
}
ttl = ttl || internals.Policy.ttl(this.rule);
this._cache.set({ segment: this._segment, id: id }, value, ttl, callback);
};
internals.Policy.prototype.drop = function (id, callback) {
callback = callback || Hoek.ignore;
if (!this._cache) {
return callback(null);
}
this._cache.drop({ segment: this._segment, id: id }, callback);
};
internals.Policy.prototype.ttl = function (created) {
return internals.Policy.ttl(this.rule, created);
};
internals.Policy.prototype.getOrGenerate = function (id, generateFunc, callback) {
var self = this;
// Check if cache enabled
if (!this._cache) {
return self._validate(id, null, generateFunc, null, callback);
}
// Lookup in cache
var timer = new Hoek.Timer();
this.get(id, function (err, cached) {
// Error
if (err) {
report = err;
return self._validate(id, null, generateFunc, err, callback);
if (!self.rule.generateFunc) {
return self._finalize(id, err, cached); // Pass 'cached' as 'value' and omit other arguments for backwards compatibility
}
// Not found
// Error / Not found
if (!cached) {
return self._validate(id, null, generateFunc, { msec: timer.elapsed() }, callback);
if (err || !cached) {
return self._generate(id, key, null, { msec: timer.elapsed(), error: err }, callback);
}

@@ -124,3 +78,9 @@

return self._validate(id, cached, generateFunc, report, callback);
// Check if found and fresh
if (!cached.isStale) {
return self._finalize(id, null, cached.item, cached, report);
}
return self._generate(id, key, cached, report, callback);
});

@@ -130,18 +90,16 @@ };

internals.Policy.prototype._validate = function (id, cached, generateFunc, report, callback) {
internals.Policy.prototype._get = function (id, callback) {
var self = this;
if (!this._cache) {
return Hoek.nextTick(callback)(null, null);
}
// Check if found and fresh
this._cache.get({ segment: this._segment, id: id }, callback);
};
if (cached &&
!cached.isStale) {
return callback(null, cached.item, cached, report);
}
internals.Policy.prototype._generate = function (id, key, cached, report, callback) {
// Not in cache, or cache stale
var self = this;
callback = Hoek.once(callback); // Return only the first callback between stale timeout and generated fresh
if (cached &&

@@ -156,3 +114,3 @@ cached.isStale) {

return callback(null, cached.item, cached, report);
return self._finalize(id, null, cached.item, cached, report);
}, this.rule.staleTimeout);

@@ -167,3 +125,3 @@ }

return callback(Boom.serverTimeout(), null, null, report);
return self._finalize(id, Boom.serverTimeout(), null, null, report);
}, this.rule.generateTimeout);

@@ -174,3 +132,3 @@ }

generateFunc.call(null, function (err, value, ttl) {
this.rule.generateFunc.call(null, key, function (err, value, ttl) {

@@ -188,3 +146,3 @@ // Error or not cached

return callback(err, value, null, report); // Ignored if stale value already returned
return self._finalize(id, err, value, null, report); // Ignored if stale value already returned
});

@@ -194,11 +152,74 @@ };

internals.Policy.prototype._finalize = function (id, err, value, cached, report) {
var pendings = this._pendings[id];
if (!pendings) {
return;
}
delete this._pendings[id]; // Return only the first callback between stale timeout and generated fresh
for (var i = 0, il = pendings.length; i < il; ++i) {
pendings[i](err, value, cached, report);
}
};
internals.Policy.prototype.getOrGenerate = function (id, generateFunc, callback) { // For backwards compatibility
var self = this;
this.rule.generateFunc = function (id, next) {
self.rule.generateFunc = null;
return generateFunc(next);
};
return this.get(id, callback);
};
internals.Policy.prototype.set = function (key, value, ttl, callback) {
callback = callback || Hoek.ignore;
if (!this._cache) {
return callback(null);
}
ttl = ttl || internals.Policy.ttl(this.rule);
var id = (key && typeof key === 'object') ? key.id : key;
this._cache.set({ segment: this._segment, id: id }, value, ttl, callback);
};
internals.Policy.prototype.drop = function (id, callback) {
callback = callback || Hoek.ignore;
if (!this._cache) {
return callback(null);
}
this._cache.drop({ segment: this._segment, id: id }, callback);
};
internals.Policy.prototype.ttl = function (created) {
return internals.Policy.ttl(this.rule, created);
};
internals.Policy.compile = function (options, serverSide) {
/*
* {
* expiresIn: 30000,
* expiresAt: '13:00',
* staleIn: 20000,
* staleTimeout: 500,
* generateTimeout: 500
* }
{
expiresIn: 30000,
expiresAt: '13:00',
generateFunc: function (id, next) { next(err, result, ttl); }
generateTimeout: 500,
staleIn: 20000,
staleTimeout: 500
}
*/

@@ -222,2 +243,4 @@

Hoek.assert(!options.staleTimeout || !options.expiresIn || options.staleTimeout < (options.expiresIn - options.staleIn), 'staleTimeout must be less than the delta between expiresIn and staleIn');
// Hoek.assert(options.generateFunc || !options.generateTimeout, 'Rule cannot include generateTimeout without generateFunc'); // Disabled for backwards compatibility
Hoek.assert(!options.generateFunc || typeof options.generateFunc === 'function', 'generateFunc must be a function');

@@ -245,5 +268,15 @@ // Expiration

// generateTimeout
if (options.generateFunc) {
rule.generateFunc = options.generateFunc;
}
if (options.generateTimeout) { // Keep outside options.generateFunc condition for backwards compatibility
rule.generateTimeout = options.generateTimeout;
}
// Stale
if (options.staleIn) {
if (options.staleIn) { // Keep outside options.generateFunc condition for backwards compatibility
Hoek.assert(serverSide, 'Cannot use stale options without server-side caching');

@@ -254,8 +287,2 @@ rule.staleIn = options.staleIn;

// generateTimeout
if (options.generateTimeout) {
rule.generateTimeout = options.generateTimeout;
}
return rule;

@@ -265,5 +292,5 @@ };

internals.Policy.ttl = function (rule, created) {
internals.Policy.ttl = function (rule, created, now) {
var now = Date.now();
now = now || Date.now();
created = created || now;

@@ -277,24 +304,26 @@ var age = now - created;

if (rule.expiresIn) {
var ttl = rule.expiresIn - age;
return (ttl > 0 ? ttl : 0); // Can be negative
return Math.max(rule.expiresIn - age, 0);
}
if (rule.expiresAt) {
if (created !== now &&
now - created > internals.day) { // If the item was created more than a 24 hours ago
if (age > internals.day) { // If the item was created more than a 24 hours ago
return 0;
}
var expiresAt = new Date(created); // Assume everything expires in relation to now
var expiresAt = new Date(created); // Compare expiration time on the same day
expiresAt.setHours(rule.expiresAt.hours);
expiresAt.setMinutes(rule.expiresAt.minutes);
expiresAt.setSeconds(0);
expiresAt.setMilliseconds(0);
var expires = expiresAt.getTime();
var expiresIn = expiresAt.getTime() - created;
if (expiresIn <= 0) {
expiresIn += internals.day; // Time passed for today, move to tomorrow
if (expires <= created) {
expires += internals.day; // Move to tomorrow
}
return expiresIn - age;
if (now >= expires) { // Expired
return 0;
}
return expires - now;
}

@@ -301,0 +330,0 @@

{
"name": "catbox",
"description": "Multi-strategy object caching service",
"version": "3.1.0",
"version": "3.2.0",
"author": "Eran Hammer <eran@hammer.io> (http://hueniverse.com)",
"contributors": [
"Wyatt Preul <wpreul@gmail.com> (http://jsgeek.com)"
"Wyatt Preul <wpreul@gmail.com> (http://jsgeek.com)",
"Ben Acker <benacker@gmail.com>"
],

@@ -22,3 +23,3 @@ "repository": "git://github.com/hapijs/catbox",

"devDependencies": {
"lab": "3.x.x"
"lab": "4.x.x"
},

@@ -25,0 +26,0 @@ "scripts": {

@@ -8,3 +8,3 @@ ![catbox Logo](https://raw.github.com/hapijs/catbox/master/images/catbox.png)

Lead Maintainer: [Van Nguyen](https://github.com/thegoleffect)
Lead Maintainer: [Ben Acker](https://github.com/nvcexploder)

@@ -82,5 +82,13 @@ **catbox** is a multi-strategy key-value object store. It comes with extensions supporting a memory cache,

expire. Uses local time. Cannot be used together with `expiresIn`.
- `staleIn` - number of milliseconds to mark an item stored in cache as stale and reload it. Must be less than `expiresIn`.
- `generateFunc` - a function used to generate a new cache item if one is not found in the cache when calling `get()`. The method's
signature is `function(id, next)` where:
- `id` - the `id` string or object provided to the `get()` method.
- `next` - the method called when the new item is returned with the signature `function(err, value, ttl)` where:
- `err` - an error condition.
- `value` - the new value generated.
- `ttl` - the cache ttl value in milliseconds. Set to `0` to skip storing in the cache. Defaults to the cache global policy.
- `staleIn` - number of milliseconds to mark an item stored in cache as stale and attempt to regenerate it when `generateFunc` is
provided. Must be less than `expiresIn`.
- `staleTimeout` - number of milliseconds to wait before checking if an item is stale.
- `generateTimeout` - number of milliseconds to wait before returning a timeout error when the `getOrGenerate()` `generateFunc` function
- `generateTimeout` - number of milliseconds to wait before returning a timeout error when the `generateFunc` function
takes too long to return a value. When the value is eventually returned, it is stored in the cache for future requests.

@@ -95,6 +103,20 @@ - `cache` - a `Client` instance (which has already been started).

- `get(id, callback)` - retrieve an item from the cache where:
- `id` - the unique item identifier (within the policy segment).
- `callback` - a function with the signature `function(err, cached)` where `cached` is the object returned by the `client.get()` with
the additional `isStale` boolean key.
- `get(id, callback)` - retrieve an item from the cache. If the item is not found and the `generateFunc` method was provided, a new value
is generated, stored in the cache, and returned. Multiple concurrent requests are queued and processed once. The method arguments are:
- `id` - the unique item identifier (within the policy segment). Can be a string or an object with the required 'id' key.
- `callback` - the return function. The function signature is based on the `generateFunc` settings. If the `generateFunc` is not set,
the signature is `function(err, cached)`. Otherwise, the signature is `function(err, value, cached, report)` where:
- `err` - any errors encountered.
- `value` - the fetched or generated value.
- `cached` - `null` if a valid item was not found in the cache, or an object with the following keys:
- `item` - the cached `value`.
- `stored` - the timestamp when the item was stored in the cache.
- `ttl` - the cache ttl value for the record.
- `isStale` - `true` if the item is stale.
- `report` - an object with logging information about the generation operation containing the following keys (as relevant):
- `msec` - the cache lookup time in milliseconds.
- `stored` - the timestamp when the item was stored in the cache.
- `isStale` - `true` if the item is stale.
- `ttl` - the cache ttl value for the record.
- `error` - lookup error.
- `set(id, value, ttl, callback)` - store an item in the cache where:

@@ -110,14 +132,2 @@ - `id` - the unique item identifier (within the policy segment).

- `ttl(created)` - given a `created` timestamp in milliseconds, returns the time-to-live left based on the configured rules.
- `getOrGenerate(id, generateFunc, callback)` - get an item from the cache if found, otherwise calls the `generateFunc` to produce a new value
and stores it in the cache. This method applies the staleness rules. Its arguments are:
- `id` - the unique item identifier (within the policy segment).
- `generateFunc` - the function used to generate a new cache item if one is not found in the cache. The method's signature is
`function(err, value, ttl)` where:
- `err` - an error condition.
- `value` - the new value generated.
- `ttl` - the cache ttl value in milliseconds. Set to `0` to skip storing in the cache. Defaults to the cache global policy.
- `callback` - a function with the signature `function(err, value, cached, report)` where:
- `err` - any errors encountered.
- `value` - the fetched or generated value.
- `cached` - the `cached` object returned by `policy.get()` is the item was found in the cache.
- `report` - an object with logging information about the operation.

@@ -14,7 +14,8 @@ // Load modules

var lab = exports.lab = Lab.script();
var expect = Lab.expect;
var before = Lab.before;
var after = Lab.after;
var describe = Lab.experiment;
var it = Lab.test;
var before = lab.before;
var after = lab.after;
var describe = lab.experiment;
var it = lab.test;

@@ -21,0 +22,0 @@

@@ -15,7 +15,8 @@ // Load modules

var lab = exports.lab = Lab.script();
var expect = Lab.expect;
var before = Lab.before;
var after = Lab.after;
var describe = Lab.experiment;
var it = Lab.test;
var before = lab.before;
var after = lab.after;
var describe = lab.experiment;
var it = lab.test;

@@ -22,0 +23,0 @@

@@ -15,7 +15,6 @@ // Load modules

var lab = exports.lab = Lab.script();
var expect = Lab.expect;
var before = Lab.before;
var after = Lab.after;
var describe = Lab.experiment;
var it = Lab.test;
var describe = lab.experiment;
var it = lab.test;

@@ -28,3 +27,3 @@

var client = new Catbox.Client(Import);
var cache = new Catbox.Policy({ expiresIn: 1000 }, client, 'test');
var policy = new Catbox.Policy({ expiresIn: 1000 }, client, 'test');

@@ -35,7 +34,7 @@ client.start(function (err) {

cache.set('x', '123', null, function (err) {
policy.set('x', '123', null, function (err) {
expect(err).to.not.exist;
cache.get('x', function (err, result) {
policy.get('x', function (err, result) {

@@ -53,3 +52,3 @@ expect(err).to.not.exist;

var client = new Catbox.Client(Import);
var cache = new Catbox.Policy({}, client, 'test');
var policy = new Catbox.Policy({}, client, 'test');

@@ -60,6 +59,6 @@ client.start(function (err) {

cache.set('x', '123', null, function (err) {
policy.set('x', '123', null, function (err) {
expect(err).to.not.exist;
cache.get('x', function (err, result) {
policy.get('x', function (err, result) {

@@ -77,3 +76,3 @@ expect(err).to.not.exist;

var client = new Catbox.Client(Import);
var cache = new Catbox.Policy({}, client, 'test');
var policy = new Catbox.Policy({}, client, 'test');

@@ -84,6 +83,6 @@ client.start(function (err) {

cache.set('x', '123', 1000, function (err) {
policy.set('x', '123', 1000, function (err) {
expect(err).to.not.exist;
cache.get('x', function (err, result) {
policy.get('x', function (err, result) {

@@ -100,6 +99,5 @@ expect(err).to.not.exist;

var cache = new Catbox.Policy({ expiresIn: 1 });
var policy = new Catbox.Policy({ expiresIn: 1 });
var key = { id: 'x', segment: 'test' };
cache.get(key, function (err, result) {
policy.get('x', function (err, result) {

@@ -114,6 +112,5 @@ expect(err).to.not.exist;

var cache = new Catbox.Policy({ expiresIn: 1 });
var policy = new Catbox.Policy({ expiresIn: 1 });
var key = { id: 'x', segment: 'test' };
cache.set(key, 'y', 100, function (err) {
policy.set('x', 'y', 100, function (err) {

@@ -127,6 +124,5 @@ expect(err).to.not.exist;

var cache = new Catbox.Policy({ expiresIn: 1 });
var policy = new Catbox.Policy({ expiresIn: 1 });
var key = { id: 'x', segment: 'test' };
cache.drop(key, function (err) {
policy.drop('x', function (err) {

@@ -161,2 +157,49 @@ expect(err).to.not.exist;

it('returns cached item using object id', function (done) {
var client = new Catbox.Client(Import);
var policy = new Catbox.Policy({ expiresIn: 1000 }, client, 'test');
client.start(function (err) {
expect(err).to.not.exist;
policy.set({ id: 'x' }, '123', null, function (err) {
expect(err).to.not.exist;
policy.get({ id: 'x' }, function (err, result) {
expect(err).to.not.exist;
expect(result.item).to.equal('123');
done();
});
});
});
});
it('returns error on null id', function (done) {
var client = new Catbox.Client(Import);
var policy = new Catbox.Policy({ expiresIn: 1000 }, client, 'test');
client.start(function (err) {
expect(err).to.not.exist;
policy.set(null, '123', null, function (err) {
expect(err).to.exist;
expect(err.message).to.equal('Invalid key');
policy.get(null, function (err, result) {
expect(err).to.exist;
expect(err.message).to.equal('Invalid key');
done();
});
});
});
});
it('passes an error to the callback when an error occurs getting the item', function (done) {

@@ -189,3 +232,3 @@

policy.get({ id: 'test1', segment: 'test2' }, function (err, result) {
policy.get('test1', function (err, result) {

@@ -228,3 +271,3 @@ expect(err).to.be.instanceOf(Error);

policy.get({ id: 'test1', segment: 'test2' }, function (err, result) {
policy.get('test1', function (err, result) {

@@ -236,46 +279,498 @@ expect(result.item).to.equal('item');

});
});
describe('#getOrGenerate', function () {
describe('generate', function () {
it('returns falsey items', function (done) {
it('returns falsey items', function (done) {
var engine = {
start: function (callback) {
var engine = {
start: function (callback) {
callback();
},
isReady: function () {
callback();
},
isReady: function () {
return true;
},
get: function (key, callback) {
return true;
},
get: function (key, callback) {
callback(null, {
stored: false,
item: false
callback(null, {
stored: false,
item: false
});
},
validateSegmentName: function () {
return null;
}
};
var policyConfig = {
expiresIn: 50000,
generateFunc: function (id, next) {
return next(null, false);
}
};
var client = new Catbox.Client(engine);
var policy = new Catbox.Policy(policyConfig, client, 'test');
policy.get('test1', function (err, item) {
expect(err).to.equal(null);
expect(item).to.equal(false);
done();
});
});
it('bypasses cache when not configured', function (done) {
var policy = new Catbox.Policy({
expiresIn: 1,
generateFunc: function (id, next) {
return next(null, 'new result');
}
});
policy.get('test', function (err, value, cached) {
expect(err).to.not.exist;
expect(value).to.equal('new result');
expect(cached).to.not.exist;
done();
});
});
it('returns the processed cached item', function (done) {
var rule = {
expiresIn: 100,
staleIn: 20,
staleTimeout: 5,
generateFunc: function (id, next) {
return next(null, { gen: ++gen });
}
};
var client = new Catbox.Client(Import, { partition: 'test-partition' });
var policy = new Catbox.Policy(rule, client, 'test-segment');
var gen = 0;
client.start(function () {
policy.get('test', function (err, value, cached) {
expect(value.gen).to.equal(1);
done();
});
},
validateSegmentName: function () {
});
});
return null;
}
};
var policyConfig = {
expiresIn: 50000
};
it('returns the processed cached item after cache error', function (done) {
function generateFunc(next) {
next(null, false);
}
var rule = {
expiresIn: 100,
staleIn: 20,
staleTimeout: 5,
generateFunc: function (id, next) {
var client = new Catbox.Client(engine);
var policy = new Catbox.Policy(policyConfig, client, 'test');
return next(null, { gen: ++gen });
}
};
policy.getOrGenerate('test1', generateFunc, function (err, item) {
var client = new Catbox.Client(Import, { partition: 'test-partition' });
client.get = function (key, callback) { callback(new Error('bad client')); };
var policy = new Catbox.Policy(rule, client, 'test-segment');
expect(err).to.equal(null);
expect(item).to.equal(false);
done();
var gen = 0;
client.start(function () {
policy.get('test', function (err, value, cached) {
expect(value.gen).to.equal(1);
done();
});
});
});
it('returns the processed cached item using manual ttl', function (done) {
var rule = {
expiresIn: 26,
staleIn: 20,
staleTimeout: 5,
generateFunc: function (id, next) {
setTimeout(function () {
return next(null, { gen: ++gen }, 100);
}, 6);
}
};
var client = new Catbox.Client(Import, { partition: 'test-partition' });
var policy = new Catbox.Policy(rule, client, 'test-segment');
var gen = 0;
client.start(function () {
policy.get('test', function (err, value1, cached) {
expect(value1.gen).to.equal(1); // Fresh
setTimeout(function () {
policy.get('test', function (err, value2, cached) {
expect(value2.gen).to.equal(1); // Stale
done();
});
}, 27);
});
});
});
it('returns stale object then fresh object based on timing', function (done) {
var rule = {
expiresIn: 100,
staleIn: 20,
staleTimeout: 5,
generateFunc: function (id, next) {
setTimeout(function () {
return next(null, { gen: ++gen }, 100);
}, 6);
}
};
var client = new Catbox.Client(Import, { partition: 'test-partition' });
var policy = new Catbox.Policy(rule, client, 'test-segment');
var gen = 0;
client.start(function () {
policy.get('test', function (err, value1, cached) {
expect(value1.gen).to.equal(1); // Fresh
setTimeout(function () {
policy.get('test', function (err, value2, cached) {
expect(value2.gen).to.equal(1); // Stale
setTimeout(function () {
policy.get('test', function (err, value3, cached) {
expect(value3.gen).to.equal(2); // Fresh
done();
});
}, 3);
});
}, 21);
});
});
});
it('returns stale object then invalidate cache on error', function (done) {
var rule = {
expiresIn: 100,
staleIn: 20,
staleTimeout: 5,
generateFunc: function (id, next) {
++gen;
setTimeout(function () {
if (gen !== 2) {
return next(null, { gen: gen });
}
return next(new Error());
}, 6);
}
};
var client = new Catbox.Client(Import, { partition: 'test-partition' });
var policy = new Catbox.Policy(rule, client, 'test-segment');
var gen = 0;
client.start(function () {
policy.get('test', function (err, value1, cached) {
expect(value1.gen).to.equal(1); // Fresh
setTimeout(function () {
policy.get('test', function (err, value2, cached) {
// Generates a new one in background which will produce Error and clear the cache
expect(value2.gen).to.equal(1); // Stale
setTimeout(function () {
policy.get('test', function (err, value3, cached) {
expect(value3.gen).to.equal(3); // Fresh
done();
});
}, 3);
});
}, 21);
});
});
});
it('returns fresh objects', function (done) {
var rule = {
expiresIn: 100,
staleIn: 20,
staleTimeout: 10,
generateFunc: function (id, next) {
return next(null, { gen: ++gen });
}
};
var client = new Catbox.Client(Import, { partition: 'test-partition' });
var policy = new Catbox.Policy(rule, client, 'test-segment');
var gen = 0;
client.start(function () {
policy.get('test', function (err, value1, cached) {
expect(value1.gen).to.equal(1); // Fresh
setTimeout(function () {
policy.get('test', function (err, value2, cached) {
expect(value2.gen).to.equal(2); // Fresh
setTimeout(function () {
policy.get('test', function (err, value3, cached) {
expect(value3.gen).to.equal(2); // Fresh
done();
});
}, 1);
});
}, 21);
});
});
});
it('returns error when generated within stale timeout', function (done) {
var rule = {
expiresIn: 30,
staleIn: 20,
staleTimeout: 5,
generateFunc: function (id, next) {
++gen;
if (gen !== 2) {
return next(null, { gen: gen });
}
return next(new Error());
}
};
var client = new Catbox.Client(Import, { partition: 'test-partition' });
var policy = new Catbox.Policy(rule, client, 'test-segment');
var gen = 0;
client.start(function () {
policy.get('test', function (err, value1, cached) {
expect(value1.gen).to.equal(1); // Fresh
setTimeout(function () {
policy.get('test', function (err, value2, cached) {
// Generates a new one which will produce Error
expect(err).to.be.instanceof(Error); // Stale
done();
});
}, 21);
});
});
});
it('returns new object when stale has less than staleTimeout time left', function (done) {
var rule = {
expiresIn: 25,
staleIn: 15,
staleTimeout: 5,
generateFunc: function (id, next) {
return next(null, { gen: ++gen });
}
};
var client = new Catbox.Client(Import, { partition: 'test-partition' });
var policy = new Catbox.Policy(rule, client, 'test-segment');
var gen = 0;
client.start(function () {
policy.get('test', function (err, value1, cached) {
expect(value1.gen).to.equal(1); // Fresh
setTimeout(function () {
policy.get('test', function (err, value2, cached) {
expect(value2.gen).to.equal(1); // Fresh
setTimeout(function () {
policy.get('test', function (err, value3, cached) {
expect(value3.gen).to.equal(2); // Fresh
done();
});
}, 11);
});
}, 10);
});
});
});
it('invalidates cache on error without stale', function (done) {
var rule = {
expiresIn: 20,
staleIn: 5,
staleTimeout: 5,
generateFunc: function (id, next) {
++gen;
if (gen === 2) {
return next(new Error());
}
return next(null, { gen: gen });
}
};
var client = new Catbox.Client(Import, { partition: 'test-partition' });
var policy = new Catbox.Policy(rule, client, 'test-segment');
var gen = 0;
client.start(function () {
policy.get('test', function (err, value1, cached) {
expect(value1.gen).to.equal(1); // Fresh
setTimeout(function () {
policy.get('test', function (err, value2, cached) {
expect(err).to.exist;
policy._get('test', function (err, value3) {
expect(value3).to.equal(null);
done();
});
});
}, 8);
});
});
});
it('returns timeout error when generate takes too long', function (done) {
var rule = {
expiresIn: 10,
generateTimeout: 5,
generateFunc: function (id, next) {
setTimeout(function () {
return next(null, { gen: ++gen });
}, 6);
}
};
var client = new Catbox.Client(Import, { partition: 'test-partition' });
var policy = new Catbox.Policy(rule, client, 'test-segment');
var gen = 0;
client.start(function () {
policy.get('test', function (err, value1, cached) {
expect(err.output.statusCode).to.equal(503);
setTimeout(function () {
policy.get('test', function (err, value2, cached) {
expect(value2.gen).to.equal(1);
setTimeout(function () {
policy.get('test', function (err, value3, cached) {
expect(err.output.statusCode).to.equal(503);
done();
});
}, 10);
});
}, 2);
});
});
});
it('queues requests while pending', function (done) {
var gen = 0;
var rule = {
expiresIn: 100,
generateFunc: function (id, next) {
return next(null, { gen: ++gen });
}
};
var client = new Catbox.Client(Import, { partition: 'test-partition' });
var policy = new Catbox.Policy(rule, client, 'test-segment');
client.start(function () {
var result = null;
var compare = function (err, value, cached) {
if (!result) {
result = value;
return;
}
expect(result).to.equal(value);
done();
};
policy.get('test', compare);
policy.get('test', compare);
});
});
});

@@ -349,5 +844,85 @@ });

var result = policy.ttl(Date.now() - 10000);
expect(result).to.be.within(39999, 40001); // There can occassionally be a 1ms difference
expect(result).to.be.within(39999, 40001); // There can occasionally be a 1ms difference
done();
});
it('returns expired when created in the future', function (done) {
var config = {
expiresAt: '10:00'
};
var rules = new Catbox.Policy.compile(config);
var created = new Date('Sat Sep 06 2014 13:00:00').getTime();
var now = new Date('Sat Sep 06 2014 12:00:00').getTime();
var ttl = Catbox.Policy.ttl(rules, created, now);
expect(ttl).to.equal(0);
done();
});
it('returns expired on c-e-n same day', function (done) {
var config = {
expiresAt: '10:00'
};
var rules = new Catbox.Policy.compile(config);
var created = new Date('Sat Sep 06 2014 9:00:00').getTime();
var now = new Date('Sat Sep 06 2014 11:00:00').getTime();
var ttl = Catbox.Policy.ttl(rules, created, now);
expect(ttl).to.equal(0);
done();
});
it('returns expired on c-(midnight)-e-n', function (done) {
var config = {
expiresAt: '10:00'
};
var rules = new Catbox.Policy.compile(config);
var created = new Date('Sat Sep 06 2014 11:00:00').getTime();
var now = new Date('Sat Sep 07 2014 10:00:01').getTime();
var ttl = Catbox.Policy.ttl(rules, created, now);
expect(ttl).to.equal(0);
done();
});
it('returns ttl on c-n-e same day', function (done) {
var config = {
expiresAt: '10:00'
};
var rules = new Catbox.Policy.compile(config);
var created = new Date('Sat Sep 06 2014 9:00:00').getTime();
var now = new Date('Sat Sep 06 2014 9:30:00').getTime();
var ttl = Catbox.Policy.ttl(rules, created, now);
expect(ttl).to.equal(30 * 60 * 1000);
done();
});
it('returns ttl on c-(midnight)-n-e', function (done) {
var config = {
expiresAt: '10:00'
};
var rules = new Catbox.Policy.compile(config);
var created = new Date('Sat Sep 06 2014 11:00:00').getTime();
var now = new Date('Sat Sep 07 2014 9:00:00').getTime();
var ttl = Catbox.Policy.ttl(rules, created, now);
expect(ttl).to.equal(60 * 60 * 1000);
done();
});
});

@@ -386,3 +961,3 @@

var client = new Catbox.Client(Import);
var cache = new Catbox.Policy(config, client);
var policy = new Catbox.Policy(config, client);
};

@@ -559,3 +1134,3 @@

var cache = new Catbox.Policy(config);
var policy = new Catbox.Policy(config);
};

@@ -851,3 +1426,3 @@

describe('getOrGenerate', function () {
describe('#getOrGenerate', function () {

@@ -1274,1 +1849,2 @@ it('bypasses cache when not configured', function (done) {

SocketSocket SOC 2 Logo

Product

  • Package Alerts
  • Integrations
  • Docs
  • Pricing
  • FAQ
  • Roadmap
  • Changelog

Packages

npm

Stay in touch

Get open source security insights delivered straight into your inbox.


  • Terms
  • Privacy
  • Security

Made with ⚡️ by Socket Inc