promisesds
Version:
ES6 Promises data structures and utils
405 lines (381 loc) • 11.2 kB
JavaScript
var PromiseCache = require('../src/promiseCache');
var QUnit = require('qunitjs');
QUnit.config.autorun = false;
module.exports = QUnit;
/**
* Aux function to emulate jQuery deferred functionality
* @return {Object} Object with resolve, reject, then methods and a promise property
*/
var deferred = function(){
var dfr;
var promise = new Promise(function(resolve, reject){
dfr = {
resolve: resolve,
reject: reject
};
});
dfr.promise = promise;
return dfr;
};
(function (QUnit) {
"use strict";
QUnit.module('Basic');
QUnit.test("set/get", function (assert) {
var promise = Promise.resolve();
assert.equal((new PromiseCache({
'first': promise
})).get('first'), promise, 'set -> get returns same promise');
assert.equal((new PromiseCache()).get('first'), undefined, 'not set key get returns undefined');
});
QUnit.test("change set promise", function (assert) {
var dfr1 = Promise.resolve();
var dfr2 = Promise.resolve();
var cache = new PromiseCache({
'first': dfr1
});
assert.strictEqual(cache.get('first'), dfr1, 'first promise match');
cache.set('first', dfr2);
assert.strictEqual(cache.get('first'), dfr2, 'second promise match');
});
QUnit.test("remove", function (assert) {
var dfr = Promise.resolve();
var cache = new PromiseCache({
'first': dfr
});
assert.strictEqual(cache.remove('first'), dfr, 'remove returns promise');
assert.strictEqual(cache.get('first'), undefined, 'key is no longer in cache after removed');
assert.strictEqual(cache.remove('second'), undefined, 'not set key returns undefined when removed');
});
QUnit.test("promises method", function (assert) {
var dfr1 = Promise.resolve();;
var dfr2 = Promise.resolve();;
var promises = {
'first': dfr1,
'second': dfr2,
'third': dfr1
};
var cache = new PromiseCache(promises);
var cached = cache.promises();
assert.strictEqual(cached.first, promises.first, '1 promises method returns all promises in cache');
assert.strictEqual(cached.second, promises.second, '2 promises method returns all promises in cache');
assert.strictEqual(cached.third, promises.third, '3 promises method returns all promises in cache');
});
QUnit.module('Settings');
QUnit.test("capacity and evict initialization", function (assert) {
assert.expect(3);
assert.throws(function () {
new PromiseCache({}, {
capacity: 100
}, Error, 'capacity requires eviction method');
});
(new PromiseCache({}, {
capacity: 100,
eviction: {
evict: function () {
assert.ok(true, 'evict called');
}
}
})).evict();
new PromiseCache({}, {
capacity: 100,
eviction: 'lru'
});
assert.ok(true, 'algorithm does not throw');
});
QUnit.test("discarded", function (assert) {
assert.expect(5);
var dfr = Promise.resolve();
(new PromiseCache({
'first': dfr
}, {
discarded: function (key, promise) {
assert.strictEqual(key, 'first', 'discarded key ok');
assert.strictEqual(promise, dfr, 'discarded promise ok');
}
})).remove('first');
var cache = new PromiseCache(null, {
discarded: function () {
throw new Error('I should be overrided');
}
});
cache.set('first', dfr, {
discarded: function (key, promise) {
assert.strictEqual(key, 'first', 'discarded key ok');
assert.strictEqual(promise, dfr, 'discarded promise ok');
}
});
cache.remove('first');
cache.set('first', dfr);
assert.throws(function () {
cache.remove('first');
});
});
QUnit.asyncTest("promise fail interception", function (assert) {
assert.expect(6);
var dfr = deferred();
var dfr2 = Promise.reject();
var dfr3 = deferred();
var cache = new PromiseCache({
'first': dfr.promise,
'second': dfr2
}, {
fail: function (deferred, key, promise) {
assert.ok(true, 'fail called');
if (key === 'first') {
assert.strictEqual(promise, dfr.promise, 'fail promise/key ok');
}
deferred.resolve();
}
});
dfr.reject();
cache.get('first').then(function () {
assert.ok(true, 'resolved');
cache.set('third', dfr3.promise, {
fail: function () {
assert.ok(true, 'override fail ok');
QUnit.start();
}
});
dfr3.reject();
}, function () {
assert.ok(false, 'never called');
});
cache.get('second').then(function () {
assert.ok(true, 'resolved');
});
});
QUnit.asyncTest("expireTime method", function (assert) {
assert.expect(4);
var promise = new Promise(function(){});
var cache = new PromiseCache({
'first': promise
}, {
expireTime: 1,
discarded: function (key) {
assert.ok(true, key + ' expired');
}
});
cache.set('second', promise);
var millis = Date.now();
cache.set('third', promise, {
expireTime: 10,
discarded: function () {
var elapsed = Date.now() - millis;
//8 for tolerance
assert.ok(elapsed > 8, 'third expireTime override expected >= 10, elapsed: ' + elapsed);
QUnit.start();
}
});
cache.set('fourth', promise, {
expireTime: 5,
discarded: function () {
var elapsed = Date.now() - millis;
//8 for tolerance
assert.ok(elapsed < 8, 'fourth deleted before expire expected immediate removal, elapsed: ' + elapsed);
}
});
cache.remove('fourth');
});
QUnit.test("eviction methods", function (assert) {
assert.expect(5);
var pro = Promise.resolve();
var cache = new PromiseCache(null, {
eviction: {
init: function (cache, promises, options) {
var check = cache.get && options.eviction && promises === null;
assert.ok(check, 'check init parameters');
},
set: function (key, promiseObj, promise, options) {
var check = key === 'first' && promise === pro && promiseObj.promise === pro && options.custom;
assert.ok(check, 'check set parameters');
},
get: function (key, promise) {
var check = key === 'first' && promise.promise === pro;
assert.ok(check, 'check get parameters');
},
evict: function (nEvicted) {
var check = nEvicted === 3;
assert.ok(check, 'check evict parameters');
},
remove: function (key, promise) {
var check = !cache.promises().first && key === 'first' && promise.promise === pro;
assert.ok(check, 'check remove key already removed and parameters');
}
}
});
cache.set('first', pro, {
custom: true
});
cache.get('first');
cache.get('none'); //no method called
cache.evict(3);
cache.remove('first');
});
QUnit.module('eviction algorithms');
var testCache = function () {
return {
promises: {
0: Promise.resolve(),
1: Promise.resolve(),
2: Promise.resolve(),
3: Promise.resolve()
},
options: {
capacity: 2
}
};
};
var getSequence = function(cache, getsArray){
getsArray.forEach(key => cache.get(key));
};
QUnit.test("LRU get", function (assert) {
var ch = testCache();
ch.options.eviction = 'lru';
ch.options.capacity = 10;
var cache = new PromiseCache(ch.promises, ch.options);
assert.strictEqual(cache._promises[0].lru, 0, 'After set promise lru 0');
cache.get(0);
assert.strictEqual(cache._promises[0].lru, 1, 'After get promise lru 1');
cache.get(1);
assert.strictEqual(cache._promises[1].lru, 2, 'After other get promise lru 2');
});
QUnit.test("LRU eviction", function (assert) {
assert.expect(6);
var ch = testCache();
var order = 0;
ch.options.discarded = function (key) {
switch (order) {
case 0:
assert.equal(key, 1, 'first evicted 1');
order++;
break;
case 1:
assert.equal(key, 2, 'second evicted 2');
order++;
break;
case 2:
assert.equal(key, 0, 'third evicted 0');
order++;
break;
}
};
ch.options.eviction = 'lru';
var cache = new PromiseCache(null, ch.options);
cache.set(0, ch.promises[0]);
cache.set(1, ch.promises[1]);
getSequence(cache, [0,1,0]);
cache.set(2, ch.promises[2]);
cache.set(3, ch.promises[3]);
cache.get(3);
cache.set(1, ch.promises[1]);
order = 0;
var ch2 = testCache();
ch2.options.discarded = ch.options.discarded;
ch2.options.evictRate = 3;
ch2.options.capacity = 4;
ch2.options.eviction = 'lru';
var cache2 = new PromiseCache(ch2.promises, ch2.options);
getSequence(cache2, [0,1,2,1,3,2,1,3,3]);
cache2.set(5, ch.promises[1]);
});
QUnit.test("MRU get", function (assert) {
var ch = testCache();
ch.options.eviction = 'mru';
ch.options.capacity = 10;
var cache = new PromiseCache(ch.promises, ch.options);
assert.strictEqual(cache._promises[0].mru, 0, 'After set promise mru 0');
cache.get(0);
assert.strictEqual(cache._promises[0].mru, 1, 'After get promise mru 1');
});
QUnit.test("MRU eviction", function (assert) {
assert.expect(6);
var ch = testCache();
var order = 0;
ch.options.discarded = function (key) {
switch (order) {
case 0:
assert.equal(key, 0, 'first evicted 1');
order++;
break;
case 1:
assert.equal(key, 1, 'second evicted 2');
order++;
break;
case 2:
assert.equal(key, 3, 'third evicted 0');
order++;
break;
}
};
ch.options.eviction = 'mru';
var cache = new PromiseCache(null, ch.options);
cache.set(0, ch.promises[0]);
cache.set(1, ch.promises[1]);
getSequence(cache, [0,1,0]);
cache.set(2, ch.promises[2]);
cache.set(3, ch.promises[3]);
cache.get(3);
cache.set(1, ch.promises[1]);
order = 0;
var ch2 = testCache();
ch2.options.discarded = ch.options.discarded;
ch2.options.evictRate = 3;
ch2.options.capacity = 4;
ch2.options.eviction = 'mru';
var cache2 = new PromiseCache(ch2.promises, ch2.options);
getSequence(cache2, [1,2,0,2,3,0,1,3,3]);
cache2.set(5, ch.promises[1]);
});
QUnit.test("LFU get", function (assert) {
var ch = testCache();
ch.options.eviction = 'lfu';
ch.options.capacity = 10;
var cache = new PromiseCache(ch.promises, ch.options);
assert.strictEqual(cache._promises[0].lfu, 0, 'After set promise lfu 0');
cache.get(0);
assert.strictEqual(cache._promises[0].lfu, 1, 'After get promise lfu 1');
});
QUnit.test("LFU eviction", function (assert) {
assert.expect(6);
var ch = testCache();
var order = 0;
ch.options.discarded = function (key) {
switch (order) {
case 0:
assert.equal(key, 1, 'first evicted 1');
order++;
break;
case 1:
assert.equal(key, 2, 'second evicted 2');
order++;
break;
case 2:
assert.equal(key, 3, 'third evicted 0');
order++;
break;
}
};
ch.options.eviction = 'lfu';
var cache = new PromiseCache(null, ch.options);
cache.set(0, ch.promises[0]);
cache.set(1, ch.promises[1]);
getSequence(cache, [0,1,0]);
cache.set(2, ch.promises[2]);
cache.set(3, ch.promises[3]);
cache.get(3);
cache.set(1, ch.promises[1]);
order = 0;
var ch2 = testCache();
ch2.options.discarded = ch.options.discarded;
ch2.options.evictRate = 3;
ch2.options.capacity = 4;
ch2.options.eviction = 'lfu';
var cache2 = new PromiseCache(ch2.promises, ch2.options);
getSequence(cache2, [3,2,0,2,1,0,0,0,1,1]);
cache2.set(5, ch.promises[1]);
});
if (require.main === module){
require('qunit-tap')(QUnit, console.log.bind(console));
QUnit.load();
}
})(QUnit);