connect-redis-test.js 6.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197
  1. /* eslint-env es6 */
  2. var test = require('blue-tape');
  3. var redisSrv = require('./redis-server');
  4. var session = require('express-session');
  5. var RedisStore = require('../')(session);
  6. var redis = require('redis');
  7. var ioRedis = require('ioredis');
  8. var sinon = require('sinon');
  9. var P = require('bluebird');
  10. var lifecycleTest = P.coroutine(function *(store, t) {
  11. P.promisifyAll(store);
  12. var ok = yield store.setAsync('123', { cookie: { maxAge: 2000 }, name: 'tj' });
  13. t.equal(ok, 'OK', '#set() ok');
  14. var data = yield store.getAsync('123');
  15. t.deepEqual({ cookie: { maxAge: 2000 }, name: 'tj' }, data, '#get() ok');
  16. ok = yield store.setAsync('123', { cookie: { maxAge: undefined }, name: 'tj' });
  17. t.equal(ok, 'OK', '#set() no maxAge ok');
  18. data = yield store.allAsync();
  19. t.deepEqual([{ id: '123', cookie: {}, name: 'tj' }], data, '#all() ok');
  20. data = yield store.idsAsync();
  21. t.deepEqual(['123'], data, '#ids() ok');
  22. ok = yield store.destroyAsync('123');
  23. t.equal(ok, 1, '#destroy() ok');
  24. store.client.end(false);
  25. });
  26. test('setup', redisSrv.connect);
  27. test('defaults', function (t) {
  28. var store = new RedisStore();
  29. t.equal(store.prefix, 'sess:', 'defaults to sess:');
  30. t.notOk(store.ttl, 'ttl not set');
  31. t.notOk(store.disableTTL, 'disableTTL not set');
  32. t.ok(store.client, 'creates client');
  33. store.client.end(false);
  34. t.end();
  35. });
  36. test('basic', function (t) {
  37. t.throws(RedisStore, TypeError, 'constructor not callable as function');
  38. var store = new RedisStore({ port: redisSrv.port });
  39. return lifecycleTest(store, t);
  40. });
  41. test('existing client', function (t) {
  42. var client = redis.createClient(redisSrv.port, 'localhost');
  43. var store = new RedisStore({ client: client });
  44. return lifecycleTest(store, t);
  45. });
  46. test('io redis client', function (t) {
  47. var client = ioRedis.createClient(redisSrv.port, 'localhost');
  48. var store = new RedisStore({ client: client });
  49. return lifecycleTest(store, t);
  50. });
  51. test('options', function (t) {
  52. var store = new RedisStore({
  53. host: 'localhost',
  54. port: redisSrv.port,
  55. prefix: 'tobi',
  56. ttl: 1000,
  57. disableTTL: true,
  58. db: 1,
  59. scanCount: 32,
  60. unref: true,
  61. pass: 'secret'
  62. });
  63. t.equal(store.prefix, 'tobi', 'uses provided prefix');
  64. t.equal(store.ttl, 1000, 'ttl set');
  65. t.ok(store.disableTTL, 'disableTTL set');
  66. t.ok(store.client, 'creates client');
  67. t.equal(store.client.address, 'localhost:'+redisSrv.port, 'sets host and port');
  68. t.equal(store.scanCount, 32, 'sets scan count');
  69. var socketStore = new RedisStore({ socket: 'word' });
  70. t.equal(socketStore.client.address, 'word', 'sets socket address');
  71. socketStore.client.end(false);
  72. var urlStore = new RedisStore({ url: 'redis://127.0.0.1:8888' });
  73. t.equal(urlStore.client.address, '127.0.0.1:8888', 'sets url address');
  74. urlStore.client.end(false);
  75. var hostNoPort = new RedisStore({ host: 'host' });
  76. t.equal(hostNoPort.client.address, 'host:6379', 'sets default port');
  77. hostNoPort.client.end(false);
  78. return lifecycleTest(store, t);
  79. });
  80. test('ttl options', P.coroutine(function *(t) {
  81. var store = new RedisStore({ port: redisSrv.port });
  82. var sid = '123';
  83. var data, ok;
  84. sinon.stub(store.client, 'set').callsArgWith(1, null, 'OK');
  85. P.promisifyAll(store);
  86. // Basic (one day)
  87. data = { cookie: {}, name: 'tj' };
  88. ok = yield store.setAsync(sid, data);
  89. t.equal(ok, 'OK', '#set() ok');
  90. assertSetCalledWith(t, store, sid, data, ['EX', 86400]);
  91. // maxAge in cookie
  92. data = { cookie: { maxAge: 2000 }, name: 'tj' };
  93. ok = yield store.setAsync(sid, data);
  94. t.equal(ok, 'OK', '#set() ok');
  95. assertSetCalledWith(t, store, sid, data, ['EX', 2]);
  96. // Floors maxage
  97. data = { cookie: { maxAge: 2500 }, name: 'tj' };
  98. ok = yield store.setAsync(sid, data);
  99. t.equal(ok, 'OK', '#set() ok');
  100. assertSetCalledWith(t, store, sid, data, ['EX', 2]);
  101. // store.disableTTL
  102. store.disableTTL = true;
  103. data = { cookie: {}, name: 'tj' };
  104. ok = yield store.setAsync(sid, data);
  105. t.equal(ok, 'OK', '#set() ok');
  106. assertSetCalledWith(t, store, sid, data);
  107. store.disableTTL = false;
  108. // store.ttl: number
  109. store.ttl = 50;
  110. data = { cookie: {}, name: 'tj' };
  111. ok = yield store.setAsync(sid, data);
  112. t.equal(ok, 'OK', '#set() ok');
  113. assertSetCalledWith(t, store, sid, data, ['EX', 50]);
  114. store.ttl = null;
  115. // store.ttl: function
  116. store.ttl = sinon.stub().returns(200);
  117. data = { cookie: {}, name: 'tj' };
  118. ok = yield store.setAsync(sid, data);
  119. t.equal(ok, 'OK', '#set() ok');
  120. assertSetCalledWith(t, store, sid, data, ['EX', 200]);
  121. t.ok(store.ttl.called, 'TTL fn was called');
  122. t.deepEqual(store.ttl.firstCall.args, [store, data, sid]);
  123. store.ttl = null;
  124. // store.ttl: string (invalid)
  125. store.ttl = {};
  126. data = { cookie: {}, name: 'tj' };
  127. try {
  128. ok = yield store.setAsync(sid, data);
  129. t.ok(false, '#set() should throw with bad TTL');
  130. } catch (e) {
  131. t.ok(/must be a number or function/i.test(e.message), 'bad TTL type throws error');
  132. }
  133. store.ttl = null;
  134. store.client.end(false);
  135. }));
  136. function assertSetCalledWith(t, store, sid, data, addl) {
  137. var args = [store.prefix + sid, store.serializer.stringify(data)];
  138. if (Array.isArray(addl)) args = args.concat(addl);
  139. t.deepEqual(store.client.set.lastCall.args[0], args, '#.set() called with expected params');
  140. }
  141. test('interups', function (t) {
  142. var store = P.promisifyAll(new RedisStore({ port: redisSrv.port, connect_timeout: 500 }));
  143. return store.setAsync('123', { cookie: { maxAge: 2000 }, name: 'tj' })
  144. .catch(function (er) {
  145. t.ok(/broken/.test(er.message), 'failed connection');
  146. store.client.end(false);
  147. });
  148. });
  149. test('serializer', function (t) {
  150. var serializer = {
  151. stringify: function() { return 'XXX'+JSON.stringify.apply(JSON, arguments); },
  152. parse: function(x) {
  153. t.ok(x.match(/^XXX/));
  154. return JSON.parse(x.substring(3));
  155. }
  156. };
  157. t.equal(serializer.stringify('UnitTest'), 'XXX"UnitTest"');
  158. t.equal(serializer.parse(serializer.stringify('UnitTest')), 'UnitTest');
  159. var store = new RedisStore({ port: redisSrv.port, serializer: serializer });
  160. return lifecycleTest(store, t);
  161. });
  162. test('teardown', redisSrv.disconnect);