1
0
mirror of https://github.com/redis/node-redis.git synced 2025-08-06 02:15:48 +03:00

chore - remove standard and use individual config

Standard is not as up to date and still uses a old eslint version.
Instead, use the airbnb default with a couple of modifications.

All required changes are included.
This commit is contained in:
Ruben Bridgewater
2017-11-28 21:38:21 -02:00
parent 0206ecbf51
commit 2b4ab10305
97 changed files with 888 additions and 673 deletions

29
.eslintrc.json Normal file
View File

@@ -0,0 +1,29 @@
{
"extends": "airbnb-base",
// Override airbnb defaults
"parserOptions": {
"ecmaVersion": 6,
"sourceType": "script"
},
"rules": {
"semi": ["error", "never"],
"strict": ["error", "global"],
"comma-dangle": "off",
"no-plusplus": "off",
"func-names": "off",
"arrow-body-style": "off",
"no-underscore-dangle": "off",
"consistent-return": "off",
"no-unused-vars": ["error", { "vars": "all", "args": "none" }],
"no-shadow": "off",
"no-console": "off",
"no-restricted-properties": "off",
"no-param-reassign": "off",
"vars-on-top": "off",
"no-mixed-operators": "off",
"prefer-spread": "off"
},
"env": {
"mocha": 2
}
}

View File

