UNPKG

fastify-redis

Version:

Plugin to share a common Redis connection across Fastify.

615 lines (495 loc) 13.4 kB
'use strict' const t = require('tap') const proxyquire = require('proxyquire') const test = t.test const Fastify = require('fastify') const fastifyRedis = require('..') const TEST_PASSWORD = 'my_secret_password' const setRedisPassword = async (password) => { const fastify = Fastify() fastify.register(fastifyRedis, { host: '127.0.0.1' }) await fastify.ready() await fastify.redis.flushall() await fastify.redis.config(['set', 'requirepass', password]) await fastify.close() } const unsetRedisPassword = async (currentPassword) => { const fastify = Fastify() fastify.register(fastifyRedis, { host: '127.0.0.1', password: currentPassword }) await fastify.ready() await fastify.redis.flushall() await fastify.redis.config(['set', 'requirepass', '']) await fastify.close() } t.beforeEach(async () => { const fastify = Fastify() fastify.register(fastifyRedis, { host: '127.0.0.1' }) await fastify.ready() await fastify.redis.flushall() await fastify.close() }) test('fastify.redis should exist', (t) => { t.plan(2) const fastify = Fastify() fastify.register(fastifyRedis, { host: '127.0.0.1' }) fastify.ready((err) => { t.error(err) t.ok(fastify.redis) fastify.close() }) }) test('fastify.redis should support url', (t) => { t.plan(3) const fastify = Fastify() const fastifyRedis = proxyquire('..', { ioredis: function Redis (path, options) { t.equal(path, 'redis://127.0.0.1') t.same(options, { otherOption: 'foo' }) this.quit = () => {} this.info = cb => cb(null, 'info') this.on = function (name, handler) { if (name === 'ready') { handler(null, 'ready') } return this } this.off = function () { return this } return this } }) fastify.register(fastifyRedis, { url: 'redis://127.0.0.1', otherOption: 'foo' }) fastify.ready((err) => { t.error(err) fastify.close() }) }) test('fastify.redis should be the redis client', (t) => { t.plan(4) const fastify = Fastify() fastify.register(fastifyRedis, { host: '127.0.0.1' }) fastify.ready((err) => { t.error(err) fastify.redis.set('key', 'value', (err) => { t.error(err) fastify.redis.get('key', (err, val) => { t.error(err) t.equal(val, 'value') fastify.close() }) }) }) }) test('fastify.redis.test namespace should exist', (t) => { t.plan(3) const fastify = Fastify() fastify.register(fastifyRedis, { host: '127.0.0.1', namespace: 'test' }) fastify.ready((err) => { t.error(err) t.ok(fastify.redis) t.ok(fastify.redis.test) fastify.close() }) }) test('fastify.redis.test should be the redis client', (t) => { t.plan(4) const fastify = Fastify() fastify.register(fastifyRedis, { host: '127.0.0.1', namespace: 'test' }) fastify.ready((err) => { t.error(err) fastify.redis.test.set('key_namespace', 'value_namespace', (err) => { t.error(err) fastify.redis.test.get('key_namespace', (err, val) => { t.error(err) t.equal(val, 'value_namespace') fastify.close() }) }) }) }) test('promises support', (t) => { t.plan(2) const fastify = Fastify() fastify.register(fastifyRedis, { host: '127.0.0.1' }) fastify.ready((err) => { t.error(err) fastify.redis .set('key', 'value') .then(() => { return fastify.redis.get('key') }) .then((val) => { t.equal(val, 'value') fastify.close() }) .catch((err) => t.fail(err)) }) }) test('custom client', (t) => { t.plan(7) const fastify = Fastify() const redis = require('redis').createClient({ host: 'localhost', port: 6379 }) fastify.register(fastifyRedis, { client: redis }) fastify.ready((err) => { t.error(err) t.equal(fastify.redis, redis) fastify.redis.set('key', 'value', (err) => { t.error(err) fastify.redis.get('key', (err, val) => { t.error(err) t.equal(val, 'value') fastify.close(function (err) { t.error(err) fastify.redis.quit(function (err) { t.error(err) }) }) }) }) }) }) test('custom ioredis client that is already connected', (t) => { t.plan(10) const fastify = Fastify() const Redis = require('ioredis') const redis = new Redis({ host: 'localhost', port: 6379 }) // use the client now, so that it is connected and ready redis.set('key', 'value', (err) => { t.error(err) redis.get('key', (err, val) => { t.error(err) t.equal(val, 'value') fastify.register(fastifyRedis, { client: redis, lazyConnect: false }) fastify.ready((err) => { t.error(err) t.equal(fastify.redis, redis) fastify.redis.set('key2', 'value2', (err) => { t.error(err) fastify.redis.get('key2', (err, val) => { t.error(err) t.equal(val, 'value2') fastify.close(function (err) { t.error(err) fastify.redis.quit(function (err) { t.error(err) }) }) }) }) }) }) }) }) test('custom redis client that is already connected', (t) => { t.plan(10) const fastify = Fastify() const redis = require('redis').createClient({ host: 'localhost', port: 6379 }) // use the client now, so that it is connected and ready redis.set('key', 'value', (err) => { t.error(err) redis.get('key', (err, val) => { t.error(err) t.equal(val, 'value') fastify.register(fastifyRedis, { client: redis, lazyConnect: false }) fastify.ready((err) => { t.error(err) t.equal(fastify.redis, redis) fastify.redis.set('key2', 'value2', (err) => { t.error(err) fastify.redis.get('key2', (err, val) => { t.error(err) t.equal(val, 'value2') fastify.close(function (err) { t.error(err) fastify.redis.quit(function (err) { t.error(err) }) }) }) }) }) }) }) }) test('custom client gets closed', (t) => { t.plan(7) const fastify = Fastify() const redis = require('redis').createClient({ host: 'localhost', port: 6379 }) fastify.register(fastifyRedis, { client: redis, closeClient: true }) fastify.ready((err) => { t.error(err) t.equal(fastify.redis, redis) fastify.redis.set('key', 'value', (err) => { t.error(err) fastify.redis.get('key', (err, val) => { t.error(err) t.equal(val, 'value') const origQuit = fastify.redis.quit fastify.redis.quit = (cb) => { t.pass('redis client closed') origQuit.call(fastify.redis, cb) } fastify.close(function (err) { t.error(err) }) }) }) }) }) test('custom client inside a namespace', (t) => { t.plan(7) const fastify = Fastify() const redis = require('redis').createClient({ host: 'localhost', port: 6379 }) fastify.register(fastifyRedis, { namespace: 'test', client: redis }) fastify.ready((err) => { t.error(err) t.equal(fastify.redis.test, redis) fastify.redis.test.set('key', 'value', (err) => { t.error(err) fastify.redis.test.get('key', (err, val) => { t.error(err) t.equal(val, 'value') fastify.close(function (err) { t.error(err) fastify.redis.test.quit(function (err) { t.error(err) }) }) }) }) }) }) test('custom client inside a namespace gets closed', (t) => { t.plan(7) const fastify = Fastify() const redis = require('redis').createClient({ host: 'localhost', port: 6379 }) fastify.register(fastifyRedis, { namespace: 'test', client: redis, closeClient: true }) fastify.ready((err) => { t.error(err) t.equal(fastify.redis.test, redis) fastify.redis.test.set('key', 'value', (err) => { t.error(err) fastify.redis.test.get('key', (err, val) => { t.error(err) t.equal(val, 'value') const origQuit = fastify.redis.test.quit fastify.redis.test.quit = (cb) => { t.pass('redis client closed') origQuit.call(fastify.redis.test, cb) } fastify.close(function (err) { t.error(err) }) }) }) }) }) test('fastify.redis.test should throw with duplicate connection namespaces', (t) => { t.plan(1) const namespace = 'test' const fastify = Fastify() t.teardown(() => fastify.close()) fastify .register(fastifyRedis, { host: '127.0.0.1', namespace }) .register(fastifyRedis, { host: '127.0.0.1', namespace }) fastify.ready((err) => { t.equal(err.message, `Redis '${namespace}' instance namespace has already been registered`) }) }) test('Should throw when trying to register multiple instances without giving a namespace', (t) => { t.plan(1) const fastify = Fastify() t.teardown(() => fastify.close()) fastify .register(fastifyRedis, { host: '127.0.0.1' }) .register(fastifyRedis, { host: '127.0.0.1' }) fastify.ready((err) => { t.equal(err.message, 'fastify-redis has already been registered') }) }) test('Should not throw within different contexts', (t) => { t.plan(1) const fastify = Fastify() t.teardown(() => fastify.close()) fastify.register(function (instance, options, next) { instance.register(fastifyRedis, { host: '127.0.0.1' }) next() }) fastify.register(function (instance, options, next) { instance .register(fastifyRedis, { host: '127.0.0.1', namespace: 'test1' }) .register(fastifyRedis, { host: '127.0.0.1', namespace: 'test2' }) next() }) fastify.ready((error) => { t.error(error) }) }) test('Should throw when trying to connect on an invalid host', (t) => { t.plan(1) const fastify = Fastify({ pluginTimeout: 20000 }) t.teardown(() => fastify.close()) fastify .register(fastifyRedis, { host: 'invalid_host' }) fastify.ready((err) => { t.ok(err) }) }) test('Should not throw when trying to connect on an invalid host but the lazyConnect option has been provided', (t) => { t.plan(1) const fastify = Fastify() t.teardown(() => fastify.close()) fastify .register(fastifyRedis, { host: 'invalid_host', lazyConnect: true }) fastify.ready((err) => { t.error(err) }) }) test('Should throw authentication error when trying to connect on a valid host with a wrong password', (t) => { t.plan(1) const fastify = Fastify() t.teardown(async () => { fastify.close() await unsetRedisPassword(TEST_PASSWORD) }) setRedisPassword(TEST_PASSWORD) .then(_ => { fastify.register(fastifyRedis, { host: '127.0.0.1', password: 'my_wrong_secret_password' }) fastify.ready(err => { t.ok(err) }) }) }) test('Should throw authentication error when trying to connect on a valid host without a password', (t) => { t.plan(1) const fastify = Fastify() t.teardown(async () => { fastify.close() await unsetRedisPassword(TEST_PASSWORD) }) setRedisPassword(TEST_PASSWORD) .then(_ => { fastify.register(fastifyRedis, { host: '127.0.0.1' }) fastify.ready(err => { t.ok(err) }) }) }) test('Should successfully create a Redis client when registered with a `url` option and without a `client` option in a namespaced instance', async t => { t.plan(2) const fastify = Fastify() t.teardown(fastify.close.bind(fastify)) await fastify.register(fastifyRedis, { url: 'redis://127.0.0.1', namespace: 'test' }) await fastify.ready() t.ok(fastify.redis) t.ok(fastify.redis.test) }) test('Should be able to register multiple namespaced fastify-redis instances', async t => { t.plan(3) const fastify = Fastify() t.teardown(fastify.close.bind(fastify)) await fastify.register(fastifyRedis, { url: 'redis://127.0.0.1', namespace: 'one' }) await fastify.register(fastifyRedis, { url: 'redis://127.0.0.1', namespace: 'two' }) await fastify.ready() t.ok(fastify.redis) t.ok(fastify.redis.one) t.ok(fastify.redis.two) }) test('Should throw when fastify-redis is initialized with an option that makes Redis throw', (t) => { t.plan(1) const fastify = Fastify() t.teardown(fastify.close.bind(fastify)) // This will throw a `TypeError: this.options.Connector is not a constructor` fastify.register(fastifyRedis, { Connector: 'should_fail' }) fastify.ready(err => { t.ok(err) }) }) test('Should throw when fastify-redis is initialized with a namespace and an option that makes Redis throw', (t) => { t.plan(1) const fastify = Fastify() t.teardown(fastify.close.bind(fastify)) // This will throw a `TypeError: this.options.Connector is not a constructor` fastify.register(fastifyRedis, { Connector: 'should_fail', namespace: 'fail' }) fastify.ready(err => { t.ok(err) }) })