1 | let redis = require("redis");
|
2 | let client = redis.createClient();
|
3 | let cache = require('../classes/controller-cache');
|
4 | let Controller = require('../classes/controller');
|
5 | const assert = require('assert');
|
6 | Promise = require('bluebird').Promise;
|
7 |
|
8 | const dbsize = () => new Promise((resolve, reject) =>
|
9 | client.dbsize((err, result) => {
|
10 | if (err) return reject(err);
|
11 | resolve(result);
|
12 | }));
|
13 |
|
14 | const tick = (time) => new Promise((resolve) => setTimeout(resolve, time || 2));
|
15 | const promise = (func) => new Promise(resolve => func(resolve));
|
16 |
|
17 | beforeEach(done => client.flushdb(done));
|
18 | afterEach(done => client.flushdb(done));
|
19 | before(done => client.flushdb(done));
|
20 | after(done => client.flushdb(done));
|
21 |
|
22 | describe('ControllerCache Handling various data types', function () {
|
23 |
|
24 | it('should take a string', () => {
|
25 | let lru = new cache(client, 'someController', 'Get', {max: 10});
|
26 | return lru.cache.set('/some', 'string content')
|
27 | .then(result => assert.equal(result, 'string content'))
|
28 | .then(() => lru.cache.get('/some'))
|
29 | .then(result => assert.equal(result, 'string content'))
|
30 | })
|
31 |
|
32 | it('should take an object', () => {
|
33 | let lru = new cache(client, 'someController', 'Get', {max: 10});
|
34 | return lru.cache.set('/my/url?foo=true', {foo: 'bar'})
|
35 | .then(result => assert.deepEqual(result, {foo: 'bar'}))
|
36 | });
|
37 |
|
38 | it('should take an array', () => {
|
39 | let lru = new cache(client, 'someController', 'Get', {max: 10});
|
40 | return lru.cache.set('/my/url', [{foo: 'bar'}])
|
41 | .then(result => assert.deepEqual(result, [{foo: 'bar'}]))
|
42 | .then(() => lru.cache.get('/my/url'))
|
43 | .then(result => assert.deepEqual(result, [{foo: 'bar'}]))
|
44 | })
|
45 |
|
46 | it('should take a number (integer)', () => {
|
47 | let lru = new cache(client, 'someController', 'Get', {max: 10});
|
48 | return lru.cache.set('/how-many/things', 4e8)
|
49 | .then(result => assert.equal(result, 4e8))
|
50 | .then(() => lru.cache.get('/how-many/things'))
|
51 | .then(result => assert.equal(result, 4e8))
|
52 | })
|
53 |
|
54 | it('should take a number (negative integer)', () => {
|
55 | let lru = new cache(client, 'someController', 'Get', {max: 10});
|
56 | return lru.cache.set('/how-many/things', -49637)
|
57 | .then(result => assert.equal(result, -49637))
|
58 | .then(() => lru.cache.get('/how-many/things'))
|
59 | .then(result => assert.equal(result, -49637))
|
60 | })
|
61 |
|
62 | it('should take a number (float)', () => {
|
63 | let lru = new cache(client, 'someController', 'Get', {max: 10});
|
64 | return lru.cache.set('/how-many/things', 4.3427)
|
65 | .then(result => assert.equal(result, 4.3427))
|
66 | .then(() => lru.cache.get('/how-many/things'))
|
67 | .then(result => assert.equal(result, 4.3427))
|
68 | })
|
69 |
|
70 | it('should take a number (negative float)', () => {
|
71 | let lru = new cache(client, 'someController', 'Get', {max: 10});
|
72 | return lru.cache.set('/how-many/things', -49637.342787368763587653876538763)
|
73 | .then(result => assert.equal(result, -49637.342787368763587653876538763))
|
74 | .then(() => lru.cache.get('/how-many/things'))
|
75 | .then(result => assert.equal(result, -49637.342787368763587653876538763))
|
76 | })
|
77 |
|
78 | it('should take a boolean (true)', () => {
|
79 | let lru = new cache(client, 'someController', 'Get', {max: 10});
|
80 | return lru.cache.set('/lengthy-analysis/result', true)
|
81 | .then(result => assert.equal(result, true))
|
82 | .then(() => lru.cache.get('/lengthy-analysis/result'))
|
83 | .then(result => assert.equal(result, true))
|
84 | })
|
85 |
|
86 | it('should take a boolean (false)', () => {
|
87 | let lru = new cache(client, 'someController', 'Get', {max: 10});
|
88 | return lru.cache.set('/lengthy-analysis/result', false)
|
89 | .then(result => assert.equal(result, false))
|
90 | .then(() => lru.cache.get('/lengthy-analysis/result'))
|
91 | .then(result => assert.equal(result, false))
|
92 | })
|
93 |
|
94 | it('should take a buffer', () => {
|
95 | let lru = new cache(client, 'someController', 'Get', {max: 10});
|
96 | let bigArray = [];
|
97 | let i = 0;
|
98 |
|
99 | for (i; i < 3518; i += 1) {
|
100 | bigArray.push((Math.random() * 10) < 5 ? 0 : 1);
|
101 | }
|
102 |
|
103 | let buffer = new Buffer(bigArray);
|
104 | return lru.cache.set('/lengthy-analysis/result', buffer)
|
105 | .then(() => lru.cache.get('/lengthy-analysis/result'))
|
106 | .then(result => assert.deepEqual(buffer, new Buffer(result)))
|
107 | })
|
108 |
|
109 | });
|
110 |
|
111 |
|
112 | describe('ControllerCache Set and Get methods', () => {
|
113 | it('should save an item in the cache and allow to get it back', () => {
|
114 | const lru = new cache(client, 'UserController').cache;
|
115 |
|
116 | return lru.set('key', 'hello')
|
117 | .then((result) => assert.equal(result, 'hello'))
|
118 | .then(() => lru.set('key2', {message: 'goodbye'}))
|
119 | .then(() => Promise.all([lru.get('key'), lru.get('key2')]))
|
120 | .then((results) => {
|
121 | assert.equal(results[0], 'hello');
|
122 | assert.deepEqual(results[1], {message: 'goodbye'});
|
123 | });
|
124 | });
|
125 |
|
126 | it('should return null if a key is not found in the cache', () => {
|
127 | const lru = new cache(client, 'UserController').cache;
|
128 |
|
129 | return lru.get('key1')
|
130 | .then((result) => assert.equal(result, null));
|
131 | });
|
132 |
|
133 | it('should save up to opts.max items in the cache', () => {
|
134 | const lru = new cache(client, 'UserController').cache;
|
135 |
|
136 | return Promise.all([
|
137 | lru.set('k1', 'v1'), lru.set('k2', 'v2'), lru.set('k3', 'v3')
|
138 | ])
|
139 | .then(() => lru.get('k1'))
|
140 | .then((r) => assert.equal(r, 'v1'))
|
141 | .then(tick)
|
142 | .then(() => lru.get('k2'))
|
143 | .then((r) => assert.equal(r, 'v2'))
|
144 | .then(tick)
|
145 | .then(() => lru.get('k3'))
|
146 | .then((r) => assert.equal(r, 'v3'))
|
147 | .then(dbsize)
|
148 | .then((r) => assert.equal(r, 4))
|
149 | .then(() => lru.set('k4', 'v4'))
|
150 | .then(() => lru.get('k1'))
|
151 | .then((r) => assert.equal(r, null, 'k1 should have been evicted from the cache'))
|
152 | .then(() => lru.get('k2'))
|
153 | .then((r) => assert.equal(r, 'v2'))
|
154 | .then(() => lru.get('k3'))
|
155 | .then((r) => assert.equal(r, 'v3'))
|
156 | .then(() => lru.get('k4'))
|
157 | .then((r) => assert.equal(r, 'v4'))
|
158 | .then(dbsize)
|
159 | .then((r) => assert.equal(r, 4, 'db size should not have grown'));
|
160 | });
|
161 |
|
162 | it('should keep different items in different namespaces', () => {
|
163 | const lru1 = new cache(client, 'first').cache;
|
164 | const lru2 = new cache(client, 'second').cache;
|
165 |
|
166 | return lru1.set('k1', 'first cache')
|
167 | .then(() => lru2.set('k1', 'second cache'))
|
168 | .then(() => Promise.all([lru1.get('k1'), lru2.get('k1')]))
|
169 | .then((results) => {
|
170 | assert.equal(results[0], 'first cache');
|
171 | assert.equal(results[1], 'second cache');
|
172 | });
|
173 | });
|
174 |
|
175 | it('should keep the last accessed items first', () => {
|
176 | const lru = new cache(client, 'UserController').cache;
|
177 |
|
178 | return lru.set('k1', 'v1')
|
179 | .then(() => lru.set('k2', 'v2'))
|
180 | .then(() => lru.set('k3', 'v3'))
|
181 | .then(() => lru.get('k2'))
|
182 | .then(tick)
|
183 | .then(() => lru.get('k3'))
|
184 | .then(tick)
|
185 | .then(() => lru.get('k1'))
|
186 | .then(tick)
|
187 | .then(() => lru.set('k4', 'v4'))
|
188 | .then(() => lru.get('k2'))
|
189 | .then((result) => {
|
190 | assert.equal(result, null);
|
191 | });
|
192 | });
|
193 |
|
194 | it('should update value and last accessed score when setting a key again', () => {
|
195 | const lru = new cache(client, 'UserController').cache;
|
196 |
|
197 | return lru.set('k1', 'v1')
|
198 | .then(() => lru.set('k2', 'v2'))
|
199 | .then(() => lru.set('k3', 'v3'))
|
200 | .then(() => lru.get('k2'))
|
201 | .then(tick)
|
202 | .then(() => lru.get('k3'))
|
203 | .then(tick)
|
204 | .then(() => lru.get('k1'))
|
205 | .then(tick)
|
206 | .then(() => lru.set('k2', 'v2'))
|
207 | .then(tick)
|
208 | .then(() => lru.set('k4', 'v4'))
|
209 | .then(() => lru.get('k3'))
|
210 | .then((result) => {
|
211 | assert.equal(result, null);
|
212 | });
|
213 | });
|
214 |
|
215 | it('should not update last accessed score on a different namespace', () => {
|
216 | let lru1 = new cache(client, 'c1', 'get', {max : 2});
|
217 | let lru2 = new cache(client, 'c2', 'get', {max: 2});
|
218 |
|
219 | return lru1.cache.set('k1', 'v1')
|
220 | .then(() => lru1.cache.set('k2', 'v2'))
|
221 | .then(() => lru2.cache.set('k1', 'v1'))
|
222 | .then(tick)
|
223 | .then(() => lru2.cache.set('k2', 'v2'))
|
224 | .then(tick)
|
225 | .then(() => lru1.cache.get('k1'))
|
226 | .then(tick)
|
227 | .then(() => lru2.cache.set('k3', 'v3'))
|
228 | .then(() => lru2.cache.get('k1'))
|
229 | .then((result) => {
|
230 | assert.equal(result, null);
|
231 | });
|
232 | });
|
233 | });
|
234 |
|
235 | describe("ControllerCache LRU set options during runtime (Single Prop)", function () {
|
236 |
|
237 | it('should update the max options', function () {
|
238 | let myCache = new cache(client, 'UserController');
|
239 | myCache.setOptions({max: 1}, true);
|
240 | return myCache.cache.set('k1', 'v1')
|
241 | .then(() => myCache.cache.set('k2', 'v2'))
|
242 | .then(() => myCache.cache.get('k1'))
|
243 | .then(tick)
|
244 | .then(() => myCache.cache.get('k1'))
|
245 | .then(result => {
|
246 | assert.equal(result, null);
|
247 | }).then(() => myCache.cache.reset());
|
248 | });
|
249 |
|
250 | });
|
251 |
|
252 | describe("ControllerCache LRU set options during runtime (Multiple Props)", function () {
|
253 | it('should update the strategy', function () {
|
254 | let myCache = new cache(client, 'UserController');
|
255 | myCache.setOptions({max: 2, strategy: 'LFU'}, true);
|
256 | return myCache.cache.set('beatles', 'john, paul, george, ringo')
|
257 | .then(() => myCache.cache.get('beatles'))
|
258 | .then(() => myCache.cache.set('zeppelin', 'jimmy, robert, john, bonzo'))
|
259 | .then(() => myCache.cache.set('floyd', 'david, roger, syd, richard, nick'))
|
260 | .then(() => myCache.cache.get('zeppelin'))
|
261 | .then(result => {
|
262 | assert.equal(result, null);
|
263 | })
|
264 | });
|
265 |
|
266 | it('should update the namespace', function () {
|
267 | let myCache = new cache(client, 'UserController');
|
268 | myCache.setOptions({max: 2, strategy: 'LFU', namespace: 'fooze'}, true);
|
269 | return myCache.cache.set('beatles', 'john, paul, george, ringo')
|
270 | .then(() => myCache.cache.get('beatles'))
|
271 | .then(() => myCache.cache.set('zeppelin', 'jimmy, robert, john, bonzo'))
|
272 | .then(() => myCache.cache.set('floyd', 'david, roger, syd, richard, nick'))
|
273 | .then(() => myCache.cache.get('zeppelin'))
|
274 | .then(result => {
|
275 | assert.equal(result, null);
|
276 | assert.equal(myCache.namespace, 'UserController#UNDEFINED-ACTION-fooze');
|
277 | })
|
278 | });
|
279 |
|
280 | });
|
281 |
|
282 | describe('ControllerCache getOrSet method', () => {
|
283 | it('should get the value from cache and NOT call the function', () => {
|
284 | const lru = new cache(client, 'someController')
|
285 |
|
286 | function fn () {
|
287 | throw Error('should not call');
|
288 | }
|
289 |
|
290 | return lru.cache.set('key', 'hello')
|
291 | .then(() => lru.cache.getOrSet('key', fn))
|
292 | .then((result) => assert.equal(result, 'hello'));
|
293 | });
|
294 |
|
295 | it('should set key to the return value of the function', () => {
|
296 | const lru = new cache(client, 'someController').cache
|
297 |
|
298 | function fn () {
|
299 | return 5;
|
300 | }
|
301 |
|
302 | return lru.getOrSet('key', fn)
|
303 | .then((result) => assert.equal(result, 5))
|
304 | .then(() => lru.get('key'))
|
305 | .then((result) => assert.equal(result, 5));
|
306 | });
|
307 |
|
308 | it('should set key to the resolved value of the promise returned by the function', () => {
|
309 | const lru = new cache(client, 'someController').cache
|
310 |
|
311 | function fn () {
|
312 | return Promise.resolve(5);
|
313 | }
|
314 |
|
315 | return lru.getOrSet('key', fn)
|
316 | .then((result) => assert.equal(result, 5))
|
317 | .then(() => lru.get('key'))
|
318 | .then((result) => assert.equal(result, 5));
|
319 | });
|
320 |
|
321 | it('should reject if function rejects', () => {
|
322 | const lru = new cache(client, 'someController').cache
|
323 |
|
324 | function fn () {
|
325 | return Promise.reject(Error('something went wrong'));
|
326 | }
|
327 |
|
328 | return lru.getOrSet('key', fn)
|
329 | .then(() => { throw Error('should not resolve'); })
|
330 | .catch((err) => assert.equal(err.message, 'something went wrong'));
|
331 | });
|
332 |
|
333 | it('should reject if function throws', () => {
|
334 | const lru = new cache(client, 'someController').cache
|
335 |
|
336 | function fn () {
|
337 | throw Error('something went wrong');
|
338 | }
|
339 |
|
340 | return lru.getOrSet('key', fn)
|
341 | .then(() => { throw Error('should not resolve'); })
|
342 | .catch((err) => assert.equal(err.message, 'something went wrong'));
|
343 | });
|
344 |
|
345 | it('should update recent-ness when getOrSet a saved value', () => {
|
346 | const lru = new cache(client, 'someController', 'FindOne').cache
|
347 |
|
348 | return lru.set('k1', 'v1')
|
349 | .then(() => lru.set('k2', 'v2'))
|
350 | .then(() => lru.set('k3', 'v3'))
|
351 | .then(() => lru.getOrSet('k2'))
|
352 | .then(tick)
|
353 | .then(() => lru.getOrSet('k3'))
|
354 | .then(tick)
|
355 | .then(() => lru.getOrSet('k1'))
|
356 | .then(tick)
|
357 | .then(() => lru.set('k4', 'v4'))
|
358 | .then(() => lru.get('k2'))
|
359 | .then((result) => {
|
360 | assert.equal(result, null);
|
361 | });
|
362 | });
|
363 |
|
364 | it('should update recent-ness when getOrSet a missing value', () => {
|
365 | const lru = new cache(client, 'someController').cache
|
366 |
|
367 | return lru.getOrSet('k2', () => 2)
|
368 | .then(tick)
|
369 | .then(() => lru.getOrSet('k3', () => 3))
|
370 | .then(tick)
|
371 | .then(() => lru.getOrSet('k1', () => 1))
|
372 | .then(tick)
|
373 | .then(() => lru.set('k4', 'v4'))
|
374 | .then(() => lru.get('k2'))
|
375 | .then((result) => {
|
376 | assert.equal(result, null);
|
377 | });
|
378 | });
|
379 | });
|
380 |
|
381 | describe('ControllerCache peek method', () => {
|
382 | it('should return the value without changing the recent-ness score', () => {
|
383 | let lrucache = new cache(client, 'someController', 'Get', {max: 2});
|
384 | const lru = lrucache.cache;
|
385 |
|
386 | return lru.set('k1', 'v1')
|
387 | .then(tick)
|
388 | .then(() => lru.set('k2', 'v2'))
|
389 | .then(() => lru.peek('k1'))
|
390 | .then((r) => {
|
391 | assert.equal(r, 'v1');
|
392 | return lru.set('k3', 'v3');
|
393 | })
|
394 | .then(() => lru.get('k1'))
|
395 | .then((r) => assert.equal(r, null));
|
396 | });
|
397 | });
|
398 |
|
399 | describe('ControllerCache del method', () => {
|
400 | it('should remove the key from the cache and preserve the rest', () => {
|
401 | let lrucache = new cache(client, 'someController', 'Get', {max: 2});
|
402 | const lru = lrucache.cache;
|
403 |
|
404 | return lru.set('k1', 'v1')
|
405 | .then(() => lru.set('k2', 'v2'))
|
406 | .then(() => lru.del('k1'))
|
407 | .then(() => lru.get('k1'))
|
408 | .then((r) => assert.equal(r, null))
|
409 | .then(() => lru.get('k2'))
|
410 | .then((r) => assert.equal(r, 'v2'));
|
411 | });
|
412 |
|
413 | it('should not remove from other namespaces', () => {
|
414 | let lrucache = new cache(client, 'someController', 'Foo', {max: 2});
|
415 | const lru = lrucache.cache;
|
416 |
|
417 | let cache2 = new cache(client, 'c2');
|
418 | cache2.setOptions({max: 2});
|
419 | const lru2 = cache2.cache;
|
420 |
|
421 | return lru.set('k1', 'v1')
|
422 | .then(() => lru2.set('k1', 'v1'))
|
423 | .then(() => lru.del('k1'))
|
424 | .then(() => lru.get('k1'))
|
425 | .then((r) => assert.equal(r, null))
|
426 | .then(() => lru2.get('k1'))
|
427 | .then((r) => assert.equal(r, 'v1'));
|
428 | });
|
429 | });
|
430 |
|
431 | describe('ControllerCache reset method', () => {
|
432 | it('should remove all keys from the cache', () => {
|
433 | let lrucache = new cache(client, 'someController', 'foo', {max: 2});
|
434 | const lru = lrucache.cache;
|
435 |
|
436 | return lru.set('k1', 'v1')
|
437 | .then(() => lru.set('k2', 'v2'))
|
438 | .then(() => lru.reset())
|
439 | .then(() => lru.get('k1'))
|
440 | .then((r) => assert.equal(r, null))
|
441 | .then(() => lru.get('k2'))
|
442 | .then((r) => assert.equal(r, null));
|
443 | });
|
444 |
|
445 | it('should not empty other namespaces', () => {
|
446 | let lrucache = new cache(client, 'someController', 'getSomeList', {max: 2});
|
447 | const lru = lrucache.cache;
|
448 |
|
449 | let cache2 = new cache(client, 'c2');
|
450 | cache2.setOptions({max: 2}, true);
|
451 | const lru2 = cache2.cache;
|
452 |
|
453 | return lru.set('k1', 'v1')
|
454 | .then(() => lru2.set('k1', 'v1'))
|
455 | .then(() => lru.reset())
|
456 | .then(() => lru.get('k1'))
|
457 | .then((r) => assert.equal(r, null))
|
458 | .then(() => lru2.get('k1'))
|
459 | .then((r) => assert.equal(r, 'v1'));
|
460 | });
|
461 | });
|
462 |
|
463 | describe('ControllerCache has method', () => {
|
464 | it('should return true if the item is in the cache without affecting the recent-ness', () => {
|
465 | let lrucache = new cache(client, 'someController');
|
466 | lrucache.setOptions({max: 2}, true);
|
467 | const lru = lrucache.cache;
|
468 |
|
469 | return lru.set('k1', 'v1')
|
470 | .then(tick)
|
471 | .then(() => lru.set('k2', 'v2'))
|
472 | .then(() => lru.has('k1'))
|
473 | .then((r) => {
|
474 | assert.equal(r, true);
|
475 | return lru.set('k3', 'v3');
|
476 | })
|
477 | .then(() => lru.get('k1'))
|
478 | .then((r) => assert.equal(r, null));
|
479 | });
|
480 |
|
481 | it('should return false if the item is not in the cache', () => {
|
482 | let lrucache = new cache(client);
|
483 | lrucache.setOptions({max: 2}, true);
|
484 | const lru = lrucache.cache;
|
485 |
|
486 | return lru.set('k1', 'v1')
|
487 | .then(() => lru.set('k2', 'v2'))
|
488 | .then(() => lru.has('k3'))
|
489 | .then((r) => assert.equal(r, false));
|
490 | });
|
491 | });
|
492 |
|
493 | describe('ControllerCache keys method', () => {
|
494 | it('should return all keys inside the cache', () => {
|
495 | let lrucache = new cache(client, 'someController');
|
496 | lrucache.setOptions({max: 2}, true);
|
497 | const lru = lrucache.cache;
|
498 |
|
499 | return lru.set('k1', 'v1')
|
500 | .then(tick)
|
501 | .then(() => lru.set('k2', 'v2'))
|
502 | .then(() => lru.keys())
|
503 | .then((r) => assert.deepEqual(r, ['k2', 'k1']));
|
504 | });
|
505 |
|
506 | it('should not return more keys if size exceeded before', () => {
|
507 | let lrucache = new cache(client, '22', 'aa');
|
508 | lrucache.setOptions({max: 2}, true);
|
509 | const lru = lrucache.cache;
|
510 |
|
511 | return lru.set('k1', 'v1')
|
512 | .then(tick)
|
513 | .then(() => lru.set('k2', 'v2'))
|
514 | .then(tick)
|
515 | .then(() => lru.set('k3', 'v3'))
|
516 | .then(() => lru.keys())
|
517 | .then((r) => assert.deepEqual(r, ['k3', 'k2']));
|
518 | });
|
519 | });
|
520 |
|
521 | describe('ControllerCache values method', () => {
|
522 | it('should return all values inside the cache', () => {
|
523 | let lrucache = new cache(client, 'someController');
|
524 | lrucache.setOptions({max: 2}, true);
|
525 | const lru = lrucache.cache;
|
526 |
|
527 | return lru.set('k1', 'v1')
|
528 | .then(tick)
|
529 | .then(() => lru.set('k2', 'v2'))
|
530 | .then(() => lru.values())
|
531 | .then((r) => assert.deepEqual(r, ['v2', 'v1']));
|
532 | });
|
533 |
|
534 | it('should not return more values if size exceeded before', () => {
|
535 | let lrucache = new cache(client, 'someController');
|
536 | lrucache.setOptions({max: 2}, true);
|
537 | const lru = lrucache.cache;
|
538 |
|
539 | return lru.set('k1', 'v1')
|
540 | .then(tick)
|
541 | .then(() => lru.set('k2', 'v2'))
|
542 | .then(tick)
|
543 | .then(() => lru.set('k3', 'v3'))
|
544 | .then(() => lru.values())
|
545 | .then((r) => assert.deepEqual(r, ['v3', 'v2']));
|
546 | });
|
547 | });
|
548 |
|
549 | describe('ControllerCache count method', () => {
|
550 | it('should return zero if no items in the cache', () => {
|
551 | let lrucache = new cache(client, 'someController');
|
552 | lrucache.setOptions({max: 2}, true);
|
553 | const lru = lrucache.cache;
|
554 |
|
555 | return lru.count()
|
556 | .then((r) => assert.equal(r, 0));
|
557 | });
|
558 |
|
559 | it('should return the amount of items in the cache', () => {
|
560 | let lrucache = new cache(client, 'someController');
|
561 | lrucache.setOptions({max: 2}, true);
|
562 | const lru = lrucache.cache;
|
563 |
|
564 | return lru.set('k1', 'v1')
|
565 | .then(tick)
|
566 | .then(() => lru.set('k2', 'v2'))
|
567 | .then(() => lru.count())
|
568 | .then((r) => assert.equal(r, 2));
|
569 | });
|
570 |
|
571 | it('should return the max size if cache size exceeded before', () => {
|
572 | let lrucache = new cache(client, 'someController');
|
573 | lrucache.setOptions({max: 2}, true);
|
574 | const lru = lrucache.cache;
|
575 |
|
576 | return lru.set('k1', 'v1')
|
577 | .then(tick)
|
578 | .then(() => lru.set('k2', 'v2'))
|
579 | .then(tick)
|
580 | .then(() => lru.set('k3', 'v3'))
|
581 | .then(() => lru.count())
|
582 | .then((r) => assert.equal(r, 2));
|
583 | });
|
584 | });
|
585 |
|
586 | describe('ControllerCache maxAge option', () => {
|
587 | it('should return null after global maxAge has passed', () => {
|
588 | let lrucache = new cache(client, 'someController');
|
589 | lrucache.setOptions({max: 2, maxAge: 10}, true);
|
590 | const lru = lrucache.cache;
|
591 |
|
592 | return lru.set('k1', 'v1')
|
593 | .then(() => lru.get('k1'))
|
594 | .then((result) => assert.equal(result, 'v1'))
|
595 | .then(() => tick(11))
|
596 | .then(() => lru.get('k1'))
|
597 | .then((result) => assert.equal(result, null));
|
598 | });
|
599 |
|
600 | it('should return null after key maxAge has passed', () => {
|
601 | let lrucache = new cache(client, 'someController');
|
602 | lrucache.setOptions({max: 2}, true);
|
603 | const lru = lrucache.cache;
|
604 |
|
605 | return lru.set('k1', 'v1', 10)
|
606 | .then(() => lru.get('k1'))
|
607 | .then((result) => assert.equal(result, 'v1'))
|
608 | .then(() => tick(11))
|
609 | .then(() => lru.get('k1'))
|
610 | .then((result) => assert.equal(result, null));
|
611 | });
|
612 |
|
613 | it('should reduce dbsize after key expiration', () => {
|
614 | let lrucache = new cache(client, 'someController');
|
615 | lrucache.setOptions({max: 2, maxAge: 10}, true);
|
616 | const lru = lrucache.cache;
|
617 |
|
618 | return lru.set('k1', 'v1')
|
619 | .then(dbsize)
|
620 | .then((size) => assert.equal(size, 2))
|
621 | .then(() => tick(11))
|
622 | .then(() => lru.get('k1'))
|
623 | .then((result) => assert.equal(result, null))
|
624 | .then(dbsize)
|
625 | .then((size) => assert.equal(size, 0));
|
626 | });
|
627 |
|
628 | it('should remove expired key from index next time is getted', () => {
|
629 | let lrucache = new cache(client, 'someController');
|
630 | lrucache.setOptions({max: 2}, true);
|
631 | const lru = lrucache.cache;
|
632 |
|
633 | return lru.set('k1', 'v1')
|
634 | .then(() => lru.set('k2', 'v2', 10))
|
635 | .then(() => tick(11))
|
636 | .then(() => lru.get('k2'))
|
637 | .then((result) => assert.equal(result, null))
|
638 | .then(() => lru.count())
|
639 | .then((count) => assert.equal(count, 1))
|
640 | .then(() => lru.keys())
|
641 | .then((keys) => assert.deepEqual(keys, ['k1']));
|
642 | });
|
643 |
|
644 | it('should remove expired key from index next time is peeked', () => {
|
645 | let lrucache = new cache(client, 'someController');
|
646 | lrucache.setOptions({max: 2}, true);
|
647 | const lru = lrucache.cache;
|
648 |
|
649 | return lru.set('k1', 'v1')
|
650 | .then(() => lru.set('k2', 'v2', 10))
|
651 | .then(() => tick(11))
|
652 | .then(() => lru.peek('k2'))
|
653 | .then((result) => assert.equal(result, null))
|
654 | .then(() => lru.count())
|
655 | .then((count) => assert.equal(count, 1))
|
656 | .then(() => lru.keys())
|
657 | .then((keys) => assert.deepEqual(keys, ['k1']));
|
658 | });
|
659 |
|
660 | it('should not let key maxAge affect other keys', () => {
|
661 | let lrucache = new cache(client, 'someController');
|
662 | lrucache.setOptions({max: 2, maxAge: 30}, true);
|
663 | const lru = lrucache.cache;
|
664 |
|
665 | return lru.set('k1', 'v1', 10)
|
666 | .then(() => lru.set('k2', 'v2'))
|
667 | .then(() => lru.get('k1'))
|
668 | .then((result) => assert.equal(result, 'v1'))
|
669 | .then(() => lru.get('k2'))
|
670 | .then((result) => assert.equal(result, 'v2'))
|
671 | .then(() => tick(11))
|
672 | .then(() => lru.get('k1'))
|
673 | .then((result) => assert.equal(result, null))
|
674 | .then(() => lru.get('k2'))
|
675 | .then((result) => assert.equal(result, 'v2'))
|
676 | .then(() => tick(20))
|
677 | .then(() => lru.get('k2'))
|
678 | .then((result) => assert.equal(result, null));
|
679 | });
|
680 |
|
681 | it('should return false when calling has on an expired item', () => {
|
682 | let lrucache = new cache(client, 'someController');
|
683 | lrucache.setOptions({max: 2, maxAge: 10}, true);
|
684 | const lru = lrucache.cache;
|
685 |
|
686 | return lru.set('k1', 'v1')
|
687 | .then(() => lru.has('k1'))
|
688 | .then((result) => assert.equal(result, true))
|
689 | .then(() => tick(11))
|
690 | .then(() => lru.has('k1'))
|
691 | .then((result) => assert.equal(result, false));
|
692 | });
|
693 | });
|
694 |
|
695 | describe('ControllerCache custom score/increment options', () => {
|
696 | it('should allow building a LFU cache with a custom score and increment', () => {
|
697 | let lrucache = new cache(client, 'someController', 'Get', {max: 3, strategy: 'LFU'});
|
698 | const lfu = lrucache.cache;
|
699 |
|
700 | return lfu.set('k1', 'v1')
|
701 | .then(() => lfu.get('k1'))
|
702 | .then(() => lfu.get('k1'))
|
703 | .then(() => lfu.set('k2', 'v2'))
|
704 | .then(() => lfu.set('k2', 'v22'))
|
705 | .then(() => lfu.set('k3', 'v3'))
|
706 | .then(() => lfu.set('k4', 'v4'))
|
707 | .then(() => lfu.get('k3'))
|
708 | .then((result) => assert.equal(result, null))
|
709 | .then(() => lfu.keys())
|
710 | .then((keys) => assert.deepEqual(keys, ['k1', 'k2', 'k4']));
|
711 | });
|
712 | });
|
713 |
|
714 | describe('ControllerCache Use a URL as a key', function () {
|
715 | it('should store a url as a key', function () {
|
716 | let lru = new cache(client, 'someController');
|
717 | return lru.cache.set('/bands/led-zeppelin', 'v1')
|
718 | .then(() => lru.cache.get('/bands/led-zeppelin'))
|
719 | .then(result => assert.equal(result,'v1'))
|
720 | });
|
721 |
|
722 | it('should store a url & querystring as a key', function () {
|
723 | let lru = new cache(client, 'someController');
|
724 | return lru.cache.set('/bands/led-zeppelin?foo=bar&zap=123&weird=[1,2,3,4]&why={"key": "val"}', 'v1')
|
725 | .then(() => lru.cache.get('/bands/led-zeppelin?foo=bar&zap=123&weird=[1,2,3,4]&why={"key": "val"}'))
|
726 | .then(result => assert.equal(result,'v1'))
|
727 | });
|
728 | });
|
729 |
|
730 | describe('ControllerCache cachedVersion', function () {
|
731 | it('should return the cached version when it is available', function () {
|
732 | let lru = new cache(client, 'someController', 'Get');
|
733 | let req = {
|
734 | controller : 'someController',
|
735 | action : 'Get',
|
736 | url : '/bands/led-zeppelin'
|
737 | };
|
738 | lru.cache.set('/bands/led-zeppelin', { name : 'Led Zeppelin' });
|
739 |
|
740 | return lru.cachedVersion(req).then(result => {
|
741 | assert.equal(result.name, 'Led Zeppelin')
|
742 | });
|
743 | });
|
744 |
|
745 | it('should return false when it is not available', function () {
|
746 | let lru = new cache(client, 'someController', 'Get');
|
747 | let req = {
|
748 | controller : 'someController',
|
749 | action : 'Get',
|
750 | url : '/bands/led-zeppelin'
|
751 | };
|
752 |
|
753 | return lru.cachedVersion(req).then(result => {
|
754 | assert.equal(result, false);
|
755 | });
|
756 | });
|
757 | });
|
758 |
|
759 | describe('ControllerCache Controller Methods should work', function () {
|
760 |
|
761 | class testController extends Controller {
|
762 |
|
763 | Get () {
|
764 | return promise( res => {
|
765 | this.cache({ max: 100, strategy: 'LFU' }, cache => {
|
766 | let doc = [{ name: 'doc1' }];
|
767 | this.res.status(200).json(doc);
|
768 | cache(doc).then(res);
|
769 | });
|
770 | });
|
771 | }
|
772 |
|
773 | FindOne () {
|
774 | return promise( res => {
|
775 | let doc = { name: 'doc1' };
|
776 | this.cache({ max: 100, strategy: 'LRU' })
|
777 | .miss(cache => {
|
778 | this.res.status(200).json(doc);
|
779 | cache(doc);
|
780 | })
|
781 | .hit(data => this.res.status(200).json(data))
|
782 | .exec().then(res);
|
783 | });
|
784 | }
|
785 |
|
786 | Post () {
|
787 | return promise( res => {
|
788 | this.actionCache('Get').reset().then(res);
|
789 | });
|
790 | }
|
791 |
|
792 | Put () {
|
793 | return promise( res => {
|
794 | this.actionCache('Get').reset().then(res);
|
795 | })
|
796 | }
|
797 |
|
798 | Delete () {
|
799 | return promise( res => {
|
800 | this.res.status(200).json({result: 'Ya, its gone forever'});
|
801 | this.actionCache('Get').reset().then( () => {
|
802 | this.actionCache('FindOne').del('/widgets/12').then(res);
|
803 | });
|
804 | })
|
805 | }
|
806 |
|
807 | lookup (val) {
|
808 | return this.cache.get(val);
|
809 | }
|
810 |
|
811 | callbackWithResponseType () {
|
812 | let doc = { name: 'doc1' };
|
813 | return promise( res => {
|
814 | let doc = { name: 'doc1' };
|
815 | this.cache({ max: 100, strategy: 'LRU', responseMethod: 'send' }, cache => {
|
816 | res(this.res.send(doc));
|
817 | cache(doc);
|
818 | })
|
819 | });
|
820 | }
|
821 |
|
822 | promisable () {
|
823 | let doc = { name: 'doc14' };
|
824 | return promise( res => {
|
825 | let doc = { name: 'doc1' };
|
826 | this.cache({ max: 2, strategy: 'LFU' })
|
827 | .then(() => User.find().limit(15))
|
828 | .then(users => this.res.json(users).cache(users))
|
829 | .catch(err => this.error(err))
|
830 | .finally(res)
|
831 | });
|
832 | }
|
833 |
|
834 | }
|
835 |
|
836 | let res = {
|
837 | status () {
|
838 | return { json () { return 'json' } }
|
839 | },
|
840 | json () { return 'json' },
|
841 | send () { return 'send'}
|
842 | }
|
843 |
|
844 | it('should cache on a request to a cacheable method (GET)', function () {
|
845 | let myController = new testController({controller: 'myController', action: 'Get', url: '/widgets'}, res, client);
|
846 | return myController.Get()
|
847 | .then(() => myController.cacheStore.get('/widgets'))
|
848 | .then(value => assert.deepEqual(value, [{name: 'doc1'}]))
|
849 | })
|
850 |
|
851 | it('should cache on a request to a cacheable method (FindOne)', function () {
|
852 | let myController = new testController({controller: 'myController', action: 'FindOne', url: '/widgets'}, res, client);
|
853 | return myController.FindOne()
|
854 | .then(() => myController.cacheStore.get('/widgets'))
|
855 | .then(value => assert.deepEqual(value, { name: 'doc1' }))
|
856 | })
|
857 |
|
858 | it('should remove a cached Item (PUT)', function () {
|
859 | let controllerForGet = new testController({controller: 'myController', action: 'Get', url: '/widgets'}, res, client);
|
860 | let controllerForPut = new testController({controller: 'myController', action: 'Put', url: '/widgets/12'}, res, client);
|
861 |
|
862 | return controllerForGet.Get()
|
863 | .then(() => controllerForGet.cacheStore.get('/widgets'))
|
864 | .then(value => assert.deepEqual(value, [{name: 'doc1'}]))
|
865 | .then(() => controllerForPut.Put())
|
866 | .then(() => controllerForGet.cacheStore.get('/widgets'))
|
867 | .then(value => assert.equal(value, null))
|
868 | })
|
869 |
|
870 |
|
871 | it('should remove a cached Item (DELETE)', function () {
|
872 | let controllerForGet = new testController({controller: 'myController', action: 'Get', url: '/widgets'}, res, client);
|
873 | let controllerForFindOne = new testController({controller: 'myController', action: 'FindOne', url: '/widgets/12'}, res, client);
|
874 | let controllerForDelete = new testController({controller: 'myController', action: 'Delete', url: '/widgets/12'}, res, client);
|
875 |
|
876 | return controllerForGet.Get()
|
877 | .then(() => controllerForFindOne.FindOne())
|
878 | .then(() => controllerForGet.cacheStore.get('/widgets'))
|
879 | .then(value => assert.deepEqual(value, [{name: 'doc1'}]))
|
880 |
|
881 | .then(() => controllerForFindOne.cacheStore.get('/widgets/12'))
|
882 | .then(value => assert.deepEqual(value, {name: 'doc1'}))
|
883 | .then(() => controllerForDelete.Delete())
|
884 | .then(() => controllerForGet.cacheStore.get('/widgets'))
|
885 | .then(value => assert.equal(value, null))
|
886 | })
|
887 |
|
888 | });
|
889 |
|
890 |
|