test("All callbacks called when getter returns", function(t) { var db = levelmem() var source = { source1: "one", source2: "two" } function getter(key, cb) { setTimeout(function() { cb(false, source[key]) }, 100) } var cache = newCache(db, getter) t.plan(3) var soFar = 0 function testResponse(expected) { return function(err, value) { t.equal(expected, value, 'The got value is ' + expected + ' as expected') soFar = soFar + 1 if (soFar === 3) { cache.stop() t.end() } } } cache.get('source1', testResponse('one')) cache.get('source2', testResponse('two')) cache.get('source1', testResponse('one')) })
test('no server running', function(t) { var butler = new Butler('http://127.0.0.1:8989', levelmem()) t.timeoutAfter(5000) t.plan(3) t.test('getting all posts with a server error', function(t) { butler.getPosts(function(err, posts) { t.ok(err, 'error getting all posts') t.end() }) }) t.test('getting most recent posts with a server error', function(t) { butler.getPosts({ mostRecent: 3 }, function(err, posts) { t.ok(err, 'error getting most recent posts') t.end() }) }) t.test('getting local posts with a server error', function(t) { butler.getPosts({ local: true }, function(err, posts) { t.ok(err, 'error getting local posts') t.end() }) }) })
coreThing.beginAuthentication(sessionId, emailAddress, function (e, sid, ea) { t.equal(coreThing.beginAuthCalls, 2, 'called beginAuth 2 times') t.notOk(e, 'no err') var core = Object.create(coreThing) var coreCopy = Object.create(coreThing) t.deepEqual(core, coreCopy, "core and copy started equal") var database = level('dbnc') jlDebounce(core, database) t.notDeepEqual(core, coreCopy, "jlDebounce modifed core") core.beginAuthentication(sessionId, emailAddress, function (err, sid, ea) { t.equal(coreThing.beginAuthCalls, 3, 'called beginAuth 3 times') t.notOk(err, "no error") t.notOk(err && err.debounce, "no debounce error") t.equal(sid, sessionId, 'has session id') t.equal(ea, emailAddress, 'has email address') core.beginAuthentication(sessionId, emailAddress, function (err, details) { t.equal(coreThing.beginAuthCalls, 3, 'called beginAuth 3 times (calls cb, bot beginAuth)') t.ok(err, "error") t.ok(err && err.debounce, "debounce error") t.ok(details, 'has details') t.ok(details && details.remaining, 'has details.remaining') t.notOk(details && details.allowed, 'has details.allowed') t.end() }) }) })
test('refresh should cause a remote get', function(t) { var db = levelmem() var source = { source1: "one", source2: "two" } function getter(key, cb) { setTimeout(function() { cb(false, source[key]) }, 10) } var cache = newCache(db, getter, { refreshEvery: 10000, checkToSeeIfItemsNeedToBeRefreshedEvery: 1000 }) cache.get('source1', function(err, value) { t.notOk(err, "no err") t.equal('one', value, 'value was one, correctly') source.source1 = 'huh' cache.refresh('source1', function(err, value) { t.notOk(err, "no err") t.equal('huh', value, 'value was huh, correctly') cache.get('source1', function(err, value) { t.notOk(err, "no err") t.equal('huh', value, 'value was huh, correctly') cache.stop() t.end() }) }) }) })
test('No file with that name', function(t) { var server = createServer(8989) var butler = new Butler('http://127.0.0.1:8989', levelmem()) butler.getPost('doesNotExist.lol', function(err, post) { t.ok(err, 'error looking up doesNotExist.lol') server.close() butler.stop() t.end() }) })
function createServer () { return http.createServer(authenticServer({ db: levelmem('mem', {valueEncoding: 'json'}), publicKey: fs.readFileSync(__dirname + '/rsa-public.pem', 'utf-8'), privateKey: fs.readFileSync(__dirname + '/rsa-private.pem', 'utf-8'), sendEmail: function (emailOpts, cb) { lastEmail = emailOpts setImmediate(cb) } })) }
it('it rejects on JSON error', function (done) { var db = levelMem('test3') var data = from(['asdasdasfrg']) data.pipe(levelImport(db)) .then(function () { throw new Error('should not resolve') }, function (err) { err.message.should.match(/^JSONError: /) }) .then(done, done) })
test("All callbacks called when getter returns", function(t) { var levelUpDb = levelmem() var source = { 'some key': { id: 1, content: 'sup dawg' }, 'some other key': { id: 2, content: 'sup doge' } } function fetchFromSomewhere(key, cb) { setTimeout(function() { cb(false, source[key]) }, 100) } t.plan(5) // Cache implementation example \\ var options = { refreshEvery: 10 * 1000, checkToSeeIfItemsNeedToBeRefreshedEvery: 5 * 1000, ttl: 24 * 60 * 60 * 1000, // Defaults to 7 days comparison: function defaultComparison(a, b) { // Defaults to a === b return a.id === b.id && a.content === b.content } } var cache = new Cache(levelUpDb, function(key, cb) { fetchFromSomewhere(key, cb) }, options) cache.get('some key', function(err, value) { t.equal(1, value.id) t.equal('sup dawg', value.content) }) cache.once('change', function(key, value) { t.equal('sup dawg', value.content) andThenDoThisThing() }) function andThenDoThisThing() { cache.once('change', function(key, value) { t.equal(2, value.id) t.equal('sup doge', value.content) cache.stop() }) cache.refresh('some other key') } })
it('streams in data', function (done) { var data = from(JSON.stringify([ {key:'s', value: 't'}, {key:'t', value: 'r'}, {key:'e', value: 'a'}, {key:'a', value: '!'} ],null,1).split('\n')) var db = levelMem('test2') data .pipe(levelImport(db)) .then(done, done) })
test('Bad index', function(t) { var server = require('http').createServer(function(req, res) { res.end('[this is not valid json]') }) server.listen(8989) var butler = new Butler('http://127.0.0.1:8989', levelmem()) butler.getPosts(function(err, posts) { t.ok(err, 'error getting all posts') butler.stop() server.close() t.end() }) })
it('it is rejected on non-key-value pairs', function (done) { var db = levelMem('test4') var data = from(JSON.stringify([ {key:'a', value: 'o'}, {key:'b', value: 'm'}, {foo: 'bar'}, {key:'d', value: '!'} ],null,1).split('\n')) data.pipe(levelImport(db)) .then(function () { throw new Error('should not resolve') }, function (err) { err.message.should.match(/^JSONError: not a key-value pair/) }) .then(done, done) })
test("'Change' events fired once for new values", function(t) { var source = { source1: "one", source2: "two" } function getter(key, cb) { setTimeout(function() { cb(false, source[key]) }, 1) } var cache = newCache(levelmem(), getter, { refreshEvery: 100, checkToSeeIfItemsNeedToBeRefreshedEvery: 5 }) t.plan(7) cache.once('change', function(key, newValue, oldValue) { t.equal('source2', key, "key was source2") t.equal('two', newValue, "value is one") t.equal(undefined, oldValue, "value was undefined") var eventEmitted = false cache.on('change', function(key, newValue, oldValue) { t.notOk(eventEmitted, "Event was not emitted before") eventEmitted = true t.equal('source2', key, "key is correct: " + key) t.equal('three', newValue, "new value is correct: " + newValue) t.equal('two', oldValue, "old value is correct:" + oldValue) }) }) cache.refresh('source2') setTimeout(function() { source.source2 = 'three' }, 350) setTimeout(function() { cache.stop() t.end() }, 900) })
test("'Change' events firing with custom comparison function", function(t) { var source = { source1: { id: 1, name: "one" }, source2: { id: 2, name: "two" } } function getter(key, cb) { setTimeout(function() { cb(false, source[key]) }, 1) } var cache = newCache(levelmem('no location', { valueEncoding: 'json' }), getter, { refreshEvery: 100, checkToSeeIfItemsNeedToBeRefreshedEvery: 5, comparison: function testComparison(a, b) { return a && b && a.id === b.id && a.name === b.name } }) t.plan(4) cache.get('source1', function() { var happenedAlready = false cache.on('change', function(key, newValue, oldValue) { t.notOk(happenedAlready) happenedAlready = true t.equal('source1', key, 'Key is source1') t.equal("something different", newValue.name, "New value's name is correct") t.equal(1, newValue.id, "New value's id is 1") cache.stop() t.end() }) }) setTimeout(function() { source.source1.name = "something different" }, 250) t.timeoutAfter(5000) })
test("Doesn't emit any events on shutdown", function(t) { function getter(key, cb) { setTimeout(cb.bind(null, null, 'meh'), 5) } var cache = newCache(levelmem(), getter, { refreshEvery: 1000, checkToSeeIfItemsNeedToBeRefreshedEvery: 10 }) cache.get('bluh', function(err, value) { t.notOk(err, 'No errors') t.equals(value, 'meh', 'meh is meh') cache.on('change', function() { t.notOk(true, 'No events fired') }) setTimeout(function() { cache.stop() t.end() }, 3500) }) })
var TestingCache = function(source, options) { var db = levelmem() var delay = options ? (options.delay || 10) : 10 source = source || { source1: "one", source2: "two" } var getter = function(key, cb) { setTimeout(function() { cb(false, source[key]) }, delay) } var cache = newCache(db, getter, options) cache.source = source return cache }
test('test if decrease works', function (t) { var debounce = Debouncer(Level('whatever'), {delayTimeMs: defaultStepDelay}) var runDebounce = function (object) { setTimeout(function () { debounce('thekey', function (err, allowed) { t.notOk(err, "No error") t.equal(allowed, object.expected, (object.expected?'A':'Not a')+'llowed to run at '+object.time/1000+' seconds') }) }, object.time) } var testObjects = [ {time: 100, expected:true}, {time: 1000, expected:false}, {time: 2200, expected:true}, {time: 3300, expected:true} ] t.plan(testObjects.length * 2) //2 tests in each debounce call testObjects.forEach(runDebounce) })
test("Only expired values are reloaded", function(t) { var db = levelmem() var source = { source1: "one", source2: "two" } function getter(key, cb) { setTimeout(function() { cb(false, source[key]) }, 10) } var cache = newCache(db, getter, { refreshEvery: 1000, checkToSeeIfItemsNeedToBeRefreshedEvery: 10 }) // Won't refresh the first time, because there won't be anything older than a second when the cache // has only been around for a second t.plan(3) cache.get('source1') setTimeout(function() { cache.get('source2', function(err, value) { t.equal('two', value, "source2's value was retrieved correctly") source.source1 = "a new value!" cache.on('load', function(key, newValue) { t.equal('source1', key, 'key is source1') t.equal("a new value!", newValue, 'value is the new updated value') }) }) }, 900) setTimeout(function() { cache.stop() t.end() }, 1500) })
test("Events are emitted when values are reloaded", function(t) { var db = levelmem() var source = { source1: "one", source2: "two" } function getter(key, cb) { setTimeout(function() { cb(false, source[key]) }, 10) } var cache = newCache(db, getter, { refreshEvery: 1000, checkToSeeIfItemsNeedToBeRefreshedEvery: 10 }) var eventCalls = 2 * 2 * 2 // Each event triggers 2 tests. There are 2 keys, and each one should be loaded twice (once on the original load, and once automatically after 1 second) var responseCalls = 3 t.plan(eventCalls + responseCalls) cache.on('load', function(key, newValue) { t.ok(key === 'source1' || key === 'source2', "The reload event key was an acceptable string") t.ok(newValue === 'one' || newValue === 'two', "The reload value was an acceptable string") }) function testResponse(expected) { return function(err, value) { t.equal(expected, value, 'The got value is ' + expected + ' as expected') } } cache.get('source1', testResponse('one')) cache.get('source2', testResponse('two')) cache.get('source1', testResponse('one')) setTimeout(function() { cache.stop() t.end() }, 1500) // The values should have been reloaded after the second check around ~2020 ms })
it('it parses JSON streams', function (done) { var db = levelMem('test1') var data = from(JSON.stringify([ {key:'a', value: 'o'}, {key:'b', value: 'm'}, {key:'c', value: 'g'}, {key:'d', value: '!'} ],null,1).split('\n')) data.pipe(levelImport(db)) .then(function () { var count = 0 db.createReadStream() .on('data', function () { count++ }) .on('end', function () { count.should.equal(4) done() }) }) .catch(done) })
test("Remote get only happens once for many gets", function(t) { var db = levelmem() var source = { source1: "one", source2: "two" } var getterCalled = false function getter(key, cb) { t.notOk(getterCalled, 'Getter has not been called before') getterCalled = true setTimeout(function() { cb(!getterCalled, source[key]) }, 400) } var cache = newCache(db, getter, { refreshEvery: 5000, checkToSeeIfItemsNeedToBeRefreshedEvery: 10 }) function makeRequest(key, expected) { return function(done) { cache.get(key, function(err, value) { t.notOk(err, "no error") t.equal(expected, value, "value was " + expected + " as expected") done() }) } } ASQ().gate(makeRequest('source2', 'two'), makeRequest('source2', 'two'), makeRequest('source2', 'two'), makeRequest('source2', 'two')).then(function(done) { cache.stop() t.end() done() }) })
test("encoding JSON objects", function(t) { var db = levelmem('no location', {valueEncoding: 'json'}) var source = { source1: { wat: "hello" }, source2: ["two", "three"], source3: "what number am I", source4: [{ thing: "stuff" }] } var getter = function(key, cb) { setTimeout(function() { cb(false, source[key]) }, 5) } function verify(cache, cb) { return ASQ().gate(function(done) { cache.get('source1', function(err, value) { t.notOk(err, "no error") t.ok(value, "value is truthy") t.equal("hello", value.wat, "value.wat is correct") done() }) }, function(done) { cache.get('source2', function(err, value) { t.notOk(err, "no error") t.ok(value, "value is truthy") t.equal(value.length, 2, "value has length 2") t.equal("two", value[0], "value index 0 is correct") done() }) }, function(done) { cache.get('source3', function(err, value) { t.notOk(err, "no error") t.equal("what number am I", value, "value is correct") done() }) }, function(done) { cache.get('source4', function(err, value) { t.notOk(err, "no error") t.ok(value, "value is truthy") t.equal(1, value.length, "value has length 1") t.ok(value[0].thing, "value[0].thing is truthy") t.equal(value[0].thing, "stuff", "value[0].thing is correct") done() }) }).then(cb) } var cache = newCache(db, getter) verify(cache, function() { verify(cache, function() { cache.stop() var cache2 = newCache(db, getter) verify(cache2, function() { cache2.stop() t.end() }) }) }) })