'use strict' const assert = require('assert') const path = require('path') const config = require('./lib/config') const RedisProcess = require('./lib/redis-process') const StunnelProcess = require('./lib/stunnel-process') let rp let stunnelProcess function startRedis (conf, done, port) { RedisProcess.start((err, _rp) => { rp = _rp return done(err) }, path.resolve(__dirname, conf), port) } // don't start redis every time we // include this helper file! if (!process.env.REDIS_TESTS_STARTED) { process.env.REDIS_TESTS_STARTED = true before((done) => { startRedis('./conf/redis.conf', done) }) after((done) => { if (rp) rp.stop(done) }) } function arrayHelper (results) { if (results instanceof Array) { assert.strictEqual(results.length, 1, 'The array length may only be one element') return results[0] } return results } function toString (res) { // If options are passed to return either strings or buffers... if (Buffer.isBuffer(res)) { return res.toString() } if (Array.isArray(res)) { return res.map(toString) } return res } module.exports = { redisProcess () { return rp }, stopRedis (done) { rp.stop(done) }, startRedis, stopStunnel (done) { if (stunnelProcess) { StunnelProcess.stop(stunnelProcess, done) } else { done() } }, startStunnel (done) { StunnelProcess.start((err, _stunnelProcess) => { stunnelProcess = _stunnelProcess return done(err) }, path.resolve(__dirname, './conf')) }, isNumber (expected, done) { return function (err, results) { assert.strictEqual(err, null, `expected ${expected}, got error: ${err}`) results = arrayHelper(results) assert.strictEqual(results, expected, `${expected } !== ${results}`) assert.strictEqual(typeof results, 'number', `expected a number, got ${typeof results}`) if (done) done() } }, isString (str, done) { str = `${str}` // Make sure it's a string return function (err, results) { assert.strictEqual(err, null, `expected string '${str}', got error: ${err}`) results = arrayHelper(results) results = toString(results) assert.strictEqual(results, str, `${str } does not match ${results}`) if (done) done() } }, isNull (done) { return function (err, results) { assert.strictEqual(err, null, `expected null, got error: ${err}`) results = arrayHelper(results) assert.strictEqual(results, null, `${results } is not null`) if (done) done() } }, isUndefined (done) { return function (err, results) { assert.strictEqual(err, null, `expected null, got error: ${err}`) results = arrayHelper(results) assert.strictEqual(results, undefined, `${results } is not undefined`) if (done) done() } }, isError (done) { return function (err, results) { assert(err instanceof Error, 'err is not instance of \'Error\', but an error is expected here.') if (done) done() } }, isNotError (done) { return function (err, results) { assert.strictEqual(err, null, `expected success, got an error: ${err}`) if (done) done() } }, isDeepEqual (args, done) { return function (err, res) { assert.strictEqual(err, null, `expected null, got error: ${err}`) res = toString(res) assert.deepStrictEqual(res, args) if (done) done() } }, isType: { number (done) { return function (err, results) { assert.strictEqual(err, null, `expected any number, got error: ${err}`) assert.strictEqual(typeof results, 'number', `${results } is not a number`) if (done) done() } }, string (done) { return function (err, results) { assert.strictEqual(err, null, `expected any string, got error: ${err}`) assert.strictEqual(typeof results, 'string', `${results } is not a string`) if (done) done() } }, positiveNumber (done) { return function (err, results) { assert.strictEqual(err, null, `expected positive number, got error: ${err}`) assert(results > 0, `${results } is not a positive number`) if (done) done() } } }, match (pattern, done) { return function (err, results) { assert.strictEqual(err, null, `expected ${pattern.toString()}, got error: ${err}`) results = arrayHelper(results) assert(pattern.test(results), `expected string '${results}' to match ${pattern.toString()}`) if (done) done() } }, serverVersionAtLeast (connection, desiredVersion) { // Wait until a connection has established (otherwise a timeout is going to be triggered at some point) if (Object.keys(connection.serverInfo).length === 0) { throw new Error('Version check not possible as the client is not yet ready or did not expose the version') } // Return true if the server version >= desiredVersion const version = connection.serverInfo.versions for (let i = 0; i < 3; i++) { if (version[i] > desiredVersion[i]) { return true } if (version[i] < desiredVersion[i]) { if (this.skip) this.skip() return false } } return true }, allTests (opts, cb) { if (!cb) { cb = opts opts = {} } const protocols = ['IPv4'] if (process.platform !== 'win32') { protocols.push('IPv6', '/tmp/redis.sock') } const options = [{ detectBuffers: true }, { detectBuffers: false }] options.forEach((options) => { let strOptions = '' let key for (key in options) { if (options.hasOwnProperty(key)) { strOptions += `${key }: ${options[key]}; ` } } describe(`using options: ${strOptions}`, () => { protocols.forEach((ip, i) => { if (i !== 0 && !opts.allConnections) { return } cb(ip, config.configureClient(ip, options)) }) }) }) }, removeMochaListener () { const mochaListener = process.listeners('uncaughtException').pop() process.removeListener('uncaughtException', mochaListener) return mochaListener }, callFuncAfter (func, max) { let i = 0 return function (err) { if (err) { throw err } i++ if (i >= max) { func() return true } return false } }, killConnection (client) { // Change the connection option to a non existing one and destroy the stream client.connectionOptions = { port: 65535, host: '127.0.0.1', family: 4 } client.address = '127.0.0.1:65535' client.stream.destroy() } }