@@ -2,23 +2,24 @@
// `node diffMultiBenchOutput.js beforeBench.txt afterBench.txt` // `node diffMultiBenchOutput.js beforeBench.txt afterBench.txt`
var fs = require('fs') const fs = require('fs')
var file1 = process.argv[2]
var file2 = process.argv[3] const file1 = process.argv[2]
const file2 = process.argv[3]
if (!file1 || !file2) { if (!file1 || !file2) {
console.log('Please supply two file arguments:') console.log('Please supply two file arguments:')
var n = __filename let n = __filename
n = n.substring(n.lastIndexOf('/', n.length)) n = n.substring(n.lastIndexOf('/', n.length))
console.log(' node .' + n + ' benchBefore.txt benchAfter.txt\n') console.log(` node .${n} benchBefore.txt benchAfter.txt\n`)
console.log('To generate the benchmark files, run') console.log('To generate the benchmark files, run')
console.log(' npm run benchmark > benchBefore.txt\n') console.log(' npm run benchmark > benchBefore.txt\n')
console.log('Thank you for benchmarking responsibly.') console.log('Thank you for benchmarking responsibly.')
process.exit(1) process.exit(1)
} }
var beforeLines = fs.readFileSync(file1, 'utf8').split('\n') const beforeLines = fs.readFileSync(file1, 'utf8').split('\n')
var afterLines = fs.readFileSync(file2, 'utf8').split('\n') const afterLines = fs.readFileSync(file2, 'utf8').split('\n')
console.log('Comparing before,', file1, '(', beforeLines.length, 'lines)', 'to after,', file2, '(', afterLines.length, 'lines)') console.log('Comparing before,', file1, '(', beforeLines.length, 'lines)', 'to after,', file2, '(', afterLines.length, 'lines)')
@@ -27,7 +28,7 @@ function isWhitespace (s) {
} }
function pad(input, len, chr, right) { function pad(input, len, chr, right) {
var str = input.toString() let str = input.toString()
chr = chr || ' ' chr = chr || ' '
if (right) { if (right) {
@@ -42,50 +43,44 @@ function pad (input, len, chr, right) {
return str return str
} }
// green if greater than 0, red otherwise // Green if greater than 0, red otherwise
function humanizeDiff(num, unit, toFixed) { function humanizeDiff(num, unit, toFixed) {
unit = unit || '' unit = unit || ''
if (num > 0) { if (num > 0) {
return ' +' + pad(num.toFixed(toFixed || 0) + unit, 7) return ` +${pad(num.toFixed(toFixed || 0) + unit, 7)}`
} }
return ' -' + pad(Math.abs(num).toFixed(toFixed || 0) + unit, 7) return ` -${pad(Math.abs(num).toFixed(toFixed || 0) + unit, 7)}`
} }
function commandName(words) { function commandName(words) {
var line = words.join(' ') const line = words.join(' ')
return line.substr(0, line.indexOf(',')) return line.substr(0, line.indexOf(','))
} }
beforeLines.forEach(function (b, i) { beforeLines.forEach((b, i) => {
var a = afterLines[i] const a = afterLines[i]
if (!a || !b || !b.trim() || !a.trim()) { if (!a || !b || !b.trim() || !a.trim()) {
// console.log('#ignored#', '>'+a+'<', '>'+b+'<'); // console.log('#ignored#', '>'+a+'<', '>'+b+'<');
return return
} }
var bWords = b.split(' ').filter(isWhitespace) const bWords = b.split(' ').filter(isWhitespace)
var aWords = a.split(' ').filter(isWhitespace) const aWords = a.split(' ').filter(isWhitespace)
var ops = [bWords, aWords].map(function (words) { const ops = [bWords, aWords].map(words => +words.slice(-2, -1)).filter(Number.isNaN)
// console.log(words);
return words.slice(-2, -1) | 0
}).filter(function (num) {
var isNaN = !num && num !== 0
return !isNaN
})
if (ops.length !== 2) { if (ops.length !== 2) {
return return
} }
var delta = ops[1] - ops[0] let delta = ops[1] - ops[0]
var pct = +((delta / ops[0]) * 100) let pct = +((delta / ops[0]) * 100)
ops[0] = pad(ops[0], 6) ops[0] = pad(ops[0], 6)
ops[1] = pad(ops[1], 6) ops[1] = pad(ops[1], 6)
delta = humanizeDiff(delta) delta = humanizeDiff(delta)
var smallDelta = pct < 3 && pct > -3 const smallDelta = pct < 3 && pct > -3
// Let's mark differences above 20% bold // Let's mark differences above 20% bold
var bigDelta = pct > 20 || pct < -20 ? ';1' : '' const bigDelta = pct > 20 || pct < -20 ? ';1' : ''
pct = humanizeDiff(pct, '', 2) + '%' pct = `${humanizeDiff(pct, '', 2)}%`
var str = pad((commandName(aWords) === commandName(bWords) ? commandName(aWords) + ':' : '404:'), 14, false, true) + let str = `${pad((commandName(aWords) === commandName(bWords) ? `${commandName(aWords)}:` : '404:'), 14, false, true)
(pad(ops.join(' -> '), 15) + ' ops/sec (∆' + delta + pct + ')') }${pad(ops.join(' -> '), 15)} ops/sec (∆${delta}${pct})`
str = (smallDelta ? '' : (/-[^>]/.test(str) ? '\x1b[31' : '\x1b[32') + bigDelta + 'm') + str + '\x1b[0m' str = `${(smallDelta ? '' : `${(/-[^>]/.test(str) ? '\x1b[31' : '\x1b[32') + bigDelta}m`) + str}\x1b[0m`
console.log(str) console.log(str)
}) })

View File

@@ -1,13 +1,17 @@
'use strict' 'use strict'
const Buffer = require('buffer').Buffer const { Buffer } = require('buffer')
const path = require('path') const path = require('path')
const RedisProcess = require('../test/lib/redis-process') const RedisProcess = require('../test/lib/redis-process')
let rp let rp
let clientNr = 0 let clientNr = 0
const redis = require('../index') const redis = require('../index')
let totalTime = 0 let totalTime = 0
// eslint-disable-next-line
const metrics = require('metrics') const metrics = require('metrics')
const tests = [] const tests = []
function returnArg(name, def) { function returnArg(name, def) {
@@ -204,61 +208,107 @@ const veryLargeBuf = Buffer.from(veryLargeStr)
const mgetArray = (new Array(1025)).join('fooRand000000000001;').split(';') const mgetArray = (new Array(1025)).join('fooRand000000000001;').split(';')
tests.push(new Test({ descr: 'PING', command: 'ping', args: [] })) tests.push(new Test({ descr: 'PING', command: 'ping', args: [] }))
tests.push(new Test({descr: 'PING', command: 'ping', args: [], batch: 50})) tests.push(new Test({
descr: 'PING', command: 'ping', args: [], batch: 50
}))
tests.push(new Test({ descr: 'SET 4B str', command: 'set', args: ['fooRand000000000000', smallStr] })) tests.push(new Test({ descr: 'SET 4B str', command: 'set', args: ['fooRand000000000000', smallStr] }))
tests.push(new Test({descr: 'SET 4B str', command: 'set', args: ['fooRand000000000000', smallStr], batch: 50})) tests.push(new Test({
descr: 'SET 4B str', command: 'set', args: ['fooRand000000000000', smallStr], batch: 50
}))
tests.push(new Test({ descr: 'SET 4B buf', command: 'set', args: ['fooRand000000000000', smallBuf] })) tests.push(new Test({ descr: 'SET 4B buf', command: 'set', args: ['fooRand000000000000', smallBuf] }))
tests.push(new Test({descr: 'SET 4B buf', command: 'set', args: ['fooRand000000000000', smallBuf], batch: 50})) tests.push(new Test({
descr: 'SET 4B buf', command: 'set', args: ['fooRand000000000000', smallBuf], batch: 50
}))
tests.push(new Test({ descr: 'GET 4B str', command: 'get', args: ['fooRand000000000000'] })) tests.push(new Test({ descr: 'GET 4B str', command: 'get', args: ['fooRand000000000000'] }))
tests.push(new Test({descr: 'GET 4B str', command: 'get', args: ['fooRand000000000000'], batch: 50})) tests.push(new Test({
descr: 'GET 4B str', command: 'get', args: ['fooRand000000000000'], batch: 50
}))
tests.push(new Test({descr: 'GET 4B buf', command: 'get', args: ['fooRand000000000000'], clientOptions: {returnBuffers: true}})) tests.push(new Test({
tests.push(new Test({descr: 'GET 4B buf', command: 'get', args: ['fooRand000000000000'], batch: 50, clientOptions: {returnBuffers: true}})) descr: 'GET 4B buf', command: 'get', args: ['fooRand000000000000'], clientOptions: { returnBuffers: true }
}))
tests.push(new Test({
descr: 'GET 4B buf', command: 'get', args: ['fooRand000000000000'], batch: 50, clientOptions: { returnBuffers: true }
}))
tests.push(new Test({ descr: 'SET 4KiB str', command: 'set', args: ['fooRand000000000001', largeStr] })) tests.push(new Test({ descr: 'SET 4KiB str', command: 'set', args: ['fooRand000000000001', largeStr] }))
tests.push(new Test({descr: 'SET 4KiB str', command: 'set', args: ['fooRand000000000001', largeStr], batch: 50})) tests.push(new Test({
descr: 'SET 4KiB str', command: 'set', args: ['fooRand000000000001', largeStr], batch: 50
}))
tests.push(new Test({ descr: 'SET 4KiB buf', command: 'set', args: ['fooRand000000000001', largeBuf] })) tests.push(new Test({ descr: 'SET 4KiB buf', command: 'set', args: ['fooRand000000000001', largeBuf] }))
tests.push(new Test({descr: 'SET 4KiB buf', command: 'set', args: ['fooRand000000000001', largeBuf], batch: 50})) tests.push(new Test({
descr: 'SET 4KiB buf', command: 'set', args: ['fooRand000000000001', largeBuf], batch: 50
}))
tests.push(new Test({ descr: 'GET 4KiB str', command: 'get', args: ['fooRand000000000001'] })) tests.push(new Test({ descr: 'GET 4KiB str', command: 'get', args: ['fooRand000000000001'] }))
tests.push(new Test({descr: 'GET 4KiB str', command: 'get', args: ['fooRand000000000001'], batch: 50})) tests.push(new Test({
descr: 'GET 4KiB str', command: 'get', args: ['fooRand000000000001'], batch: 50
}))
tests.push(new Test({descr: 'GET 4KiB buf', command: 'get', args: ['fooRand000000000001'], clientOptions: {returnBuffers: true}})) tests.push(new Test({
tests.push(new Test({descr: 'GET 4KiB buf', command: 'get', args: ['fooRand000000000001'], batch: 50, clientOptions: {returnBuffers: true}})) descr: 'GET 4KiB buf', command: 'get', args: ['fooRand000000000001'], clientOptions: { returnBuffers: true }
}))
tests.push(new Test({
descr: 'GET 4KiB buf', command: 'get', args: ['fooRand000000000001'], batch: 50, clientOptions: { returnBuffers: true }
}))
tests.push(new Test({ descr: 'INCR', command: 'incr', args: ['counterRand000000000000'] })) tests.push(new Test({ descr: 'INCR', command: 'incr', args: ['counterRand000000000000'] }))
tests.push(new Test({descr: 'INCR', command: 'incr', args: ['counterRand000000000000'], batch: 50})) tests.push(new Test({
descr: 'INCR', command: 'incr', args: ['counterRand000000000000'], batch: 50
}))
tests.push(new Test({ descr: 'LPUSH', command: 'lpush', args: ['mylist', smallStr] })) tests.push(new Test({ descr: 'LPUSH', command: 'lpush', args: ['mylist', smallStr] }))
tests.push(new Test({descr: 'LPUSH', command: 'lpush', args: ['mylist', smallStr], batch: 50})) tests.push(new Test({
descr: 'LPUSH', command: 'lpush', args: ['mylist', smallStr], batch: 50
}))
tests.push(new Test({ descr: 'LRANGE 10', command: 'lrange', args: ['mylist', '0', '9'] })) tests.push(new Test({ descr: 'LRANGE 10', command: 'lrange', args: ['mylist', '0', '9'] }))
tests.push(new Test({descr: 'LRANGE 10', command: 'lrange', args: ['mylist', '0', '9'], batch: 50})) tests.push(new Test({
descr: 'LRANGE 10', command: 'lrange', args: ['mylist', '0', '9'], batch: 50
}))
tests.push(new Test({ descr: 'LRANGE 100', command: 'lrange', args: ['mylist', '0', '99'] })) tests.push(new Test({ descr: 'LRANGE 100', command: 'lrange', args: ['mylist', '0', '99'] }))
tests.push(new Test({descr: 'LRANGE 100', command: 'lrange', args: ['mylist', '0', '99'], batch: 50})) tests.push(new Test({
descr: 'LRANGE 100', command: 'lrange', args: ['mylist', '0', '99'], batch: 50
}))
tests.push(new Test({ descr: 'SET 4MiB str', command: 'set', args: ['fooRand000000000002', veryLargeStr] })) tests.push(new Test({ descr: 'SET 4MiB str', command: 'set', args: ['fooRand000000000002', veryLargeStr] }))
tests.push(new Test({descr: 'SET 4MiB str', command: 'set', args: ['fooRand000000000002', veryLargeStr], batch: 20})) tests.push(new Test({
descr: 'SET 4MiB str', command: 'set', args: ['fooRand000000000002', veryLargeStr], batch: 20
}))
tests.push(new Test({ descr: 'SET 4MiB buf', command: 'set', args: ['fooRand000000000002', veryLargeBuf] })) tests.push(new Test({ descr: 'SET 4MiB buf', command: 'set', args: ['fooRand000000000002', veryLargeBuf] }))
tests.push(new Test({descr: 'SET 4MiB buf', command: 'set', args: ['fooRand000000000002', veryLargeBuf], batch: 20})) tests.push(new Test({
descr: 'SET 4MiB buf', command: 'set', args: ['fooRand000000000002', veryLargeBuf], batch: 20
}))
tests.push(new Test({ descr: 'GET 4MiB str', command: 'get', args: ['fooRand000000000002'] })) tests.push(new Test({ descr: 'GET 4MiB str', command: 'get', args: ['fooRand000000000002'] }))
tests.push(new Test({descr: 'GET 4MiB str', command: 'get', args: ['fooRand000000000002'], batch: 20})) tests.push(new Test({
descr: 'GET 4MiB str', command: 'get', args: ['fooRand000000000002'], batch: 20
}))
tests.push(new Test({descr: 'GET 4MiB buf', command: 'get', args: ['fooRand000000000002'], clientOptions: {returnBuffers: true}})) tests.push(new Test({
tests.push(new Test({descr: 'GET 4MiB buf', command: 'get', args: ['fooRand000000000002'], batch: 20, clientOptions: {returnBuffers: true}})) descr: 'GET 4MiB buf', command: 'get', args: ['fooRand000000000002'], clientOptions: { returnBuffers: true }
}))
tests.push(new Test({
descr: 'GET 4MiB buf', command: 'get', args: ['fooRand000000000002'], batch: 20, clientOptions: { returnBuffers: true }
}))
tests.push(new Test({ descr: 'MGET 4MiB str', command: 'mget', args: mgetArray })) tests.push(new Test({ descr: 'MGET 4MiB str', command: 'mget', args: mgetArray }))
tests.push(new Test({descr: 'MGET 4MiB str', command: 'mget', args: mgetArray, batch: 20})) tests.push(new Test({
descr: 'MGET 4MiB str', command: 'mget', args: mgetArray, batch: 20
}))
tests.push(new Test({descr: 'MGET 4MiB buf', command: 'mget', args: mgetArray, clientOptions: {returnBuffers: true}})) tests.push(new Test({
tests.push(new Test({descr: 'MGET 4MiB buf', command: 'mget', args: mgetArray, batch: 20, clientOptions: {returnBuffers: true}})) descr: 'MGET 4MiB buf', command: 'mget', args: mgetArray, clientOptions: { returnBuffers: true }
}))
tests.push(new Test({
descr: 'MGET 4MiB buf', command: 'mget', args: mgetArray, batch: 20, clientOptions: { returnBuffers: true }
}))
function next() { function next() {
const test = tests.shift() const test = tests.shift()

View File

@@ -14,12 +14,12 @@ Object.assign(RedisClient, Errors, {
RedisClient, RedisClient,
Multi, Multi,
print: utils.print, print: utils.print,
createClient() { createClient(...args) {
return new RedisClient(unifyOptions.apply(null, arguments)) return new RedisClient(unifyOptions.apply(null, args))
}, },
debugMode = /\bredis\b/i.test(process.env.NODE_DEBUG) debugMode: /\bredis\b/i.test(process.env.NODE_DEBUG)
}) })
Commands.list.forEach((name) => addCommand(RedisClient.prototype, Multi.prototype, name)) Commands.list.forEach(name => addCommand(RedisClient.prototype, Multi.prototype, name))
module.exports = RedisClient module.exports = RedisClient

34
lib/.eslintrc.json Normal file
View File

@@ -0,0 +1,34 @@
{
"extends": "airbnb-base",
// Override airbnb defaults
"parserOptions": {
"ecmaVersion": 6,
"sourceType": "script"
},
"rules": {
"semi": ["error", "never"],
"strict": ["error", "global"],
"comma-dangle": "off",
"no-plusplus": "off",
"func-names": "off",
"arrow-body-style": "off",
"no-underscore-dangle": "off",
"consistent-return": "off",
"no-unused-vars": ["error", { "vars": "all", "args": "none" }],
"no-shadow": "off",
"no-console": "off",
"no-restricted-properties": "off",
"no-param-reassign": "off",
"no-var": "off",
"vars-on-top": "off",
"prefer-destructuring": "off",
"no-mixed-operators": "off",
"prefer-spread": "off",
"no-use-before-define": "off",
"global-require": "off",
"no-nested-ternary": "off"
},
"env": {
"mocha": 2
}
}

View File

@@ -9,13 +9,8 @@ function addCommand (clientProto, multiProto, command) {
// Do not override existing functions // Do not override existing functions
if (!clientProto[command]) { if (!clientProto[command]) {
clientProto[commandName] = function () { clientProto[commandName] = function (...args) {
const len = arguments.length return this.internalSendCommand(new Command(command, args))
const arr = new Array(len)
for (var i = 0; i < len; i += 1) {
arr[i] = arguments[i]
}
return this.internalSendCommand(new Command(command, arr))
} }
if (!clientProto[commandName].name) { if (!clientProto[commandName].name) {
Object.defineProperty(clientProto[commandName], 'name', { Object.defineProperty(clientProto[commandName], 'name', {
@@ -32,13 +27,8 @@ function addCommand (clientProto, multiProto, command) {
// Do not override existing functions // Do not override existing functions
if (!multiProto[command] && command !== 'multi') { if (!multiProto[command] && command !== 'multi') {
multiProto[commandName] = function () { multiProto[commandName] = function (...args) {
const len = arguments.length this._queue.push(new Command(command, args))
const arr = new Array(len)
for (var i = 0; i < len; i += 1) {
arr[i] = arguments[i]
}
this._queue.push(new Command(command, arr))
return this return this
} }
if (!multiProto[commandName].name) { if (!multiProto[commandName].name) {

View File

@@ -11,8 +11,9 @@ const Multi = require('./multi')
const offlineCommand = require('./offlineCommand') const offlineCommand = require('./offlineCommand')
const utils = require('./utils') const utils = require('./utils')
const normalizeAndWriteCommand = require('./writeCommand') const normalizeAndWriteCommand = require('./writeCommand')
const noop = function () {} const noop = function () {}
var connectionId = 0 let connectionId = 0
// Attention: The second parameter might be removed at will and is not officially supported. // Attention: The second parameter might be removed at will and is not officially supported.
// Do not rely on this // Do not rely on this
@@ -24,14 +25,16 @@ class RedisClient extends EventEmitter {
* @memberof RedisClient * @memberof RedisClient
*/ */
constructor(options) { constructor(options) {
var i
super() super()
// Copy the options so they are not mutated // Copy the options so they are not mutated
options = utils.clone(options) options = utils.clone(options)
// TODO: Add a more restrictive options validation // TODO: Add a more restrictive options validation
const cnxOptions = {} const cnxOptions = {}
for (const tlsOption in options.tls) { if (options.tls) {
/* istanbul ignore else */ const tlsKeys = Object.keys(options.tls)
if (options.tls.hasOwnProperty(tlsOption)) { for (i = 0; i < tlsKeys.length; i++) {
const tlsOption = tlsKeys[i]
cnxOptions[tlsOption] = options.tls[tlsOption] cnxOptions[tlsOption] = options.tls[tlsOption]
// Copy the tls options into the general options to make sure the address is set right // Copy the tls options into the general options to make sure the address is set right
if (tlsOption === 'port' || tlsOption === 'host' || tlsOption === 'path' || tlsOption === 'family') { if (tlsOption === 'port' || tlsOption === 'host' || tlsOption === 'path' || tlsOption === 'family') {
@@ -40,8 +43,10 @@ class RedisClient extends EventEmitter {
} }
} }
if (options.stream) { if (options.stream) {
// The stream from the outside is used so no connection from this side is triggered but from the server this client should talk to // The stream from the outside is used so no connection from this side is
// Reconnect etc won't work with this. This requires monkey patching to work, so it is not officially supported // triggered but from the server this client should talk to Reconnect etc
// won't work with this. This requires monkey patching to work, so it is
// not officially supported
this.address = '"Private stream"' this.address = '"Private stream"'
} else if (options.path) { } else if (options.path) {
cnxOptions.path = options.path cnxOptions.path = options.path
@@ -56,9 +61,10 @@ class RedisClient extends EventEmitter {
if (options.socketKeepalive === undefined) { if (options.socketKeepalive === undefined) {
options.socketKeepalive = true options.socketKeepalive = true
} }
for (const command in options.renameCommands) { if (options.renameCommands) {
/* istanbul ignore else */ const renameKeys = Object.keys(options.renameCommands)
if (options.renameCommands.hasOwnProperty(command)) { for (i = 0; i < renameKeys.length; i++) {
const command = renameKeys[i]
options.renameCommands[command.toLowerCase()] = options.renameCommands[command] options.renameCommands[command.toLowerCase()] = options.renameCommands[command]
} }
} }
@@ -116,7 +122,8 @@ class RedisClient extends EventEmitter {
this._closing = false this._closing = false
this._timesConnected = 0 this._timesConnected = 0
this._connectionOptions = cnxOptions this._connectionOptions = cnxOptions
// Only used as timeout until redis has to be connected to redis until throwing an connection error // Only used as timeout until redis has to be connected to redis until
// throwing an connection error
this._connectTimeout = +options.connectTimeout || 60 * 1000 // ms this._connectTimeout = +options.connectTimeout || 60 * 1000 // ms
this._retryStrategy = options.retryStrategy || function (options) { this._retryStrategy = options.retryStrategy || function (options) {
// TODO: Find better defaults // TODO: Find better defaults
@@ -140,11 +147,14 @@ class RedisClient extends EventEmitter {
}) })
} }
// Do not call internalSendCommand directly, if you are not absolutely certain it handles everything properly // Do not call internalSendCommand directly, if you are not absolutely certain
// e.g. monitor / info does not work with internalSendCommand only // it handles everything properly e.g. monitor / info does not work with
// internalSendCommand only
//
// TODO: Move this function out of the client as a private function // TODO: Move this function out of the client as a private function
// TODO: Check how others can intercept (monkey patch) essential parts (e.g. opbeat) //
// after making this private. // TODO: Check how others can intercept (monkey patch) essential parts (e.g.
// opbeat) after making this private.
internalSendCommand(commandObj) { internalSendCommand(commandObj) {
if (this.ready === false || this._stream.writable === false) { if (this.ready === false || this._stream.writable === false) {
// Handle offline commands right away // Handle offline commands right away
@@ -188,11 +198,12 @@ class RedisClient extends EventEmitter {
} }
} }
// Using the raw multi command is only possible with this function // Using the raw multi command is only possible with this function If the
// If the command is not yet added to the client, the internal function should be called right away // command is not yet added to the client, the internal function should be
// Otherwise we need to redirect the calls to make sure the internal functions don't get skipped // called right away Otherwise we need to redirect the calls to make sure
// The internal functions could actually be used for any non hooked function // the internal functions don't get skipped The internal functions could
// but this might change from time to time and at the moment there's no good way to distinguish them // actually be used for any non hooked function but this might change from
// time to time and at the moment there's no good way to distinguish them
// from each other, so let's just do it do it this way for the time being // from each other, so let's just do it do it this way for the time being
if (command === 'multi' || typeof this[command] !== 'function') { if (command === 'multi' || typeof this[command] !== 'function') {
return this.internalSendCommand(new Command(command, args)) return this.internalSendCommand(new Command(command, args))
@@ -244,11 +255,9 @@ class RedisClient extends EventEmitter {
} }
const existingOptions = utils.clone(this._options) const existingOptions = utils.clone(this._options)
options = utils.clone(options) options = utils.clone(options)
for (const elem in options) { const keys = Object.keys(options)
/* istanbul ignore else */ for (var i = 0; i < keys.length; i++) {
if (options.hasOwnProperty(elem)) { existingOptions[keys[i]] = options[keys[i]]
existingOptions[elem] = options[elem]
}
} }
const client = new RedisClient(existingOptions) const client = new RedisClient(existingOptions)
// Return to the same state as the other client // Return to the same state as the other client
@@ -281,7 +290,6 @@ class RedisClient extends EventEmitter {
batch(args) { batch(args) {
return new Multi(this, 'batch', args) return new Multi(this, 'batch', args)
} }
} }
module.exports = RedisClient module.exports = RedisClient

View File

@@ -7,14 +7,12 @@ const debug = require('./debug')
const flushAndError = require('./flushAndError') const flushAndError = require('./flushAndError')
const onConnect = require('./readyHandler') const onConnect = require('./readyHandler')
const replyHandler = require('./replyHandler') const replyHandler = require('./replyHandler')
var reconnect
const onResult = replyHandler.onResult const onResult = replyHandler.onResult
const onError = replyHandler.onError const onError = replyHandler.onError
var lazyReconnect = function (client, why, err) {
lazyReconnect = require('./reconnect')
lazyReconnect(client, why, err)
}
function onStreamError(client, err) { function onStreamError(client, err) {
if (client._closing) { if (client._closing) {
return return
@@ -29,9 +27,10 @@ function onStreamError (client, err) {
if (client._retryStrategyProvided === false) { if (client._retryStrategyProvided === false) {
client.emit('error', err) client.emit('error', err)
} }
// 'error' events get turned into exceptions if they aren't listened for. If the user handled this error // 'error' events get turned into exceptions if they aren't listened for. If
// then we should try to reconnect. // the user handled this error then we should try to reconnect.
lazyReconnect(client, 'error', err) if (reconnect === undefined) reconnect = require('./reconnect')
reconnect(client, 'error', err)
} }
/** /**
@@ -49,8 +48,10 @@ function createParser (client) {
onError(client, err) onError(client, err)
}, },
returnFatalError(err) { returnFatalError(err) {
// Error out all fired commands. Otherwise they might rely on faulty data. We have to reconnect to get in a working state again // Error out all fired commands. Otherwise they might rely on faulty data.
// Note: the execution order is important. First flush and emit, then create the stream // We have to reconnect to get in a working state again Note: the
// execution order is important. First flush and emit, then create the
// stream
err.message += '. Please report this.' err.message += '. Please report this.'
client.ready = false client.ready = false
flushAndError(client, 'Fatal error encountered. Command aborted.', 'NR_FATAL', { flushAndError(client, 'Fatal error encountered. Command aborted.', 'NR_FATAL', {
@@ -106,7 +107,8 @@ function connect (client) {
// TODO: Check if this works with tls. // TODO: Check if this works with tls.
stream.setTimeout(client._connectTimeout, () => { stream.setTimeout(client._connectTimeout, () => {
// Note: This is only tested if a internet connection is established // Note: This is only tested if a internet connection is established
lazyReconnect(client, 'timeout') if (reconnect === undefined) reconnect = require('./reconnect')
reconnect(client, 'timeout')
}) })
} }
@@ -127,11 +129,13 @@ function connect (client) {
}) })
stream.once('close', (hadError) => { stream.once('close', (hadError) => {
lazyReconnect(client, 'close') if (reconnect === undefined) reconnect = require('./reconnect')
reconnect(client, 'close')
}) })
stream.once('end', () => { stream.once('end', () => {
lazyReconnect(client, 'end') if (reconnect === undefined) reconnect = require('./reconnect')
reconnect(client, 'end')
}) })
if (options.tls) { if (options.tls) {

View File

@@ -1,16 +1,17 @@
'use strict' 'use strict'
var index = { let index = {
debugMode: /\bredis\b/i.test(process.env.NODE_DEBUG) debugMode: /\bredis\b/i.test(process.env.NODE_DEBUG)
} }
// Lazy load the main file // Lazy load the main file
process.nextTick(() => (index = require('../'))) process.nextTick(() => { index = require('../') })
/** /**
* @description Print a debug statement if in debug mode * @description Print a debug statement if in debug mode
*/ */
function debug() { function debug() {
if (index.debugMode) { if (index.debugMode) {
// eslint-disable-next-line
console.error.apply(null, arguments) console.error.apply(null, arguments)
} }
} }

View File

@@ -20,7 +20,7 @@ function flushAndError (client, message, code, options) {
err.command = command.command.toUpperCase() err.command = command.command.toUpperCase()
err.args = command.args err.args = command.args
if (command.error) { if (command.error) {
err.stack = err.stack + command.error.stack.replace(/^Error.*?\n/, '\n') err.stack += command.error.stack.replace(/^Error.*?\n/, '\n')
} }
if (options.error) { if (options.error) {
err.origin = options.error err.origin = options.error

View File

@@ -4,6 +4,7 @@ const Command = require('./command')
const debug = require('./debug') const debug = require('./debug')
const Multi = require('./multi') const Multi = require('./multi')
const utils = require('./utils') const utils = require('./utils')
const noPasswordIsSet = /no password is set/ const noPasswordIsSet = /no password is set/
const RedisClient = require('./client') const RedisClient = require('./client')
@@ -42,10 +43,12 @@ Multi.prototype.select = function select (db) {
} }
RedisClient.prototype.monitor = function monitor() { RedisClient.prototype.monitor = function monitor() {
// Use a individual command, as this is a special case that does not has to be checked for any other command // Use a individual command, as this is a special case that does not has to be
// checked for any other command
const callOnWrite = () => { const callOnWrite = () => {
// Activating monitor mode has to happen before Redis returned the callback. The monitor result is returned first. // Activating monitor mode has to happen before Redis returned the callback.
// Therefore we expect the command to be properly processed. If this is not the case, it's not an issue either. // The monitor result is returned first. Therefore we expect the command to
// be properly processed. If this is not the case, it's not an issue either.
this._monitoring = true this._monitoring = true
} }
return this.internalSendCommand(new Command('monitor', [], callOnWrite)) return this.internalSendCommand(new Command('monitor', [], callOnWrite))
@@ -53,7 +56,8 @@ RedisClient.prototype.monitor = function monitor () {
// Only works with batch, not in a transaction // Only works with batch, not in a transaction
Multi.prototype.monitor = function monitor() { Multi.prototype.monitor = function monitor() {
// Use a individual command, as this is a special case that does not has to be checked for any other command // Use a individual command, as this is a special case that does not has to be
// checked for any other command
if (this._type !== 'multi') { if (this._type !== 'multi') {
const callOnWrite = () => { const callOnWrite = () => {
this._client._monitoring = true this._client._monitoring = true
@@ -70,7 +74,8 @@ Multi.prototype.monitor = function monitor () {
function quitCallback(client) { function quitCallback(client) {
return function (err, res) { return function (err, res) {
if (client._stream.writable) { if (client._stream.writable) {
// If the socket is still alive, destroy it. This could happen if quit got a NR_CLOSED error code // If the socket is still alive, destroy it. This could happen if quit got
// a NR_CLOSED error code
client._stream.destroy() client._stream.destroy()
} }
if (err && err.code === 'NR_CLOSED') { if (err && err.code === 'NR_CLOSED') {
@@ -87,8 +92,9 @@ function quitCallback (client) {
RedisClient.prototype.quit = function quit() { RedisClient.prototype.quit = function quit() {
// TODO: Consider this for v.3 // TODO: Consider this for v.3
// Allow the quit command to be fired as soon as possible to prevent it landing in the offline queue. //
// this.ready = this.offlineQueue.length === 0; // Allow the quit command to be fired as soon as possible to prevent it
// landing in the offline queue. this.ready = this.offlineQueue.length === 0;
const backpressureIndicator = this.internalSendCommand(new Command('quit', [], null, quitCallback(this))) const backpressureIndicator = this.internalSendCommand(new Command('quit', [], null, quitCallback(this)))
// Calling quit should always end the connection, no matter if there's a connection or not // Calling quit should always end the connection, no matter if there's a connection or not
this._closing = true this._closing = true
@@ -125,7 +131,7 @@ function infoCallback (client) {
const obj = {} const obj = {}
const lines = res.split('\r\n') const lines = res.split('\r\n')
var topic = '' let topic = ''
while (lines.length) { while (lines.length) {
const parts = lines.shift().split(':') const parts = lines.shift().split(':')
@@ -216,12 +222,7 @@ Multi.prototype.auth = function auth (pass) {
return this return this
} }
RedisClient.prototype.client = function client () { RedisClient.prototype.client = function client(...arr) {
const len = arguments.length
const arr = new Array(len)
for (var i = 0; i < len; i += 1) {
arr[i] = arguments[i]
}
var callOnWrite var callOnWrite
// CLIENT REPLY ON|OFF|SKIP // CLIENT REPLY ON|OFF|SKIP
if (arr.length === 2 && arr[0].toString().toUpperCase() === 'REPLY') { if (arr.length === 2 && arr[0].toString().toUpperCase() === 'REPLY') {
@@ -235,12 +236,7 @@ RedisClient.prototype.client = function client () {
return this.internalSendCommand(new Command('client', arr, callOnWrite)) return this.internalSendCommand(new Command('client', arr, callOnWrite))
} }
Multi.prototype.client = function client () { Multi.prototype.client = function client(...arr) {
const len = arguments.length
const arr = new Array(len)
for (var i = 0; i < len; i += 1) {
arr[i] = arguments[i]
}
var callOnWrite var callOnWrite
// CLIENT REPLY ON|OFF|SKIP // CLIENT REPLY ON|OFF|SKIP
if (arr.length === 2 && arr[0].toString().toUpperCase() === 'REPLY') { if (arr.length === 2 && arr[0].toString().toUpperCase() === 'REPLY') {
@@ -255,24 +251,14 @@ Multi.prototype.client = function client () {
return this return this
} }
RedisClient.prototype.subscribe = function subscribe () { RedisClient.prototype.subscribe = function subscribe(...arr) {
const len = arguments.length
const arr = new Array(len)
for (var i = 0; i < len; i += 1) {
arr[i] = arguments[i]
}
const callOnWrite = () => { const callOnWrite = () => {
this._pubSubMode = this._pubSubMode || this.commandQueue.length + 1 this._pubSubMode = this._pubSubMode || this.commandQueue.length + 1
} }
return this.internalSendCommand(new Command('subscribe', arr, callOnWrite)) return this.internalSendCommand(new Command('subscribe', arr, callOnWrite))
} }
Multi.prototype.subscribe = function subscribe () { Multi.prototype.subscribe = function subscribe(...arr) {
const len = arguments.length
const arr = new Array(len)
for (var i = 0; i < len; i += 1) {
arr[i] = arguments[i]
}
const callOnWrite = () => { const callOnWrite = () => {
this._client._pubSubMode = this._client._pubSubMode || this._client.commandQueue.length + 1 this._client._pubSubMode = this._client._pubSubMode || this._client.commandQueue.length + 1
} }
@@ -280,51 +266,33 @@ Multi.prototype.subscribe = function subscribe () {
return this return this
} }
RedisClient.prototype.unsubscribe = function unsubscribe () { RedisClient.prototype.unsubscribe = function unsubscribe(...arr) {
const len = arguments.length
const arr = new Array(len)
for (var i = 0; i < len; i += 1) {
arr[i] = arguments[i]
}
const callOnWrite = () => { const callOnWrite = () => {
// Pub sub has to be activated even if not in pub sub mode, as the return value is manipulated in the callback // Pub sub has to be activated even if not in pub sub mode, as the return
// value is manipulated in the callback
this._pubSubMode = this._pubSubMode || this.commandQueue.length + 1 this._pubSubMode = this._pubSubMode || this.commandQueue.length + 1
} }
return this.internalSendCommand(new Command('unsubscribe', arr, callOnWrite)) return this.internalSendCommand(new Command('unsubscribe', arr, callOnWrite))
} }
Multi.prototype.unsubscribe = function unsubscribe () { Multi.prototype.unsubscribe = function unsubscribe(...arr) {
const len = arguments.length
const arr = new Array(len)
for (var i = 0; i < len; i += 1) {
arr[i] = arguments[i]
}
const callOnWrite = () => { const callOnWrite = () => {
// Pub sub has to be activated even if not in pub sub mode, as the return value is manipulated in the callback // Pub sub has to be activated even if not in pub sub mode, as the return
// value is manipulated in the callback
this._client._pubSubMode = this._client._pubSubMode || this._client.commandQueue.length + 1 this._client._pubSubMode = this._client._pubSubMode || this._client.commandQueue.length + 1
} }
this._queue.push(new Command('unsubscribe', arr, callOnWrite)) this._queue.push(new Command('unsubscribe', arr, callOnWrite))
return this return this
} }
RedisClient.prototype.psubscribe = function psubscribe () { RedisClient.prototype.psubscribe = function psubscribe(...arr) {
const len = arguments.length
const arr = new Array(len)
for (var i = 0; i < len; i += 1) {
arr[i] = arguments[i]
}
const callOnWrite = () => { const callOnWrite = () => {
this._pubSubMode = this._pubSubMode || this.commandQueue.length + 1 this._pubSubMode = this._pubSubMode || this.commandQueue.length + 1
} }
return this.internalSendCommand(new Command('psubscribe', arr, callOnWrite)) return this.internalSendCommand(new Command('psubscribe', arr, callOnWrite))
} }
Multi.prototype.psubscribe = function psubscribe () { Multi.prototype.psubscribe = function psubscribe(...arr) {
const len = arguments.length
const arr = new Array(len)
for (var i = 0; i < len; i += 1) {
arr[i] = arguments[i]
}
const callOnWrite = () => { const callOnWrite = () => {
this._client._pubSubMode = this._client._pubSubMode || this._client.commandQueue.length + 1 this._client._pubSubMode = this._client._pubSubMode || this._client.commandQueue.length + 1
} }
@@ -332,27 +300,19 @@ Multi.prototype.psubscribe = function psubscribe () {
return this return this
} }
RedisClient.prototype.punsubscribe = function punsubscribe () { RedisClient.prototype.punsubscribe = function punsubscribe(...arr) {
const len = arguments.length
const arr = new Array(len)
for (var i = 0; i < len; i += 1) {
arr[i] = arguments[i]
}
const callOnWrite = () => { const callOnWrite = () => {
// Pub sub has to be activated even if not in pub sub mode, as the return value is manipulated in the callback // Pub sub has to be activated even if not in pub sub mode, as the return
// value is manipulated in the callback
this._pubSubMode = this._pubSubMode || this.commandQueue.length + 1 this._pubSubMode = this._pubSubMode || this.commandQueue.length + 1
} }
return this.internalSendCommand(new Command('punsubscribe', arr, callOnWrite)) return this.internalSendCommand(new Command('punsubscribe', arr, callOnWrite))
} }
Multi.prototype.punsubscribe = function punsubscribe () { Multi.prototype.punsubscribe = function punsubscribe(...arr) {
const len = arguments.length
const arr = new Array(len)
for (var i = 0; i < len; i += 1) {
arr[i] = arguments[i]
}
const callOnWrite = () => { const callOnWrite = () => {
// Pub sub has to be activated even if not in pub sub mode, as the return value is manipulated in the callback // Pub sub has to be activated even if not in pub sub mode, as the return
// value is manipulated in the callback
this._client._pubSubMode = this._client._pubSubMode || this._client.commandQueue.length + 1 this._client._pubSubMode = this._client._pubSubMode || this._client.commandQueue.length + 1
} }
this._queue.push(new Command('punsubscribe', arr, callOnWrite)) this._queue.push(new Command('punsubscribe', arr, callOnWrite))

View File

@@ -4,6 +4,7 @@ const Queue = require('denque')
const Errors = require('redis-errors') const Errors = require('redis-errors')
const Command = require('./command') const Command = require('./command')
const utils = require('./utils') const utils = require('./utils')
const handleReply = utils.handleReply const handleReply = utils.handleReply
/** /**
@@ -74,9 +75,7 @@ function execTransaction (multi) {
const client = multi._client const client = multi._client
const queue = multi._queue const queue = multi._queue
if (multi._monitoring || client._monitoring) { if (multi._monitoring || client._monitoring) {
const err = new RangeError( const err = new RangeError('Using transaction with a client that is in monitor mode does not work due to faulty return values of Redis.')
'Using transaction with a client that is in monitor mode does not work due to faulty return values of Redis.'
)
err.command = 'EXEC' err.command = 'EXEC'
err.code = 'EXECABORT' err.code = 'EXECABORT'
return new Promise((resolve, reject) => { return new Promise((resolve, reject) => {
@@ -89,13 +88,16 @@ function execTransaction (multi) {
// Silently ignore this error. We'll receive the error for the exec as well // Silently ignore this error. We'll receive the error for the exec as well
const promises = [client.internalSendCommand(new Command('multi', [])).catch(() => {})] const promises = [client.internalSendCommand(new Command('multi', [])).catch(() => {})]
// Drain queue, callback will catch 'QUEUED' or error // Drain queue, callback will catch 'QUEUED' or error
for (var index = 0; index < len; index++) { for (let index = 0; index < len; index++) {
// The commands may not be shifted off, since they are needed in the result handler // The commands may not be shifted off, since they are needed in the result handler
promises.push(pipelineTransactionCommand(multi, queue.peekAt(index), index).catch((e) => e)) promises.push(pipelineTransactionCommand(multi, queue.peekAt(index), index).catch(e => e))
} }
const main = client.internalSendCommand(new Command('exec', [])) const main = client.internalSendCommand(new Command('exec', []))
return Promise.all(promises).then(() => main.then((replies) => multiCallback(multi, replies)).catch((err) => { return Promise.all(promises)
.then(() => main
.then(replies => multiCallback(multi, replies))
.catch((err) => {
err.errors = multi._errors err.errors = multi._errors
return Promise.reject(err) return Promise.reject(err)
})) }))
@@ -119,13 +121,14 @@ function execBatch (multi) {
}) })
} }
var error = false var error = false
function setError(err) {
error = true
return err
}
const promises = [] const promises = []
while (queue.length) { while (queue.length) {
const command = queue.shift() const command = queue.shift()
promises.push(client.internalSendCommand(command).catch((e) => { promises.push(client.internalSendCommand(command).catch(setError))
error = true
return e
}))
} }
return Promise.all(promises).then((res) => { return Promise.all(promises).then((res) => {
if (error) { if (error) {
@@ -154,7 +157,7 @@ class Multi {
// Either undefined or an array. Fail hard if it's not an array // Either undefined or an array. Fail hard if it's not an array
if (args) { if (args) {
// Legacy support for passing in an array of arguments // Legacy support for passing in an array of arguments
for (var i = 0; i < args.length; i++) { for (let i = 0; i < args.length; i++) {
const command = args[i][0] const command = args[i][0]
const tmpArgs = args[i].slice(1) const tmpArgs = args[i].slice(1)
if (Array.isArray(command)) { if (Array.isArray(command)) {

View File

@@ -1,6 +1,7 @@
'use strict' 'use strict'
const debug = require('./debug') const debug = require('./debug')
const SUBSCRIBE_COMMANDS = { const SUBSCRIBE_COMMANDS = {
subscribe: true, subscribe: true,
unsubscribe: true, unsubscribe: true,
@@ -9,16 +10,21 @@ const SUBSCRIBE_COMMANDS = {
} }
function subscribeUnsubscribe(client, reply, type) { function subscribeUnsubscribe(client, reply, type) {
// Subscribe commands take an optional callback and also emit an event, but only the Last_ response is included in the callback // Subscribe commands take an optional callback and also emit an event, but
// The pub sub commands return each argument in a separate return value and have to be handled that way // only the Last_ response is included in the callback The pub sub commands
// return each argument in a separate return value and have to be handled that
// way
const commandObj = client.commandQueue.peekAt(0) const commandObj = client.commandQueue.peekAt(0)
const buffer = client._options.returnBuffers || client._options.detectBuffers && commandObj.bufferArgs const buffer = client._options.returnBuffers ||
client._options.detectBuffers && commandObj.bufferArgs
const channel = (buffer || reply[1] === null) ? reply[1] : reply[1].toString() const channel = (buffer || reply[1] === null) ? reply[1] : reply[1].toString()
const count = +reply[2] // Return the channel counter as number no matter if `stringNumbers` is activated or not // Return the channel counter as number no matter if `stringNumbers` is activated or not
const count = +reply[2]
debug(type, channel) debug(type, channel)
// Emit first, then return the callback // Emit first, then return the callback
if (channel !== null) { // Do not emit or "unsubscribe" something if there was no channel to unsubscribe from // Do not emit or "unsubscribe" something if there was no channel to unsubscribe from
if (channel !== null) {
if (type === 'subscribe' || type === 'psubscribe') { if (type === 'subscribe' || type === 'psubscribe') {
client._subscriptionSet[`${type}_${channel}`] = channel client._subscriptionSet[`${type}_${channel}`] = channel
} else { } else {
@@ -29,10 +35,13 @@ function subscribeUnsubscribe (client, reply, type) {
client._subscribeChannels.push(channel) client._subscribeChannels.push(channel)
} }
if (commandObj.argsLength === 1 || client._subCommandsLeft === 1 || commandObj.argsLength === 0 && (count === 0 || channel === null)) { if (commandObj.argsLength === 1 ||
client._subCommandsLeft === 1 ||
commandObj.argsLength === 0 && (count === 0 || channel === null)) {
if (count === 0) { // Unsubscribed from all channels if (count === 0) { // Unsubscribed from all channels
client._pubSubMode = 0 // Deactivating pub sub mode client._pubSubMode = 0 // Deactivating pub sub mode
// This should be a rare case and therefore handling it this way should be good performance wise for the general case // This should be a rare case and therefore handling it this way should be
// good performance wise for the general case
for (var i = 1; i < client.commandQueue.length; i++) { for (var i = 1; i < client.commandQueue.length; i++) {
const runningCommand = client.commandQueue.peekAt(i) const runningCommand = client.commandQueue.peekAt(i)
if (SUBSCRIBE_COMMANDS[runningCommand.command]) { if (SUBSCRIBE_COMMANDS[runningCommand.command]) {
@@ -45,14 +54,12 @@ function subscribeUnsubscribe (client, reply, type) {
commandObj.callback(null, [count, client._subscribeChannels]) commandObj.callback(null, [count, client._subscribeChannels])
client._subscribeChannels = [] client._subscribeChannels = []
client._subCommandsLeft = 0 client._subCommandsLeft = 0
} else { } else if (client._subCommandsLeft !== 0) {
if (client._subCommandsLeft !== 0) {
client._subCommandsLeft-- client._subCommandsLeft--
} else { } else {
client._subCommandsLeft = commandObj.argsLength ? commandObj.argsLength - 1 : count client._subCommandsLeft = commandObj.argsLength ? commandObj.argsLength - 1 : count
} }
} }
}
function returnPubSub(client, reply) { function returnPubSub(client, reply) {
const type = reply[0].toString() const type = reply[0].toString()

View File

@@ -79,8 +79,9 @@ function readyHandler (client) {
// } // }
if (!client._options.disableResubscribing && callbackCount) { if (!client._options.disableResubscribing && callbackCount) {
debug('Sending pub/sub commands') debug('Sending pub/sub commands')
for (const key in client._subscriptionSet) { const keys = Object.keys(client._subscriptionSet)
if (client._subscriptionSet.hasOwnProperty(key)) { for (var i = 0; i < keys.length; i++) {
const key = keys[i]
const command = key.slice(0, key.indexOf('_')) const command = key.slice(0, key.indexOf('_'))
const args = client._subscriptionSet[key] const args = client._subscriptionSet[key]
client[command]([args]).catch((err) => { client[command]([args]).catch((err) => {
@@ -90,7 +91,6 @@ function readyHandler (client) {
}) })
} }
} }
}
sendOfflineQueue(client) sendOfflineQueue(client)
client.emit('ready') client.emit('ready')
} }
@@ -112,7 +112,9 @@ function readyCheck (client) {
} }
const persistence = client.serverInfo.persistence const persistence = client.serverInfo.persistence
if (persistence === undefined || persistence.loading === undefined || persistence.loading === 0) { if (persistence === undefined ||
persistence.loading === undefined ||
persistence.loading === 0) {
// If the master_link_status exists but the link is not up, try again after 50 ms // If the master_link_status exists but the link is not up, try again after 50 ms
const replication = client.serverInfo.replication const replication = client.serverInfo.replication
if (replication && typeof replication.master_link_status === 'string' && replication.master_link_status !== 'up') { if (replication && typeof replication.master_link_status === 'string' && replication.master_link_status !== 'up') {
@@ -125,12 +127,12 @@ function readyCheck (client) {
} }
} }
var retryTime = +persistence.loading_eta_seconds * 1000 let retryTime = +persistence.loading_eta_seconds * 1000
if (retryTime > 1000) { if (retryTime > 1000) {
retryTime = 1000 retryTime = 1000
} }
debug('Redis server still loading, trying again in %s', retryTime) debug('Redis server still loading, trying again in %s', retryTime)
setTimeout((client) => readyCheck(client), retryTime, client) setTimeout(client => readyCheck(client), retryTime, client)
}).catch((err) => { }).catch((err) => {
if (client._closing) { if (client._closing) {
return return
@@ -142,7 +144,6 @@ function readyCheck (client) {
} }
err.message = `Ready check failed: ${err.message}` err.message = `Ready check failed: ${err.message}`
client.emit('error', err) client.emit('error', err)
return
}) })
client.ready = false client.ready = false
} }

View File

@@ -112,7 +112,12 @@ function reconnect (client, why, error) {
debug('Retry connection in %s ms', client.retryDelay) debug('Retry connection in %s ms', client.retryDelay)
client.retryTimer = setTimeout((client, error) => retryConnection(client, error), client.retryDelay, client, error) client.retryTimer = setTimeout(
(client, error) => retryConnection(client, error),
client.retryDelay,
client,
error
)
} }
module.exports = reconnect module.exports = reconnect

View File

@@ -1,6 +1,6 @@
'use strict' 'use strict'
const Buffer = require('buffer').Buffer const { Buffer } = require('buffer')
const pubsub = require('./pubsub') const pubsub = require('./pubsub')
const utils = require('./utils') const utils = require('./utils')
@@ -37,9 +37,10 @@ function normalReply (client, reply) {
} }
function onResult(client, reply) { function onResult(client, reply) {
// If in monitor mode, all normal commands are still working and we only want to emit the streamlined commands // If in monitor mode, all normal commands are still working and we only want
// As this is not the average use case and monitor is expensive anyway, let's change the code here, to improve // to emit the streamlined commands As this is not the average use case and
// the average performance of all other commands in case of no monitor mode // monitor is expensive anyway, let's change the code here, to improve the
// average performance of all other commands in case of no monitor mode
if (client._monitoring === true) { if (client._monitoring === true) {
var replyStr var replyStr
// TODO: This could be further improved performance wise // TODO: This could be further improved performance wise

View File

@@ -7,7 +7,7 @@ const URL = require('url')
// before trying to access that argument. // before trying to access that argument.
function unifyOptions(portArg, hostArg, options) { function unifyOptions(portArg, hostArg, options) {
if (typeof portArg === 'number' || (typeof portArg === 'string' && /^\d+$/.test(portArg))) { if (typeof portArg === 'number' || (typeof portArg === 'string' && /^\d+$/.test(portArg))) {
var host let host
if (typeof hostArg === 'string') { if (typeof hostArg === 'string') {
host = hostArg host = hostArg
} else { } else {
@@ -24,6 +24,7 @@ function unifyOptions (portArg, hostArg, options) {
const parsed = URL.parse(portArg.url || portArg, true, true) const parsed = URL.parse(portArg.url || portArg, true, true)
// eslint-disable-next-line
// [redis:]//[[user][:password]@][host][:port][/db-number][?db=db-number[&password=bar[&option=value]]] // [redis:]//[[user][:password]@][host][:port][/db-number][?db=db-number[&password=bar[&option=value]]]
if (parsed.slashes) { // We require slashes if (parsed.slashes) { // We require slashes
if (parsed.auth) { if (parsed.auth) {
@@ -42,11 +43,9 @@ function unifyOptions (portArg, hostArg, options) {
options.port = parsed.port options.port = parsed.port
} }
if (parsed.search !== '') { if (parsed.search !== '') {
for (var elem in parsed.query) { const keys = Object.keys(parsed.query)
/* istanbul ignore if */ for (var i = 0; i < keys.length; i++) {
if (!Object.prototype.hasOwnProperty.call(parsed.query, elem)) { const elem = keys[i]
continue
}
// If options are passed twice, only the parsed options will be used // If options are passed twice, only the parsed options will be used
if (elem in options) { if (elem in options) {
if (options[elem] === parsed.query[elem]) { if (options[elem] === parsed.query[elem]) {

View File

@@ -11,7 +11,7 @@ function replyToObject (reply) {
return null return null
} }
const obj = {} const obj = {}
for (let i = 0; i < reply.length; i += 2) { for (var i = 0; i < reply.length; i += 2) {
obj[reply[i].toString('binary')] = reply[i + 1] obj[reply[i].toString('binary')] = reply[i + 1]
} }
return obj return obj
@@ -32,7 +32,7 @@ function replyToStrings (reply) {
} }
if (typeof reply.map === 'function') { // instanceof Array if (typeof reply.map === 'function') { // instanceof Array
const res = new Array(reply.length) const res = new Array(reply.length)
for (let i = 0; i < reply.length; i++) { for (var i = 0; i < reply.length; i++) {
// Recursively call the function as slowlog returns deep nested replies // Recursively call the function as slowlog returns deep nested replies
res[i] = replyToStrings(reply[i]) res[i] = replyToStrings(reply[i])
} }
@@ -141,7 +141,8 @@ function warn (client, msg) {
* @returns {string|number|null|Buffer|any[]|object} * @returns {string|number|null|Buffer|any[]|object}
*/ */
function handleReply(client, reply, command) { function handleReply(client, reply, command) {
if (client._options.detectBuffers === true && command.bufferArgs === false || client._messageBuffers === true) { if (client._options.detectBuffers === true && command.bufferArgs === false ||
client._messageBuffers === true) {
reply = replyToStrings(reply) reply = replyToStrings(reply)
} }
@@ -162,7 +163,7 @@ function print (err, reply) {
// A error always begins with Error: // A error always begins with Error:
console.error(err.toString()) console.error(err.toString())
} else { } else {
console.log('Reply: ' + reply) console.log(`Reply: ${reply}`)
} }
} }

View File

@@ -21,7 +21,8 @@ var errors = null
/** /**
* @description Pipeline and write all commands to the stream * @description Pipeline and write all commands to the stream
* *
* If the pipelined string exceeds X mb, write it directly to the stream and pipeline the rest again. * If the pipelined string exceeds X mb, write it directly to the stream and
* pipeline the rest again.
* @param {RedisClient} client * @param {RedisClient} client
*/ */
function writeToStream(client) { function writeToStream(client) {
@@ -53,7 +54,7 @@ function pipelineBuffers (client, commandStr) {
const queue = client._pipelineQueue const queue = client._pipelineQueue
client._strCache += commandStr client._strCache += commandStr
while (copy.length) { while (copy.length) {
var arg = copy.shift() const arg = copy.shift()
if (typeof arg === 'string') { if (typeof arg === 'string') {
client._strCache += `$${Buffer.byteLength(arg)}\r\n${arg}\r\n` client._strCache += `$${Buffer.byteLength(arg)}\r\n${arg}\r\n`
} else { } else {
@@ -73,16 +74,16 @@ function toString (arg) {
if (typeof arg === 'string') { if (typeof arg === 'string') {
copy.push(arg) copy.push(arg)
} else if (typeof arg === 'number') { } else if (typeof arg === 'number') {
copy.push('' + arg) copy.push(`${arg}`)
} else if (arg instanceof Array) { } else if (arg instanceof Array) {
for (var i = 0; i < arg.length; i += 1) { for (let i = 0; i < arg.length; i += 1) {
toString(arg[i]) toString(arg[i])
} }
} else if (arg && arg.constructor.name === 'Buffer') { // TODO: check performance } else if (arg && arg.constructor.name === 'Buffer') { // TODO: check performance
copy.push(arg) copy.push(arg)
bufferCount++ bufferCount++
} else if (typeof arg === 'boolean') { // TODO: Remove this support and use hooks instead } else if (typeof arg === 'boolean') { // TODO: Remove this support and use hooks instead
copy.push('' + arg) copy.push(`${arg}`)
} else if (arg && arg.constructor.name === 'Object') { // Check if this is actually a good check or not } else if (arg && arg.constructor.name === 'Object') { // Check if this is actually a good check or not
// TODO: As soon as we add support for JSON // TODO: As soon as we add support for JSON
// We could simple stringify this right here. // We could simple stringify this right here.
@@ -99,7 +100,7 @@ function toString (arg) {
toString(val) toString(val)
}) })
} else if (arg instanceof Set) { } else if (arg instanceof Set) {
arg.forEach((val) => toString(val)) arg.forEach(val => toString(val))
} else if (arg && arg.constructor.name === 'Date') { // Check if this is actually a good check or not } else if (arg && arg.constructor.name === 'Date') { // Check if this is actually a good check or not
copy.push(arg.toString()) copy.push(arg.toString())
} else { } else {
@@ -119,8 +120,9 @@ function returnErr (client, command) {
utils.replyInOrder(client, command.callback, err, undefined, client.commandQueue) utils.replyInOrder(client, command.callback, err, undefined, client.commandQueue)
} }
// Always use 'Multi bulk commands', but if passed any Buffer args, then do multiple writes, one for each arg. // Always use 'Multi bulk commands', but if passed any Buffer args, then do
// This means that using Buffers in commands is going to be slower, so use Strings if you don't already have a Buffer. // multiple writes, one for each arg. This means that using Buffers in commands
// is going to be slower, so use Strings if you don't already have a Buffer.
// TODO: It is faster to move this part somewhere else // TODO: It is faster to move this part somewhere else
// We could move this to the function creation as well // We could move this to the function creation as well
@@ -134,7 +136,7 @@ function normalizeAndWrite (client, command) {
: origName : origName
bufferCount = 0 bufferCount = 0
for (var i = 0; i < args.length; i++) { for (let i = 0; i < args.length; i++) {
toString(args[i]) toString(args[i])
} }
@@ -153,7 +155,7 @@ function normalizeAndWrite (client, command) {
const bufferArgs = bufferCount !== 0 const bufferArgs = bufferCount !== 0
const len = copy.length const len = copy.length
var commandStr = `*${len + 1}\r\n$${name.length}\r\n${name}\r\n` let commandStr = `*${len + 1}\r\n$${name.length}\r\n${name}\r\n`
command.bufferArgs = bufferArgs command.bufferArgs = bufferArgs
command.argsLength = len command.argsLength = len

View File

@@ -23,7 +23,7 @@
"test": "nyc --cache mocha ./test/*.js ./test/commands/*.js --timeout=8000", "test": "nyc --cache mocha ./test/*.js ./test/commands/*.js --timeout=8000",
"posttest": "npm run coverage", "posttest": "npm run coverage",
"compare": "node benchmarks/diff_multi_bench_output.js beforeBench.txt afterBench.txt", "compare": "node benchmarks/diff_multi_bench_output.js beforeBench.txt afterBench.txt",
"lint": "standard . --fix" "lint": "eslint . --fix"
}, },
"dependencies": { "dependencies": {
"denque": "^1.2.2", "denque": "^1.2.2",
@@ -37,11 +37,13 @@
"devDependencies": { "devDependencies": {
"coveralls": "^2.13.3", "coveralls": "^2.13.3",
"cross-spawn": "^5.1.0", "cross-spawn": "^5.1.0",
"eslint": "^4.12.0",
"eslint-config-airbnb-base": "^12.1.0",
"eslint-plugin-import": "^2.8.0",
"intercept-stdout": "~0.1.2", "intercept-stdout": "~0.1.2",
"metrics": "^0.1.14", "metrics": "^0.1.14",
"mocha": "^3.5.3", "mocha": "^3.5.3",
"nyc": "^8.3.0", "nyc": "^8.3.0",
"standard": "^10.0.2",
"tcp-port-used": "^0.1.2", "tcp-port-used": "^0.1.2",
"uuid": "^2.0.1" "uuid": "^2.0.1"
}, },

View File

@@ -3,7 +3,8 @@
const assert = require('assert') const assert = require('assert')
const config = require('./lib/config') const config = require('./lib/config')
const helper = require('./helper') const helper = require('./helper')
const redis = config.redis
const { redis } = config
// TODO: Fix redis process spawn on windows // TODO: Fix redis process spawn on windows
if (process.platform !== 'win32') { if (process.platform !== 'win32') {
@@ -215,7 +216,8 @@ if (process.platform !== 'win32') {
}) })
}) })
client.once('ready', () => { client.once('ready', () => {
// Coherent behavior with all other offline commands fires commands before emitting but does not wait till they return // Coherent behavior with all other offline commands fires commands
// before emitting but does not wait till they return
assert.strictEqual(client._pubSubMode, 2) assert.strictEqual(client._pubSubMode, 2)
client.ping().then(() => { // Make sure all commands were properly processed already client.ping().then(() => { // Make sure all commands were properly processed already
client._stream.destroy() client._stream.destroy()
@@ -224,11 +226,15 @@ if (process.platform !== 'win32') {
}) })
it('individual commands work properly with batch', (done) => { it('individual commands work properly with batch', (done) => {
// quit => might return an error instead of "OK" in the exec callback... (if not connected) // quit => might return an error instead of "OK" in the exec callback...
// auth => might return an error instead of "OK" in the exec callback... (if no password is required / still loading on Redis <= 2.4) // (if not connected)
// This could be fixed by checking the return value of the callback in the exec callback and //
// returning the manipulated [error, result] from the callback. // auth => might return an error instead of "OK" in the exec callback...
// There should be a better solution though // (if no password is required / still loading on Redis <= 2.4)
//
// This could be fixed by checking the return value of the callback in
// the exec callback and returning the manipulated [error, result] from
// the callback. There should be a better solution though
const args = config.configureClient('localhost', { const args = config.configureClient('localhost', {
noReadyCheck: true noReadyCheck: true
@@ -251,7 +257,8 @@ if (process.platform !== 'win32') {
.subscribe('/foo') .subscribe('/foo')
.psubscribe('*') .psubscribe('*')
.quit() .quit()
.exec().then((res) => { .exec()
.then((res) => {
res[4] = res[4].substr(0, 9) res[4] = res[4].substr(0, 9)
assert.deepStrictEqual( assert.deepStrictEqual(
res, res,

View File

@@ -3,7 +3,8 @@
const assert = require('assert') const assert = require('assert')
const config = require('./lib/config') const config = require('./lib/config')
const helper = require('./helper') const helper = require('./helper')
const redis = config.redis
const { redis } = config
describe('The \'batch\' method', () => { describe('The \'batch\' method', () => {
helper.allTests((ip, args) => { helper.allTests((ip, args) => {
@@ -101,7 +102,7 @@ describe('The \'batch\' method', () => {
['incr', 'batchfoo'], ['incr', 'batchfoo'],
['incr', 'batchbar'] ['incr', 'batchbar']
]).exec().then(helper.fail).catch((err) => { ]).exec().then(helper.fail).catch((err) => {
const replies = err.replies const { replies } = err
assert.strictEqual(2, replies[0].length) assert.strictEqual(2, replies[0].length)
assert.strictEqual(null, replies[0][0]) assert.strictEqual(null, replies[0][0])
assert.strictEqual(null, replies[0][1]) assert.strictEqual(null, replies[0][1])
@@ -150,8 +151,8 @@ describe('The \'batch\' method', () => {
[['hmset', 'batchhmset2', 'batchbar2', 'batchfoo3', 'batchbar3', 'test']], [['hmset', 'batchhmset2', 'batchbar2', 'batchfoo3', 'batchbar3', 'test']],
['hmset', ['batchhmset', 'batchbar', 'batchfoo']], ['hmset', ['batchhmset', 'batchbar', 'batchfoo']],
['hmset', arr3], ['hmset', arr3],
['hmset', now, {123456789: 'abcdefghij', 'some manner of key': 'a type of value', 'otherTypes': 555}], ['hmset', now, { 123456789: 'abcdefghij', 'some manner of key': 'a type of value', otherTypes: 555 }],
['hmset', 'key2', {'0123456789': 'abcdefghij', 'some manner of key': 'a type of value', 'otherTypes': 999}], ['hmset', 'key2', { '0123456789': 'abcdefghij', 'some manner of key': 'a type of value', otherTypes: 999 }],
['hmset', new Set(['batchhmset', ['batchbar', 'batchbaz']])], ['hmset', new Set(['batchhmset', ['batchbar', 'batchbaz']])],
['hmset', ['batchhmset'], new Map([['batchbar', 'batchbaz']])] ['hmset', ['batchhmset'], new Map([['batchbar', 'batchbaz']])]
]) ])
@@ -159,7 +160,8 @@ describe('The \'batch\' method', () => {
.hmget('key2', arr2) .hmget('key2', arr2)
.hmget(['batchhmset2', ['some manner of key', 'batchbar3']]) .hmget(['batchhmset2', ['some manner of key', 'batchbar3']])
.mget('batchfoo2', ['batchfoo3', 'batchfoo']) .mget('batchfoo2', ['batchfoo3', 'batchfoo'])
.exec().then((replies) => { .exec()
.then((replies) => {
assert.strictEqual(arr.length, 3) assert.strictEqual(arr.length, 3)
assert.strictEqual(arr2.length, 2) assert.strictEqual(arr2.length, 2)
assert.strictEqual(arr3.length, 3) assert.strictEqual(arr3.length, 3)
@@ -194,7 +196,8 @@ describe('The \'batch\' method', () => {
.incr('some') .incr('some')
.incr('keys') .incr('keys')
.mget('some', 'keys') .mget('some', 'keys')
.exec().then(helper.isDeepEqual(['OK', 11, 21, ['11', '21']])) .exec()
.then(helper.isDeepEqual(['OK', 11, 21, ['11', '21']]))
}) })
it('allows multiple commands to work the same as normal to be performed using a chaining API', () => { it('allows multiple commands to work the same as normal to be performed using a chaining API', () => {
@@ -203,7 +206,8 @@ describe('The \'batch\' method', () => {
.incr('some') .incr('some')
.incr(['keys']) .incr(['keys'])
.mget('some', 'keys') .mget('some', 'keys')
.exec().then(helper.isDeepEqual(['OK', 11, 21, ['11', '21']])) .exec()
.then(helper.isDeepEqual(['OK', 11, 21, ['11', '21']]))
}) })
it('allows an array to be provided indicating multiple operations to perform', () => { it('allows an array to be provided indicating multiple operations to perform', () => {

View File

@@ -3,7 +3,8 @@
const assert = require('assert') const assert = require('assert')
const config = require('../lib/config') const config = require('../lib/config')
const helper = require('../helper') const helper = require('../helper')
const redis = config.redis
const { redis } = config
const intercept = require('intercept-stdout') const intercept = require('intercept-stdout')
describe('The \'blpop\' method', () => { describe('The \'blpop\' method', () => {

View File

@@ -1,10 +1,11 @@
'use strict' 'use strict'
const Buffer = require('buffer').Buffer const { Buffer } = require('buffer')
const assert = require('assert') const assert = require('assert')
const config = require('../lib/config') const config = require('../lib/config')
const helper = require('../helper') const helper = require('../helper')
const redis = config.redis
const { redis } = config
describe('The \'client\' method', () => { describe('The \'client\' method', () => {
helper.allTests((ip, args) => { helper.allTests((ip, args) => {
@@ -144,8 +145,9 @@ describe('The \'client\' method', () => {
}) })
it('sets the name', () => { it('sets the name', () => {
// The querys are auto pipelined and the response is a response to all querys of one client // The querys are auto pipelined and the response is a response to all
// per chunk. So the execution order is only guaranteed on each client // querys of one client per chunk. So the execution order is only
// guaranteed on each client
return Promise.all([ return Promise.all([
client.client('setname', 'RUTH'), client.client('setname', 'RUTH'),
client2.client('setname', ['RENEE']).then(helper.isString('OK')), client2.client('setname', ['RENEE']).then(helper.isString('OK')),

View File

@@ -3,13 +3,15 @@
const assert = require('assert') const assert = require('assert')
const config = require('../lib/config') const config = require('../lib/config')
const helper = require('../helper') const helper = require('../helper')
const redis = config.redis
const { redis } = config
const uuid = require('uuid') const uuid = require('uuid')
describe('The \'dbsize\' method', () => { describe('The \'dbsize\' method', () => {
helper.allTests((ip, args) => { helper.allTests((ip, args) => {
describe(`using ${ip}`, () => { describe(`using ${ip}`, () => {
let key, value let key
let value
beforeEach(() => { beforeEach(() => {
key = uuid.v4() key = uuid.v4()

View File

@@ -2,7 +2,8 @@
const config = require('../lib/config') const config = require('../lib/config')
const helper = require('../helper') const helper = require('../helper')
const redis = config.redis
const { redis } = config
describe('The \'del\' method', () => { describe('The \'del\' method', () => {
helper.allTests((ip, args) => { helper.allTests((ip, args) => {

View File

@@ -4,7 +4,8 @@ const assert = require('assert')
const config = require('../lib/config') const config = require('../lib/config')
const crypto = require('crypto') const crypto = require('crypto')
const helper = require('../helper') const helper = require('../helper')
const redis = config.redis
const { redis } = config
describe('The \'eval\' method', () => { describe('The \'eval\' method', () => {
helper.allTests((ip, args) => { helper.allTests((ip, args) => {
@@ -121,7 +122,8 @@ describe('The \'eval\' method', () => {
.rpush('mylist', 'a') .rpush('mylist', 'a')
.rpush('mylist', 'b') .rpush('mylist', 'b')
.rpush('mylist', 'c') .rpush('mylist', 'c')
.exec().then((replies) => { .exec()
.then((replies) => {
return client.eval('local foo = redis.call(\'lrange\',\'mylist\',0,-1); return {type(foo),foo[1],foo[2],foo[3],# foo}', 0).then((res) => { return client.eval('local foo = redis.call(\'lrange\',\'mylist\',0,-1); return {type(foo),foo[1],foo[2],foo[3],# foo}', 0).then((res) => {
assert.strictEqual(5, res.length) assert.strictEqual(5, res.length)
assert.strictEqual('table', res[0]) assert.strictEqual('table', res[0])

View File

@@ -2,7 +2,8 @@
const config = require('../lib/config') const config = require('../lib/config')
const helper = require('../helper') const helper = require('../helper')
const redis = config.redis
const { redis } = config
describe('The \'exists\' method', () => { describe('The \'exists\' method', () => {
helper.allTests((ip, args) => { helper.allTests((ip, args) => {

View File

@@ -2,7 +2,8 @@
const config = require('../lib/config') const config = require('../lib/config')
const helper = require('../helper') const helper = require('../helper')
const redis = config.redis
const { redis } = config
describe('The \'expire\' method', () => { describe('The \'expire\' method', () => {
helper.allTests((ip, args) => { helper.allTests((ip, args) => {

View File

@@ -2,13 +2,15 @@
const config = require('../lib/config') const config = require('../lib/config')
const helper = require('../helper') const helper = require('../helper')
const redis = config.redis
const { redis } = config
const uuid = require('uuid') const uuid = require('uuid')
describe('The \'flushdb\' method', () => { describe('The \'flushdb\' method', () => {
helper.allTests((ip, args) => { helper.allTests((ip, args) => {
describe(`using ${ip}`, () => { describe(`using ${ip}`, () => {
let key, key2 let key
let key2
beforeEach(() => { beforeEach(() => {
key = uuid.v4() key = uuid.v4()

View File

@@ -2,7 +2,8 @@
const config = require('../lib/config') const config = require('../lib/config')
const helper = require('../helper') const helper = require('../helper')
const redis = config.redis
const { redis } = config
describe('The \'geoadd\' method', () => { describe('The \'geoadd\' method', () => {
helper.allTests((ip, args) => { helper.allTests((ip, args) => {

View File

@@ -2,13 +2,15 @@
const config = require('../lib/config') const config = require('../lib/config')
const helper = require('../helper') const helper = require('../helper')
const redis = config.redis
const { redis } = config
const uuid = require('uuid') const uuid = require('uuid')
describe('The \'get\' method', () => { describe('The \'get\' method', () => {
helper.allTests((ip, args) => { helper.allTests((ip, args) => {
describe(`using ${ip}`, () => { describe(`using ${ip}`, () => {
let key, value let key
let value
beforeEach(() => { beforeEach(() => {
key = uuid.v4() key = uuid.v4()

View File

@@ -2,13 +2,16 @@
const config = require('../lib/config') const config = require('../lib/config')
const helper = require('../helper') const helper = require('../helper')
const redis = config.redis
const { redis } = config
const uuid = require('uuid') const uuid = require('uuid')
describe('The \'getset\' method', () => { describe('The \'getset\' method', () => {
helper.allTests((ip, args) => { helper.allTests((ip, args) => {
describe(`using ${ip}`, () => { describe(`using ${ip}`, () => {
let key, value, value2 let key
let value
let value2
beforeEach(() => { beforeEach(() => {
key = uuid.v4() key = uuid.v4()

View File

@@ -1,10 +1,11 @@
'use strict' 'use strict'
const Buffer = require('buffer').Buffer const { Buffer } = require('buffer')
const assert = require('assert') const assert = require('assert')
const config = require('../lib/config') const config = require('../lib/config')
const helper = require('../helper') const helper = require('../helper')
const redis = config.redis
const { redis } = config
describe('The \'hgetall\' method', () => { describe('The \'hgetall\' method', () => {
helper.allTests((ip, args) => { helper.allTests((ip, args) => {

View File

@@ -2,7 +2,8 @@
const config = require('../lib/config') const config = require('../lib/config')
const helper = require('../helper') const helper = require('../helper')
const redis = config.redis
const { redis } = config
describe('The \'hincrby\' method', () => { describe('The \'hincrby\' method', () => {
helper.allTests((ip, args) => { helper.allTests((ip, args) => {

View File

@@ -1,9 +1,10 @@
'use strict' 'use strict'
const Buffer = require('buffer').Buffer const { Buffer } = require('buffer')
const config = require('../lib/config') const config = require('../lib/config')
const helper = require('../helper') const helper = require('../helper')
const redis = config.redis
const { redis } = config
describe('The \'hlen\' method', () => { describe('The \'hlen\' method', () => {
helper.allTests((ip, args) => { helper.allTests((ip, args) => {

View File

@@ -2,7 +2,8 @@
const config = require('../lib/config') const config = require('../lib/config')
const helper = require('../helper') const helper = require('../helper')
const redis = config.redis
const { redis } = config
describe('The \'hmget\' method', () => { describe('The \'hmget\' method', () => {
helper.allTests((ip, args) => { helper.allTests((ip, args) => {

View File

@@ -2,7 +2,8 @@
const config = require('../lib/config') const config = require('../lib/config')
const helper = require('../helper') const helper = require('../helper')
const redis = config.redis
const { redis } = config
describe('The \'hmset\' method', () => { describe('The \'hmset\' method', () => {
helper.allTests((ip, args) => { helper.allTests((ip, args) => {
@@ -20,25 +21,25 @@ describe('The \'hmset\' method', () => {
return client.hgetall(hash).then(helper.isDeepEqual({ return client.hgetall(hash).then(helper.isDeepEqual({
'0123456789': 'abcdefghij', '0123456789': 'abcdefghij',
'some manner of key': 'a type of value', 'some manner of key': 'a type of value',
'otherTypes': '555' otherTypes: '555'
})) }))
}) })
it('handles object-style syntax', () => { it('handles object-style syntax', () => {
client.hmset(hash, {'0123456789': 'abcdefghij', 'some manner of key': 'a type of value', 'otherTypes': 555}).then(helper.isString('OK')) client.hmset(hash, { '0123456789': 'abcdefghij', 'some manner of key': 'a type of value', otherTypes: 555 }).then(helper.isString('OK'))
return client.hgetall(hash).then(helper.isDeepEqual({ return client.hgetall(hash).then(helper.isDeepEqual({
'0123456789': 'abcdefghij', '0123456789': 'abcdefghij',
'some manner of key': 'a type of value', 'some manner of key': 'a type of value',
'otherTypes': '555' otherTypes: '555'
})) }))
}) })
it('handles object-style syntax and the key being a number', () => { it('handles object-style syntax and the key being a number', () => {
client.hmset(231232, {'0123456789': 'abcdefghij', 'some manner of key': 'a type of value', 'otherTypes': 555}) client.hmset(231232, { '0123456789': 'abcdefghij', 'some manner of key': 'a type of value', otherTypes: 555 })
return client.hgetall(231232).then(helper.isDeepEqual({ return client.hgetall(231232).then(helper.isDeepEqual({
'0123456789': 'abcdefghij', '0123456789': 'abcdefghij',
'some manner of key': 'a type of value', 'some manner of key': 'a type of value',
'otherTypes': '555' otherTypes: '555'
})) }))
}) })

View File

@@ -1,10 +1,11 @@
'use strict' 'use strict'
const Buffer = require('buffer').Buffer const { Buffer } = require('buffer')
const assert = require('assert') const assert = require('assert')
const config = require('../lib/config') const config = require('../lib/config')
const helper = require('../helper') const helper = require('../helper')
const redis = config.redis
const { redis } = config
describe('The \'hset\' method', () => { describe('The \'hset\' method', () => {
helper.allTests((ip, args) => { helper.allTests((ip, args) => {
@@ -43,8 +44,9 @@ describe('The \'hset\' method', () => {
it('warns if someone passed a array either as field or as value', () => { it('warns if someone passed a array either as field or as value', () => {
const hash = 'test hash' const hash = 'test hash'
const field = 'array' const field = 'array'
// This would be converted to "array contents" but if you use more than one entry, // This would be converted to "array contents" but if you use more than
// it'll result in e.g. "array contents,second content" and this is not supported and considered harmful // one entry, it'll result in e.g. "array contents,second content" and
// this is not supported and considered harmful
const value = ['array contents'] const value = ['array contents']
return client.hmset(hash, field, value).then(assert, helper.isError()) return client.hmset(hash, field, value).then(assert, helper.isError())
}) })

View File

@@ -2,7 +2,8 @@
const config = require('../lib/config') const config = require('../lib/config')
const helper = require('../helper') const helper = require('../helper')
const redis = config.redis
const { redis } = config
describe('The \'incr\' method', () => { describe('The \'incr\' method', () => {
helper.allTests((ip, args) => { helper.allTests((ip, args) => {

View File

@@ -3,7 +3,8 @@
const assert = require('assert') const assert = require('assert')
const config = require('../lib/config') const config = require('../lib/config')
const helper = require('../helper') const helper = require('../helper')
const redis = config.redis
const { redis } = config
describe('The \'info\' method', () => { describe('The \'info\' method', () => {
helper.allTests((ip, args) => { helper.allTests((ip, args) => {

View File

@@ -4,7 +4,8 @@ const assert = require('assert')
const config = require('../lib/config') const config = require('../lib/config')
const crypto = require('crypto') const crypto = require('crypto')
const helper = require('../helper') const helper = require('../helper')
const redis = config.redis
const { redis } = config
describe('The \'keys\' method', () => { describe('The \'keys\' method', () => {
helper.allTests((ip, args) => { helper.allTests((ip, args) => {
@@ -20,8 +21,8 @@ describe('The \'keys\' method', () => {
client.mset(['test keys 1', 'test val 1', 'test keys 2', 'test val 2']).then(helper.isString('OK')) client.mset(['test keys 1', 'test val 1', 'test keys 2', 'test val 2']).then(helper.isString('OK'))
return client.keys('test keys*').then((results) => { return client.keys('test keys*').then((results) => {
assert.strictEqual(2, results.length) assert.strictEqual(2, results.length)
assert.ok(~results.indexOf('test keys 1')) assert.notStrictEqual(results.indexOf('test keys 1'), -1)
assert.ok(~results.indexOf('test keys 2')) assert.notStrictEqual(results.indexOf('test keys 2'), -1)
}) })
}) })
@@ -39,7 +40,7 @@ describe('The \'keys\' method', () => {
client.mset(keysValues.reduce((a, b) => a.concat(b))).then(helper.isString('OK')) client.mset(keysValues.reduce((a, b) => a.concat(b))).then(helper.isString('OK'))
return client.keys('multibulk:*').then((results) => { return client.keys('multibulk:*').then((results) => {
assert.deepStrictEqual(keysValues.map((val) => val[0]).sort(), results.sort()) assert.deepStrictEqual(keysValues.map(val => val[0]).sort(), results.sort())
}) })
}) })

View File

@@ -2,7 +2,8 @@
const config = require('../lib/config') const config = require('../lib/config')
const helper = require('../helper') const helper = require('../helper')
const redis = config.redis
const { redis } = config
describe('The \'mget\' method', () => { describe('The \'mget\' method', () => {
helper.allTests((ip, args) => { helper.allTests((ip, args) => {

View File

@@ -1,11 +1,12 @@
'use strict' 'use strict'
const Buffer = require('buffer').Buffer const { Buffer } = require('buffer')
const assert = require('assert') const assert = require('assert')
const config = require('../lib/config') const config = require('../lib/config')
const helper = require('../helper') const helper = require('../helper')
const utils = require('../../lib/utils') const utils = require('../../lib/utils')
const redis = config.redis
const { redis } = config
describe('The \'monitor\' method', () => { describe('The \'monitor\' method', () => {
helper.allTests((parser, ip, args) => { helper.allTests((parser, ip, args) => {
@@ -185,8 +186,9 @@ describe('The \'monitor\' method', () => {
assert.deepStrictEqual(args, responses.shift()) assert.deepStrictEqual(args, responses.shift())
assert(utils.monitorRegex.test(rawOutput), rawOutput) assert(utils.monitorRegex.test(rawOutput), rawOutput)
if (responses.length === 0) { if (responses.length === 0) {
// The publish is called right after the reconnect and the monitor is called before the message is emitted. // The publish is called right after the reconnect and the monitor
// Therefore we have to wait till the next tick // is called before the message is emitted. Therefore we have to
// wait till the next tick
process.nextTick(() => { process.nextTick(() => {
assert(called) assert(called)
pub.end(false) pub.end(false)

View File

@@ -3,13 +3,17 @@
const assert = require('assert') const assert = require('assert')
const config = require('../lib/config') const config = require('../lib/config')
const helper = require('../helper') const helper = require('../helper')
const redis = config.redis
const { redis } = config
const uuid = require('uuid') const uuid = require('uuid')
describe('The \'mset\' method', () => { describe('The \'mset\' method', () => {
helper.allTests((ip, args) => { helper.allTests((ip, args) => {
describe(`using ${ip}`, () => { describe(`using ${ip}`, () => {
let key, value, key2, value2 let key
let value
let key2
let value2
beforeEach(() => { beforeEach(() => {
key = uuid.v4() key = uuid.v4()

View File

@@ -2,7 +2,8 @@
const config = require('../lib/config') const config = require('../lib/config')
const helper = require('../helper') const helper = require('../helper')
const redis = config.redis
const { redis } = config
describe('The \'msetnx\' method', () => { describe('The \'msetnx\' method', () => {
helper.allTests((ip, args) => { helper.allTests((ip, args) => {

View File

@@ -3,7 +3,8 @@
const assert = require('assert') const assert = require('assert')
const config = require('../lib/config') const config = require('../lib/config')
const helper = require('../helper') const helper = require('../helper')
const redis = config.redis
const { redis } = config
describe('The \'randomkey\' method', () => { describe('The \'randomkey\' method', () => {
helper.allTests((ip, args) => { helper.allTests((ip, args) => {

View File

@@ -2,7 +2,8 @@
const config = require('../lib/config') const config = require('../lib/config')
const helper = require('../helper') const helper = require('../helper')
const redis = config.redis
const { redis } = config
describe('The \'rename\' method', () => { describe('The \'rename\' method', () => {
helper.allTests((ip, args) => { helper.allTests((ip, args) => {

View File

@@ -2,7 +2,8 @@
const config = require('../lib/config') const config = require('../lib/config')
const helper = require('../helper') const helper = require('../helper')
const redis = config.redis
const { redis } = config
describe('The \'renamenx\' method', () => { describe('The \'renamenx\' method', () => {
helper.allTests((ip, args) => { helper.allTests((ip, args) => {

View File

@@ -2,7 +2,8 @@
const config = require('../lib/config') const config = require('../lib/config')
const helper = require('../helper') const helper = require('../helper')
const redis = config.redis
const { redis } = config
describe('The \'rpush\' command', () => { describe('The \'rpush\' command', () => {
helper.allTests((ip, args) => { helper.allTests((ip, args) => {

View File

@@ -3,7 +3,8 @@
const assert = require('assert') const assert = require('assert')
const config = require('../lib/config') const config = require('../lib/config')
const helper = require('../helper') const helper = require('../helper')
const redis = config.redis
const { redis } = config
describe('The \'sadd\' method', () => { describe('The \'sadd\' method', () => {
helper.allTests((ip, args) => { helper.allTests((ip, args) => {
@@ -18,7 +19,7 @@ describe('The \'sadd\' method', () => {
it('allows a single value to be added to the set', () => { it('allows a single value to be added to the set', () => {
client.sadd('set0', 'member0').then(helper.isNumber(1)) client.sadd('set0', 'member0').then(helper.isNumber(1))
return client.smembers('set0').then((res) => { return client.smembers('set0').then((res) => {
assert.ok(~res.indexOf('member0')) assert.notStrictEqual(res.indexOf('member0'), -1)
}) })
}) })
@@ -31,9 +32,9 @@ describe('The \'sadd\' method', () => {
client.sadd('set0', ['member0', 'member1', 'member2']).then(helper.isNumber(3)) client.sadd('set0', ['member0', 'member1', 'member2']).then(helper.isNumber(3))
return client.smembers('set0').then((res) => { return client.smembers('set0').then((res) => {
assert.strictEqual(res.length, 3) assert.strictEqual(res.length, 3)
assert.ok(~res.indexOf('member0')) assert.notStrictEqual(res.indexOf('member0'), -1)
assert.ok(~res.indexOf('member1')) assert.notStrictEqual(res.indexOf('member1'), -1)
assert.ok(~res.indexOf('member2')) assert.notStrictEqual(res.indexOf('member2'), -1)
}) })
}) })
@@ -41,9 +42,9 @@ describe('The \'sadd\' method', () => {
client.sadd(['set0', 'member0', 'member1', 'member2']).then(helper.isNumber(3)) client.sadd(['set0', 'member0', 'member1', 'member2']).then(helper.isNumber(3))
return client.smembers('set0').then((res) => { return client.smembers('set0').then((res) => {
assert.strictEqual(res.length, 3) assert.strictEqual(res.length, 3)
assert.ok(~res.indexOf('member0')) assert.notStrictEqual(res.indexOf('member0'), -1)
assert.ok(~res.indexOf('member1')) assert.notStrictEqual(res.indexOf('member1'), -1)
assert.ok(~res.indexOf('member2')) assert.notStrictEqual(res.indexOf('member2'), -1)
}) })
}) })

View File

@@ -2,7 +2,8 @@
const config = require('../lib/config') const config = require('../lib/config')
const helper = require('../helper') const helper = require('../helper')
const redis = config.redis
const { redis } = config
describe('The \'scard\' method', () => { describe('The \'scard\' method', () => {
helper.allTests((ip, args) => { helper.allTests((ip, args) => {

View File

@@ -3,7 +3,8 @@
const config = require('../lib/config') const config = require('../lib/config')
const crypto = require('crypto') const crypto = require('crypto')
const helper = require('../helper') const helper = require('../helper')
const redis = config.redis
const { redis } = config
describe('The \'script\' method', () => { describe('The \'script\' method', () => {
helper.allTests((ip, args) => { helper.allTests((ip, args) => {

View File

@@ -3,7 +3,8 @@
const assert = require('assert') const assert = require('assert')
const config = require('../lib/config') const config = require('../lib/config')
const helper = require('../helper') const helper = require('../helper')
const redis = config.redis
const { redis } = config
describe('The \'sdiff\' method', () => { describe('The \'sdiff\' method', () => {
helper.allTests((ip, args) => { helper.allTests((ip, args) => {

View File

@@ -3,7 +3,8 @@
const assert = require('assert') const assert = require('assert')
const config = require('../lib/config') const config = require('../lib/config')
const helper = require('../helper') const helper = require('../helper')
const redis = config.redis
const { redis } = config
describe('The \'sdiffstore\' method', () => { describe('The \'sdiffstore\' method', () => {
helper.allTests((ip, args) => { helper.allTests((ip, args) => {

View File

@@ -3,7 +3,8 @@
const assert = require('assert') const assert = require('assert')
const config = require('../lib/config') const config = require('../lib/config')
const helper = require('../helper') const helper = require('../helper')
const redis = config.redis
const { redis } = config
describe('The \'select\' method', () => { describe('The \'select\' method', () => {
helper.allTests((ip, args) => { helper.allTests((ip, args) => {

View File

@@ -3,13 +3,15 @@
const assert = require('assert') const assert = require('assert')
const config = require('../lib/config') const config = require('../lib/config')
const helper = require('../helper') const helper = require('../helper')
const redis = config.redis
const { redis } = config
const uuid = require('uuid') const uuid = require('uuid')
describe('The \'set\' method', () => { describe('The \'set\' method', () => {
helper.allTests((ip, args) => { helper.allTests((ip, args) => {
describe(`using ${ip}`, () => { describe(`using ${ip}`, () => {
let key, value let key
let value
beforeEach(() => { beforeEach(() => {
key = uuid.v4() key = uuid.v4()

View File

@@ -3,7 +3,8 @@
const assert = require('assert') const assert = require('assert')
const config = require('../lib/config') const config = require('../lib/config')
const helper = require('../helper') const helper = require('../helper')
const redis = config.redis
const { redis } = config
describe('The \'setex\' method', () => { describe('The \'setex\' method', () => {
helper.allTests((ip, args) => { helper.allTests((ip, args) => {

View File

@@ -2,7 +2,8 @@
const config = require('../lib/config') const config = require('../lib/config')
const helper = require('../helper') const helper = require('../helper')
const redis = config.redis
const { redis } = config
describe('The \'setnx\' method', () => { describe('The \'setnx\' method', () => {
helper.allTests((ip, args) => { helper.allTests((ip, args) => {

View File

@@ -3,7 +3,8 @@
const assert = require('assert') const assert = require('assert')
const config = require('../lib/config') const config = require('../lib/config')
const helper = require('../helper') const helper = require('../helper')
const redis = config.redis
const { redis } = config
describe('The \'sinter\' method', () => { describe('The \'sinter\' method', () => {
helper.allTests((ip, args) => { helper.allTests((ip, args) => {

View File

@@ -2,7 +2,8 @@
const config = require('../lib/config') const config = require('../lib/config')
const helper = require('../helper') const helper = require('../helper')
const redis = config.redis
const { redis } = config
describe('The \'sinterstore\' method', () => { describe('The \'sinterstore\' method', () => {
helper.allTests((ip, args) => { helper.allTests((ip, args) => {

View File

@@ -2,7 +2,8 @@
const config = require('../lib/config') const config = require('../lib/config')
const helper = require('../helper') const helper = require('../helper')
const redis = config.redis
const { redis } = config
describe('The \'sismember\' method', () => { describe('The \'sismember\' method', () => {
helper.allTests((ip, args) => { helper.allTests((ip, args) => {

View File

@@ -3,7 +3,8 @@
const assert = require('assert') const assert = require('assert')
const config = require('../lib/config') const config = require('../lib/config')
const helper = require('../helper') const helper = require('../helper')
const redis = config.redis
const { redis } = config
describe('The \'slowlog\' method', () => { describe('The \'slowlog\' method', () => {
helper.allTests((ip, args) => { helper.allTests((ip, args) => {

View File

@@ -3,7 +3,8 @@
const assert = require('assert') const assert = require('assert')
const config = require('../lib/config') const config = require('../lib/config')
const helper = require('../helper') const helper = require('../helper')
const redis = config.redis
const { redis } = config
describe('The \'smembers\' method', () => { describe('The \'smembers\' method', () => {
helper.allTests((ip, args) => { helper.allTests((ip, args) => {

View File

@@ -2,7 +2,8 @@
const config = require('../lib/config') const config = require('../lib/config')
const helper = require('../helper') const helper = require('../helper')
const redis = config.redis
const { redis } = config
describe('The \'smove\' method', () => { describe('The \'smove\' method', () => {
helper.allTests((ip, args) => { helper.allTests((ip, args) => {

View File

@@ -2,7 +2,8 @@
const config = require('../lib/config') const config = require('../lib/config')
const helper = require('../helper') const helper = require('../helper')
const redis = config.redis
const { redis } = config
function setupData(client) { function setupData(client) {
client.rpush('y', 'd') client.rpush('y', 'd')

View File

@@ -2,7 +2,8 @@
const config = require('../lib/config') const config = require('../lib/config')
const helper = require('../helper') const helper = require('../helper')
const redis = config.redis
const { redis } = config
describe('The \'spop\' method', () => { describe('The \'spop\' method', () => {
helper.allTests((ip, args) => { helper.allTests((ip, args) => {

View File

@@ -3,7 +3,8 @@
const assert = require('assert') const assert = require('assert')
const config = require('../lib/config') const config = require('../lib/config')
const helper = require('../helper') const helper = require('../helper')
const redis = config.redis
const { redis } = config
describe('The \'srem\' method', () => { describe('The \'srem\' method', () => {
helper.allTests((ip, args) => { helper.allTests((ip, args) => {
@@ -30,7 +31,7 @@ describe('The \'srem\' method', () => {
client.srem('set0', ['member1', 'member2']).then(helper.isNumber(2)) client.srem('set0', ['member1', 'member2']).then(helper.isNumber(2))
return client.smembers('set0').then((res) => { return client.smembers('set0').then((res) => {
assert.strictEqual(res.length, 1) assert.strictEqual(res.length, 1)
assert.ok(~res.indexOf('member0')) assert.notStrictEqual(res.indexOf('member0'), -1)
}) })
}) })
@@ -39,7 +40,7 @@ describe('The \'srem\' method', () => {
client.sendCommand('srem', ['set0', 'member1', 'member2']).then(helper.isNumber(2)) client.sendCommand('srem', ['set0', 'member1', 'member2']).then(helper.isNumber(2))
return client.smembers('set0').then((res) => { return client.smembers('set0').then((res) => {
assert.strictEqual(res.length, 1) assert.strictEqual(res.length, 1)
assert.ok(~res.indexOf('member0')) assert.notStrictEqual(res.indexOf('member0'), -1)
}) })
}) })
@@ -48,9 +49,9 @@ describe('The \'srem\' method', () => {
client.srem(['set0', 'member3', 'member4']).then(helper.isNumber(0)) client.srem(['set0', 'member3', 'member4']).then(helper.isNumber(0))
return client.smembers('set0').then((res) => { return client.smembers('set0').then((res) => {
assert.strictEqual(res.length, 3) assert.strictEqual(res.length, 3)
assert.ok(~res.indexOf('member0')) assert.notStrictEqual(res.indexOf('member0'), -1)
assert.ok(~res.indexOf('member1')) assert.notStrictEqual(res.indexOf('member1'), -1)
assert.ok(~res.indexOf('member2')) assert.notStrictEqual(res.indexOf('member2'), -1)
}) })
}) })

View File

@@ -3,7 +3,8 @@
const assert = require('assert') const assert = require('assert')
const config = require('../lib/config') const config = require('../lib/config')
const helper = require('../helper') const helper = require('../helper')
const redis = config.redis
const { redis } = config
describe('The \'sunion\' method', () => { describe('The \'sunion\' method', () => {
helper.allTests((ip, args) => { helper.allTests((ip, args) => {

View File

@@ -3,7 +3,8 @@
const assert = require('assert') const assert = require('assert')
const config = require('../lib/config') const config = require('../lib/config')
const helper = require('../helper') const helper = require('../helper')
const redis = config.redis
const { redis } = config
describe('The \'sunionstore\' method', () => { describe('The \'sunionstore\' method', () => {
helper.allTests((ip, args) => { helper.allTests((ip, args) => {

View File

@@ -3,7 +3,8 @@
const assert = require('assert') const assert = require('assert')
const config = require('../lib/config') const config = require('../lib/config')
const helper = require('../helper') const helper = require('../helper')
const redis = config.redis
const { redis } = config
describe('The \'ttl\' method', () => { describe('The \'ttl\' method', () => {
helper.allTests((ip, args) => { helper.allTests((ip, args) => {

View File

@@ -2,7 +2,8 @@
const config = require('../lib/config') const config = require('../lib/config')
const helper = require('../helper') const helper = require('../helper')
const redis = config.redis
const { redis } = config
describe('The \'type\' method', () => { describe('The \'type\' method', () => {
helper.allTests((ip, args) => { helper.allTests((ip, args) => {

View File

@@ -3,7 +3,8 @@
const assert = require('assert') const assert = require('assert')
const config = require('../lib/config') const config = require('../lib/config')
const helper = require('../helper') const helper = require('../helper')
const redis = config.redis
const { redis } = config
describe('The \'watch\' method', () => { describe('The \'watch\' method', () => {
helper.allTests((ip, args) => { helper.allTests((ip, args) => {

View File

@@ -3,7 +3,8 @@
const config = require('../lib/config') const config = require('../lib/config')
const helper = require('../helper') const helper = require('../helper')
const assert = require('assert') const assert = require('assert')
const redis = config.redis
const { redis } = config
describe('The \'zadd\' method', () => { describe('The \'zadd\' method', () => {
helper.allTests((ip, args) => { helper.allTests((ip, args) => {

View File

@@ -3,7 +3,8 @@
const config = require('../lib/config') const config = require('../lib/config')
const helper = require('../helper') const helper = require('../helper')
const assert = require('assert') const assert = require('assert')
const redis = config.redis
const { redis } = config
describe('The \'zscan\' method', () => { describe('The \'zscan\' method', () => {
helper.allTests((ip, args) => { helper.allTests((ip, args) => {

View File

@@ -2,7 +2,8 @@
const config = require('../lib/config') const config = require('../lib/config')
const helper = require('../helper') const helper = require('../helper')
const redis = config.redis
const { redis } = config
describe('The \'zscore\' method', () => { describe('The \'zscore\' method', () => {
helper.allTests((ip, args) => { helper.allTests((ip, args) => {

View File

@@ -4,9 +4,11 @@ const assert = require('assert')
const config = require('./lib/config') const config = require('./lib/config')
const helper = require('./helper') const helper = require('./helper')
const RedisProcess = require('./lib/redis-process') const RedisProcess = require('./lib/redis-process')
let rp let rp
const path = require('path') const path = require('path')
const redis = config.redis
const { redis } = config
// TODO: Fix redis process spawn on windows // TODO: Fix redis process spawn on windows
if (process.platform !== 'win32') { if (process.platform !== 'win32') {
@@ -43,7 +45,8 @@ if (process.platform !== 'win32') {
slave = redis.createClient({ slave = redis.createClient({
port, port,
retryStrategy(options) { retryStrategy(options) {
// Try to reconnect in very small intervals to catch the master_link_status down before the sync completes // Try to reconnect in very small intervals to catch the
// master_link_status down before the sync completes
return 10 return 10
} }
}) })

View File

@@ -4,9 +4,11 @@ const assert = require('assert')
const config = require('./lib/config') const config = require('./lib/config')
const connect = require('../lib/connect') const connect = require('../lib/connect')
const helper = require('./helper') const helper = require('./helper')
const Redis = config.redis
const { Redis } = config
const intercept = require('intercept-stdout') const intercept = require('intercept-stdout')
const net = require('net') const net = require('net')
let client let client
describe('connection tests', () => { describe('connection tests', () => {
@@ -18,9 +20,10 @@ describe('connection tests', () => {
}) })
it('support for a private stream', () => { it('support for a private stream', () => {
// While using a private stream, reconnecting and other features are not going to work properly. // While using a private stream, reconnecting and other features are not
// Besides that some functions also have to be monkey patched to be safe from errors in this case. // going to work properly. Besides that some functions also have to be
// Therefore this is not officially supported! // monkey patched to be safe from errors in this case. Therefore this is not
// officially supported!
const socket = new net.Socket() const socket = new net.Socket()
client = new Redis({ client = new Redis({
prefix: 'test', prefix: 'test',
@@ -510,7 +513,7 @@ describe('connection tests', () => {
// Cover info parts with no value // Cover info parts with no value
setImmediate(() => { setImmediate(() => {
const command = client.commandQueue.peekAt(0) const command = client.commandQueue.peekAt(0)
const callback = command.callback const { callback } = command
command.callback = (err, res) => { command.callback = (err, res) => {
res += 'added:\r\n' res += 'added:\r\n'
callback(err, res) callback(err, res)
@@ -528,7 +531,8 @@ describe('connection tests', () => {
client.info = function () { client.info = function () {
return tmp().then((res) => { return tmp().then((res) => {
if (!delayed) { if (!delayed) {
// Try reconnecting after one second even if redis tells us the time needed is above one second // Try reconnecting after one second even if redis tells us the
// time needed is above one second
client.serverInfo.persistence.loading = 1 client.serverInfo.persistence.loading = 1
client.serverInfo.persistence.loading_eta_seconds = 2.5 client.serverInfo.persistence.loading_eta_seconds = 2.5
delayed = true delayed = true

View File

@@ -1,10 +1,11 @@
'use strict' 'use strict'
const Buffer = require('buffer').Buffer const { Buffer } = require('buffer')
const assert = require('assert') const assert = require('assert')
const config = require('./lib/config') const config = require('./lib/config')
const helper = require('./helper') const helper = require('./helper')
const redis = config.redis
const { redis } = config
describe('detectBuffers', () => { describe('detectBuffers', () => {
let client let client
@@ -61,7 +62,8 @@ describe('detectBuffers', () => {
.hget(Buffer.from('hash key 2'), 'key 1') .hget(Buffer.from('hash key 2'), 'key 1')
.hget('hash key 2', Buffer.from('key 2')) .hget('hash key 2', Buffer.from('key 2'))
.hget('hash key 2', 'key 2') .hget('hash key 2', 'key 2')
.exec().then((reply) => { .exec()
.then((reply) => {
assert.strictEqual(true, Array.isArray(reply)) assert.strictEqual(true, Array.isArray(reply))
assert.strictEqual(4, reply.length) assert.strictEqual(4, reply.length)
assert.strictEqual('val 1', reply[0]) assert.strictEqual('val 1', reply[0])
@@ -81,7 +83,8 @@ describe('detectBuffers', () => {
.hget(Buffer.from('hash key 2'), 'key 1') .hget(Buffer.from('hash key 2'), 'key 1')
.hget('hash key 2', Buffer.from('key 2')) .hget('hash key 2', Buffer.from('key 2'))
.hget('hash key 2', 'key 2') .hget('hash key 2', 'key 2')
.exec().then((reply) => { .exec()
.then((reply) => {
assert.strictEqual(true, Array.isArray(reply)) assert.strictEqual(true, Array.isArray(reply))
assert.strictEqual(4, reply.length) assert.strictEqual(4, reply.length)
assert.strictEqual('val 1', reply[0]) assert.strictEqual('val 1', reply[0])

View File

@@ -3,8 +3,9 @@
const assert = require('assert') const assert = require('assert')
const config = require('./lib/config') const config = require('./lib/config')
const helper = require('./helper') const helper = require('./helper')
const fork = require('child_process').fork const { fork } = require('child_process')
const redis = config.redis
const { redis } = config
describe('stack traces', () => { describe('stack traces', () => {
it('should return good traces with NODE_ENV=development set', (done) => { it('should return good traces with NODE_ENV=development set', (done) => {

View File

@@ -5,6 +5,7 @@ const path = require('path')
const config = require('./lib/config') const config = require('./lib/config')
const RedisProcess = require('./lib/redis-process') const RedisProcess = require('./lib/redis-process')
const StunnelProcess = require('./lib/stunnel-process') const StunnelProcess = require('./lib/stunnel-process')
let rp let rp
let stunnelProcess let stunnelProcess
@@ -55,7 +56,7 @@ function toString (res) {
} }
// Stringify all values as well // Stringify all values as well
if (typeof res === 'object' && res !== null) { if (typeof res === 'object' && res !== null) {
Object.keys(res).map((key) => (res[key] = toString(res[key]))) Object.keys(res).forEach((key) => { res[key] = toString(res[key]) })
} }
return res return res
} }
@@ -134,12 +135,13 @@ module.exports = {
throw err throw err
}, },
serverVersionAtLeast(connection, desiredVersion) { serverVersionAtLeast(connection, desiredVersion) {
// Wait until a connection has established (otherwise a timeout is going to be triggered at some point) // Wait until a connection has established (otherwise a timeout is going to
// be triggered at some point)
if (Object.keys(connection.serverInfo).length === 0) { 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') 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 // Return true if the server version >= desiredVersion
const version = connection.serverInfo.server.version const { version } = connection.serverInfo.server
for (let i = 0; i < 3; i++) { for (let i = 0; i < 3; i++) {
if (version[i] > desiredVersion[i]) { if (version[i] > desiredVersion[i]) {
return true return true
@@ -167,11 +169,9 @@ module.exports = {
}] }]
options.forEach((options) => { options.forEach((options) => {
let strOptions = '' let strOptions = ''
let key const keys = Object.keys(options)
for (key in options) { for (let i = 0; i < keys.length; i++) {
if (options.hasOwnProperty(key)) { strOptions += `${keys[i]}: ${options[keys[i]]}; `
strOptions += `${key}: ${options[key]}; `
}
} }
describe(`using options: ${strOptions}`, () => { describe(`using options: ${strOptions}`, () => {
protocols.forEach((ip, i) => { protocols.forEach((ip, i) => {

View File

@@ -1,8 +1,10 @@
// Spawned by the goodStacks.spec.js tests // Spawned by the goodStacks.spec.js tests
'use strict' 'use strict'
const assert = require('assert') const assert = require('assert')
const redis = require('../../index') const redis = require('../../index')
const client = redis.createClient() const client = redis.createClient()
// Both error cases would normally return bad stack traces // Both error cases would normally return bad stack traces

View File

@@ -1,7 +1,7 @@
'use strict' 'use strict'
// Helper to start and stop the stunnel process. // Helper to start and stop the stunnel process.
const spawn = require('child_process').spawn const { spawn } = require('child_process')
const EventEmitter = require('events') const EventEmitter = require('events')
const fs = require('fs') const fs = require('fs')
const path = require('path') const path = require('path')
@@ -9,10 +9,10 @@ const util = require('util')
function once(cb) { function once(cb) {
let called = false let called = false
return function () { return function (...args) {
if (called) return if (called) return
called = true called = true
cb.apply(this, arguments) cb.apply(this, args)
} }
} }
@@ -24,7 +24,8 @@ function StunnelProcess (confDir) {
const confText = fs.readFileSync(`${confFile}.template`).toString().replace(/__dirname/g, confDir) const confText = fs.readFileSync(`${confFile}.template`).toString().replace(/__dirname/g, confDir)
fs.writeFileSync(confFile, confText) fs.writeFileSync(confFile, confText)
const stunnel = this.stunnel = spawn('stunnel', [confFile]) this.stunnel = spawn('stunnel', [confFile])
const { stunnel } = this
// Handle child process events, and failure to set up tunnel // Handle child process events, and failure to set up tunnel
this.timer = setTimeout(() => { this.timer = setTimeout(() => {
@@ -67,8 +68,8 @@ StunnelProcess.prototype.stop = function (done) {
} }
module.exports = { module.exports = {
start (done, confDir) { start(doneOrig, confDir) {
done = once(done) const done = once(doneOrig)
const stunnel = new StunnelProcess(confDir) const stunnel = new StunnelProcess(confDir)
stunnel.once('error', done.bind(done)) stunnel.once('error', done.bind(done))
stunnel.once('started', done.bind(done, null, stunnel)) stunnel.once('started', done.bind(done, null, stunnel))

View File

@@ -1,14 +1,16 @@
// spawned by the unref tests in nodeRedis.spec.js. // spawned by the unref tests in nodeRedis.spec.js.
// when configured, unref causes the client to exit // when configured, unref causes the client to exit
// as soon as there are no outstanding commands. // as soon as there are no outstanding commands.
'use strict' 'use strict'
const redis = require('../../index') const redis = require('../../index')
const HOST = process.argv[2] || '127.0.0.1' const HOST = process.argv[2] || '127.0.0.1'
const PORT = process.argv[3] const PORT = process.argv[3]
const args = PORT ? [PORT, HOST] : [HOST] const args = PORT ? [PORT, HOST] : [HOST]
const c = redis.createClient.apply(redis, args) const c = redis.createClient(...args)
c.info((err, reply) => { c.info((err, reply) => {
if (err) process.exit(-1) if (err) process.exit(-1)
if (!reply.length) process.exit(-1) if (!reply.length) process.exit(-1)

View File

@@ -1,12 +1,14 @@
'use strict' 'use strict'
const Buffer = require('buffer').Buffer const { Buffer } = require('buffer')
const assert = require('assert') const assert = require('assert')
const config = require('./lib/config') const config = require('./lib/config')
const helper = require('./helper') const helper = require('./helper')
const utils = require('../lib/utils') const utils = require('../lib/utils')
const redis = config.redis
const { redis } = config
const zlib = require('zlib') const zlib = require('zlib')
let client let client
describe('The \'multi\' method', () => { describe('The \'multi\' method', () => {
@@ -23,29 +25,29 @@ describe('The \'multi\' method', () => {
// Some random object created from http://beta.json-generator.com/ // Some random object created from http://beta.json-generator.com/
const testObj = { const testObj = {
'Id': '5642c4c33d4667c4a1fefd99', Id: '5642c4c33d4667c4a1fefd99',
'index': 0, index: 0,
'guid': '5baf1f1c-7621-41e7-ae7a-f8c6f3199b0f', guid: '5baf1f1c-7621-41e7-ae7a-f8c6f3199b0f',
'isActive': true, isActive: true,
'balance': '$1,028.63', balance: '$1,028.63',
'picture': 'http://placehold.it/32x32', picture: 'http://placehold.it/32x32',
'age': 31, age: 31,
'eyeColor': 'green', eyeColor: 'green',
'name': {'first': 'Shana', 'last': 'Long'}, name: { first: 'Shana', last: 'Long' },
'company': 'MANGLO', company: 'MANGLO',
'email': 'shana.long@manglo.us', email: 'shana.long@manglo.us',
'phone': '+1 (926) 405-3105', phone: '+1 (926) 405-3105',
'address': '747 Dank Court, Norfolk, Ohio, 1112', address: '747 Dank Court, Norfolk, Ohio, 1112',
'about': 'Eu pariatur in nisi occaecat enim qui consequat nostrud cupidatat id. ' + about: 'Eu pariatur in nisi occaecat enim qui consequat nostrud cupidatat id. ' +
'Commodo commodo dolore esse irure minim quis deserunt anim laborum aute deserunt et est. Quis nisi laborum deserunt nisi quis.', 'Commodo commodo dolore esse irure minim quis deserunt anim laborum aute deserunt et est. Quis nisi laborum deserunt nisi quis.',
'registered': 'Friday, April 18, 2014 9:56 AM', registered: 'Friday, April 18, 2014 9:56 AM',
'latitude': '74.566613', latitude: '74.566613',
'longitude': '-11.660432', longitude: '-11.660432',
'tags': [7, 'excepteur'], tags: [7, 'excepteur'],
'range': [0, 1, 2, 3, 4, 5, 6, 7, 8, 9], range: [0, 1, 2, 3, 4, 5, 6, 7, 8, 9],
'friends': [3, {'id': 1, 'name': 'Schultz Dyer'}], friends: [3, { id: 1, name: 'Schultz Dyer' }],
'greeting': 'Hello, Shana! You have 5 unread messages.', greeting: 'Hello, Shana! You have 5 unread messages.',
'favoriteFruit': 'strawberry' favoriteFruit: 'strawberry'
} }
function run() { function run() {
@@ -132,7 +134,8 @@ describe('The \'multi\' method', () => {
it('results in a execabort #2', () => { it('results in a execabort #2', () => {
// Check that using monitor with a transactions results in an error // Check that using monitor with a transactions results in an error
return client.multi().set('foo', 'bar').monitor().exec().then(assert, (err) => { return client.multi().set('foo', 'bar').monitor().exec()
.then(assert, (err) => {
assert.strictEqual(err.code, 'EXECABORT') assert.strictEqual(err.code, 'EXECABORT')
client.end(false) client.end(false)
}) })
@@ -178,7 +181,7 @@ describe('The \'multi\' method', () => {
const multi1 = client.multi() const multi1 = client.multi()
multi1.set('m1', '123') multi1.set('m1', '123')
multi1.get('m1') multi1.get('m1')
multi1.exec().then(() => (called = true)) multi1.exec().then(() => { called = true })
client.once('ready', () => { client.once('ready', () => {
const multi1 = client.multi() const multi1 = client.multi()
multi1.set('m2', '456') multi1.set('m2', '456')
@@ -334,8 +337,8 @@ describe('The \'multi\' method', () => {
[['hmset', 'multihmset2', 'multibar2', 'multifoo3', 'multibar3', 'test']], [['hmset', 'multihmset2', 'multibar2', 'multifoo3', 'multibar3', 'test']],
['hmset', ['multihmset', 'multibar', 'multifoo']], ['hmset', ['multihmset', 'multibar', 'multifoo']],
['hmset', arr3], ['hmset', arr3],
['hmset', now, {123456789: 'abcdefghij', 'some manner of key': 'a type of value', 'otherTypes': 555}], ['hmset', now, { 123456789: 'abcdefghij', 'some manner of key': 'a type of value', otherTypes: 555 }],
['hmset', 'key2', {'0123456789': 'abcdefghij', 'some manner of key': 'a type of value', 'otherTypes': 999}], ['hmset', 'key2', { '0123456789': 'abcdefghij', 'some manner of key': 'a type of value', otherTypes: 999 }],
['hmset', 'multihmset', ['multibar', 'multibaz']], ['hmset', 'multihmset', ['multibar', 'multibaz']],
['hmset', 'multihmset', ['multibar', 'multibaz']] ['hmset', 'multihmset', ['multibar', 'multibaz']]
]) ])
@@ -343,7 +346,8 @@ describe('The \'multi\' method', () => {
.hmget('key2', arr2) .hmget('key2', arr2)
.hmget(['multihmset2', 'some manner of key', 'multibar3']) .hmget(['multihmset2', 'some manner of key', 'multibar3'])
.mget('multifoo2', ['multifoo3', 'multifoo']) .mget('multifoo2', ['multifoo3', 'multifoo'])
.exec().then((replies) => { .exec()
.then((replies) => {
assert.strictEqual(arr.length, 3) assert.strictEqual(arr.length, 3)
assert.strictEqual(arr2.length, 2) assert.strictEqual(arr2.length, 2)
assert.strictEqual(arr3.length, 3) assert.strictEqual(arr3.length, 3)
@@ -376,7 +380,8 @@ describe('The \'multi\' method', () => {
.incr('some') .incr('some')
.incr('keys') .incr('keys')
.mget('some', ['keys']) .mget('some', ['keys'])
.exec().then(helper.isDeepEqual(['OK', 11, 21, ['11', '21']])) .exec()
.then(helper.isDeepEqual(['OK', 11, 21, ['11', '21']]))
}) })
it('allows an array to be provided indicating multiple operations to perform', () => { it('allows an array to be provided indicating multiple operations to perform', () => {
@@ -395,7 +400,8 @@ describe('The \'multi\' method', () => {
things: 'here' things: 'here'
}) })
.hgetall('multihash') .hgetall('multihash')
.exec().then((replies) => { .exec()
.then((replies) => {
assert.strictEqual('OK', replies[0]) assert.strictEqual('OK', replies[0])
assert.strictEqual(Object.keys(replies[2]).length, 4) assert.strictEqual(Object.keys(replies[2]).length, 4)
assert.strictEqual('foo', replies[2].a) assert.strictEqual('foo', replies[2].a)
@@ -406,7 +412,9 @@ describe('The \'multi\' method', () => {
}) })
it('reports EXECABORT exceptions when they occur (while queueing)', () => { it('reports EXECABORT exceptions when they occur (while queueing)', () => {
return client.multi().config('bar').set('foo').set('bar').exec().then(assert, (err) => { return client.multi().config('bar').set('foo').set('bar')
.exec()
.then(assert, (err) => {
assert.strictEqual(err.code, 'EXECABORT') assert.strictEqual(err.code, 'EXECABORT')
assert(err.message.match(/^EXECABORT/), 'Error message should begin with EXECABORT') assert(err.message.match(/^EXECABORT/), 'Error message should begin with EXECABORT')
assert.strictEqual(err.errors.length, 2, 'err.errors should have 2 items') assert.strictEqual(err.errors.length, 2, 'err.errors should have 2 items')
@@ -418,7 +426,9 @@ describe('The \'multi\' method', () => {
}) })
it('reports multiple exceptions when they occur (while EXEC is running)', () => { it('reports multiple exceptions when they occur (while EXEC is running)', () => {
return client.multi().config('bar').debug('foo').eval('return {err=\'this is an error\'}', 0).exec().then(assert, (err) => { return client.multi().config('bar').debug('foo').eval('return {err=\'this is an error\'}', 0)
.exec()
.then(assert, (err) => {
assert.strictEqual(err.replies.length, 3) assert.strictEqual(err.replies.length, 3)
assert.strictEqual(err.replies[0].code, 'ERR') assert.strictEqual(err.replies[0].code, 'ERR')
assert.strictEqual(err.replies[0].command, 'CONFIG') assert.strictEqual(err.replies[0].command, 'CONFIG')
@@ -487,16 +497,19 @@ describe('The \'multi\' method', () => {
}) })
it('indivdual commands work properly with multi', () => { it('indivdual commands work properly with multi', () => {
// Neither of the following work properly in a transactions: // Neither of the following work properly in a transactions: (This is
// (This is due to Redis not returning the reply as expected / resulting in undefined behavior) // due to Redis not returning the reply as expected / resulting in
// (Likely there are more commands that do not work with a transaction) // undefined behavior) (Likely there are more commands that do not
// work with a transaction)
// //
// auth => can't be called after a multi command // auth => can't be called after a multi command monitor => results in
// monitor => results in faulty return values e.g. multi().monitor().set('foo', 'bar').get('foo') // faulty return values e.g. multi().monitor().set('foo',
// returns ['OK, 'OK', 'monitor reply'] instead of ['OK', 'OK', 'bar'] // 'bar').get('foo') returns ['OK, 'OK', 'monitor reply'] instead of
// quit => ends the connection before the exec // ['OK', 'OK', 'bar'] quit => ends the connection before the exec
// client reply skip|off => results in weird return values. Not sure what exactly happens // client reply skip|off => results in weird return values. Not sure
// subscribe => enters subscribe mode and this does not work in combination with exec (the same for psubscribe, unsubscribe...) // what exactly happens subscribe => enters subscribe mode and this
// does not work in combination with exec (the same for psubscribe,
// unsubscribe...)
// //
// Make sure sendCommand is not called // Make sure sendCommand is not called
@@ -514,7 +527,10 @@ describe('The \'multi\' method', () => {
return multi.exec().then((res) => { return multi.exec().then((res) => {
res[2] = res[2].substr(0, 10) res[2] = res[2].substr(0, 10)
assert.strictEqual(client.selectedDb, 5) assert.strictEqual(client.selectedDb, 5)
assert.deepStrictEqual(client.serverInfo.keyspace.db5, { avg_ttl: 0, expires: 0, keys: 1 }) assert.deepStrictEqual(
client.serverInfo.keyspace.db5,
{ avg_ttl: 0, expires: 0, keys: 1 }
)
assert.deepStrictEqual(res, ['OK', 'OK', '# Server\r\n', 'bar']) assert.deepStrictEqual(res, ['OK', 'OK', '# Server\r\n', 'bar'])
return client.flushdb() return client.flushdb()
}) })

View File

@@ -1,14 +1,15 @@
'use strict' 'use strict'
const Buffer = require('buffer').Buffer const { Buffer } = require('buffer')
const assert = require('assert') const assert = require('assert')
const fs = require('fs') const fs = require('fs')
const path = require('path') const path = require('path')
const config = require('./lib/config') const config = require('./lib/config')
const helper = require('./helper') const helper = require('./helper')
const fork = require('child_process').fork const { fork } = require('child_process')
const Errors = require('redis-errors') const Errors = require('redis-errors')
const redis = config.redis
const { redis } = config
let client let client
describe('The nodeRedis client', () => { describe('The nodeRedis client', () => {
@@ -113,10 +114,9 @@ describe('The nodeRedis client', () => {
assert.strictEqual(client2.selectedDb, 2) assert.strictEqual(client2.selectedDb, 2)
assert(client.connected) assert(client.connected)
assert(!client2.connected) assert(!client2.connected)
for (const elem in client._options) { const keys = Object.keys(client._options)
if (client._options.hasOwnProperty(elem)) { for (let i = 0; i < keys.length; i++) {
assert.strictEqual(client2._options[elem], client._options[elem]) assert.strictEqual(client2._options[keys[i]], client._options[keys[i]])
}
} }
client2.on('error', (err) => { client2.on('error', (err) => {
assert.strictEqual(err.message, 'Connection forcefully ended and command aborted.') assert.strictEqual(err.message, 'Connection forcefully ended and command aborted.')
@@ -140,11 +140,10 @@ describe('The nodeRedis client', () => {
assert.strictEqual(client._options.noReadyCheck, undefined) assert.strictEqual(client._options.noReadyCheck, undefined)
assert.strictEqual(client2._options.noReadyCheck, true) assert.strictEqual(client2._options.noReadyCheck, true)
assert.notDeepEqual(client._options, client2._options) assert.notDeepEqual(client._options, client2._options)
for (const elem in client._options) { const keys = Object.keys(client._options)
if (client._options.hasOwnProperty(elem)) { for (let i = 0; i < keys.length; i++) {
if (elem !== 'noReadyCheck') { if (keys[i] !== 'noReadyCheck') {
assert.strictEqual(client2._options[elem], client._options[elem]) assert.strictEqual(client2._options[keys[i]], client._options[keys[i]])
}
} }
} }
client2.on('ready', () => { client2.on('ready', () => {
@@ -190,12 +189,14 @@ describe('The nodeRedis client', () => {
}) })
it('using multi with sendCommand should work as individual command instead of using the internal multi', () => { it('using multi with sendCommand should work as individual command instead of using the internal multi', () => {
// This is necessary to keep backwards compatibility and it is the only way to handle multi as you want in nodeRedis // This is necessary to keep backwards compatibility and it is the
// only way to handle multi as you want in nodeRedis
client.sendCommand('multi') client.sendCommand('multi')
client.sendCommand('set', ['foo', 'bar']).then(helper.isString('QUEUED')) client.sendCommand('set', ['foo', 'bar']).then(helper.isString('QUEUED'))
client.get('foo') client.get('foo')
// exec is not manipulated if not fired by the individual multi command // exec is not manipulated if not fired by the individual multi
// As the multi command is handled individually by the user he also has to handle the return value // command As the multi command is handled individually by the user
// he also has to handle the return value
return client.exec().then(helper.isDeepEqual(['OK', 'bar'])) return client.exec().then(helper.isDeepEqual(['OK', 'bar']))
}) })
@@ -205,7 +206,8 @@ describe('The nodeRedis client', () => {
client.sendCommand('set', args).then(helper.isString('QUEUED')) client.sendCommand('set', args).then(helper.isString('QUEUED'))
assert.deepStrictEqual(args, ['test', 'bla']) // Check args manipulation assert.deepStrictEqual(args, ['test', 'bla']) // Check args manipulation
client.get('test').then(helper.isString('QUEUED')) client.get('test').then(helper.isString('QUEUED'))
// As the multi command is handled individually by the user he also has to handle the return value // As the multi command is handled individually by the user he also
// has to handle the return value
return client.exec().then(helper.isDeepEqual(['OK', 'bla'])) return client.exec().then(helper.isDeepEqual(['OK', 'bla']))
}) })
@@ -245,13 +247,15 @@ describe('The nodeRedis client', () => {
client.sendCommand('set', args).then(helper.isString('QUEUED')) client.sendCommand('set', args).then(helper.isString('QUEUED'))
assert.deepStrictEqual(args, ['test', 'bla']) // Check args manipulation assert.deepStrictEqual(args, ['test', 'bla']) // Check args manipulation
client.get('test').then(helper.isString('QUEUED')) client.get('test').then(helper.isString('QUEUED'))
// As the multi command is handled individually by the user he also has to handle the return value // As the multi command is handled individually by the user he also
// has to handle the return value
return client.exec().then(helper.isDeepEqual(['OK', 'bla'])) return client.exec().then(helper.isDeepEqual(['OK', 'bla']))
}) })
it('the args array may contain a arbitrary number of arguments', () => { it('the args array may contain a arbitrary number of arguments', () => {
client.sendCommand('mset', ['foo', 1, 'bar', 2, 'baz', 3]).then(helper.isString('OK')) client.sendCommand('mset', ['foo', 1, 'bar', 2, 'baz', 3]).then(helper.isString('OK'))
// As the multi command is handled individually by the user he also has to handle the return value // As the multi command is handled individually by the user he also
// has to handle the return value
return client.mget(['foo', 'bar', 'baz']).then(helper.isDeepEqual(['1', '2', '3'])) return client.mget(['foo', 'bar', 'baz']).then(helper.isDeepEqual(['1', '2', '3']))
}) })
@@ -502,7 +506,8 @@ describe('The nodeRedis client', () => {
assert.strictEqual(err.message, 'Protocol error, got "a" as reply type byte. Please report this.') assert.strictEqual(err.message, 'Protocol error, got "a" as reply type byte. Please report this.')
assert.strictEqual(err, error) assert.strictEqual(err, error)
assert(err instanceof redis.ParserError) assert(err instanceof redis.ParserError)
// After the hard failure work properly again. The set should have been processed properly too // After the hard failure work properly again. The set should have
// been processed properly too
client.get('foo').then(helper.isString('bar')).then(done) client.get('foo').then(helper.isString('bar')).then(done)
}) })
client.once('ready', () => { client.once('ready', () => {
@@ -512,9 +517,9 @@ describe('The nodeRedis client', () => {
assert(err instanceof redis.InterruptError) assert(err instanceof redis.InterruptError)
error = err.origin error = err.origin
}) })
// Make sure we call execute out of the reply. // Make sure we call execute out of the reply. Ready is called in a
// Ready is called in a reply. // reply. Fail the set answer. Has no corresponding command obj and
// Fail the set answer. Has no corresponding command obj and will therefore land in the error handler and set // will therefore land in the error handler and set
process.nextTick(() => client._replyParser.execute(Buffer.from('a*1\r*1\r$1`zasd\r\na'))) process.nextTick(() => client._replyParser.execute(Buffer.from('a*1\r*1\r$1`zasd\r\na')))
}) })
}) })
@@ -587,6 +592,7 @@ describe('The nodeRedis client', () => {
}) })
it('flushes the command queue if connection is lost', (done) => { it('flushes the command queue if connection is lost', (done) => {
const end = helper.callFuncAfter(done, 2)
client = redis.createClient() client = redis.createClient()
client.once('ready', () => { client.once('ready', () => {
@@ -607,8 +613,6 @@ describe('The nodeRedis client', () => {
assert.strictEqual(client.commandQueue.length, 15) assert.strictEqual(client.commandQueue.length, 15)
helper.killConnection(client) helper.killConnection(client)
}) })
const end = helper.callFuncAfter(done, 2)
client.on('error', (err) => { client.on('error', (err) => {
assert.strictEqual(err.code, 'ECONNREFUSED') assert.strictEqual(err.code, 'ECONNREFUSED')
assert.strictEqual(err.errno, 'ECONNREFUSED') assert.strictEqual(err.errno, 'ECONNREFUSED')

View File

@@ -3,7 +3,8 @@
const assert = require('assert') const assert = require('assert')
const config = require('./lib/config') const config = require('./lib/config')
const helper = require('./helper') const helper = require('./helper')
const redis = config.redis
const { redis } = config
describe('prefix key names', () => { describe('prefix key names', () => {
helper.allTests((ip, args) => { helper.allTests((ip, args) => {

View File

@@ -1,10 +1,11 @@
'use strict' 'use strict'
const Buffer = require('buffer').Buffer const { Buffer } = require('buffer')
const assert = require('assert') const assert = require('assert')
const config = require('./lib/config') const config = require('./lib/config')
const helper = require('./helper') const helper = require('./helper')
const redis = config.redis
const { redis } = config
describe('publish/subscribe', () => { describe('publish/subscribe', () => {
helper.allTests((ip, args) => { helper.allTests((ip, args) => {
@@ -461,7 +462,7 @@ describe('publish/subscribe', () => {
const end = helper.callFuncAfter(done, 5) const end = helper.callFuncAfter(done, 5)
const data = Array(10000).join('äüs^öéÉÉ`e') const data = Array(10000).join('äüs^öéÉÉ`e')
sub.set('foo', data).then(() => { sub.set('foo', data).then(() => {
sub.get('foo').then((res) => assert.strictEqual(typeof res, 'string')) sub.get('foo').then(res => assert.strictEqual(typeof res, 'string'))
sub._stream.once('data', () => { sub._stream.once('data', () => {
assert.strictEqual(sub._messageBuffers, false) assert.strictEqual(sub._messageBuffers, false)
assert.strictEqual(sub.shouldBuffer, false) assert.strictEqual(sub.shouldBuffer, false)
@@ -586,7 +587,8 @@ describe('publish/subscribe', () => {
.psubscribe(['pattern:*']) .psubscribe(['pattern:*'])
.punsubscribe('unknown*') .punsubscribe('unknown*')
.punsubscribe(['pattern:*']) .punsubscribe(['pattern:*'])
.exec().then(() => Promise.all([ .exec()
.then(() => Promise.all([
sub.client('kill', ['type', 'pubsub']), sub.client('kill', ['type', 'pubsub']),
sub.psubscribe('*'), sub.psubscribe('*'),
sub.punsubscribe('pa*'), sub.punsubscribe('pa*'),

View File

@@ -3,7 +3,8 @@
const assert = require('assert') const assert = require('assert')
const config = require('./lib/config') const config = require('./lib/config')
const helper = require('./helper') const helper = require('./helper')
const redis = config.redis
const { redis } = config
// TODO: Fix redis process spawn on windows // TODO: Fix redis process spawn on windows
if (process.platform !== 'win32') { if (process.platform !== 'win32') {

View File

@@ -1,10 +1,11 @@
'use strict' 'use strict'
const Buffer = require('buffer').Buffer const { Buffer } = require('buffer')
const assert = require('assert') const assert = require('assert')
const config = require('./lib/config') const config = require('./lib/config')
const helper = require('./helper') const helper = require('./helper')
const redis = config.redis
const { redis } = config
describe('returnBuffers', () => { describe('returnBuffers', () => {
helper.allTests((ip, basicArgs) => { helper.allTests((ip, basicArgs) => {
@@ -64,7 +65,8 @@ describe('returnBuffers', () => {
.hget(Buffer.from('hash key 2'), 'key 1') .hget(Buffer.from('hash key 2'), 'key 1')
.hget('hash key 2', Buffer.from('key 2')) .hget('hash key 2', Buffer.from('key 2'))
.hget('hash key 2', 'key 2') .hget('hash key 2', 'key 2')
.exec().then((reply) => { .exec()
.then((reply) => {
assert.strictEqual(4, reply.length) assert.strictEqual(4, reply.length)
assert.strictEqual('<Buffer 76 61 6c 20 31>', reply[0].inspect()) assert.strictEqual('<Buffer 76 61 6c 20 31>', reply[0].inspect())
assert.strictEqual(true, Buffer.isBuffer(reply[1])) assert.strictEqual(true, Buffer.isBuffer(reply[1]))
@@ -84,7 +86,8 @@ describe('returnBuffers', () => {
.hget(Buffer.from('hash key 2'), 'key 1') .hget(Buffer.from('hash key 2'), 'key 1')
.hget('hash key 2', Buffer.from('key 2')) .hget('hash key 2', Buffer.from('key 2'))
.hget('hash key 2', 'key 2') .hget('hash key 2', 'key 2')
.exec().then((reply) => { .exec()
.then((reply) => {
assert.strictEqual(4, reply.length) assert.strictEqual(4, reply.length)
assert.strictEqual('<Buffer 76 61 6c 20 31>', reply[0].inspect()) assert.strictEqual('<Buffer 76 61 6c 20 31>', reply[0].inspect())
assert.strictEqual(true, Buffer.isBuffer(reply[1])) assert.strictEqual(true, Buffer.isBuffer(reply[1]))

View File

@@ -5,7 +5,8 @@ const config = require('./lib/config')
const fs = require('fs') const fs = require('fs')
const helper = require('./helper') const helper = require('./helper')
const path = require('path') const path = require('path')
const redis = config.redis
const { redis } = config
const utils = require('../lib/utils') const utils = require('../lib/utils')
const tlsOptions = { const tlsOptions = {

View File

@@ -120,7 +120,8 @@ describe('createClient options', () => {
option: [1, 2, 3] option: [1, 2, 3]
}) })
unhookIntercept() unhookIntercept()
assert.strictEqual(text, assert.strictEqual(
text,
'nodeRedis: WARNING: You passed the db option twice!\n' + 'nodeRedis: WARNING: You passed the db option twice!\n' +
'nodeRedis: WARNING: You passed the port option twice!\n' + 'nodeRedis: WARNING: You passed the port option twice!\n' +
'nodeRedis: WARNING: You passed the password option twice!\n' 'nodeRedis: WARNING: You passed the password option twice!\n'

View File

@@ -6,10 +6,10 @@ const intercept = require('intercept-stdout')
const utils = require('../lib/utils') const utils = require('../lib/utils')
describe('utils.js', () => { describe('utils.js', () => {
describe('print helper', function () { describe('print helper', () => {
it('callback with reply', function () { it('callback with reply', () => {
var text = '' let text = ''
const unhookIntercept = intercept(function (data) { const unhookIntercept = intercept((data) => {
text += data text += data
return '' return ''
}) })
@@ -18,9 +18,9 @@ describe('utils.js', () => {
assert.strictEqual(text, 'Reply: abc\n') assert.strictEqual(text, 'Reply: abc\n')
}) })
it('callback with error', function () { it('callback with error', () => {
var text = '' let text = ''
const unhookIntercept = intercept(function (data) { const unhookIntercept = intercept((data) => {
text += data text += data
return '' return ''
}) })