You've already forked node-redis
mirror of
https://github.com/redis/node-redis.git
synced 2025-08-06 02:15:48 +03:00
chore: add print helper again and refactor some code
Expose the RedisClient directly instead of only being a property
This commit is contained in:
13
changelog.md
13
changelog.md
@@ -19,14 +19,18 @@ and maybe more.
|
||||
|
||||
Bugfixes
|
||||
- Fixed auth in batch not saving the password
|
||||
- Fixed catch tls handshake failures with newer Node.js versions
|
||||
- Fixed stream option being copied
|
||||
- Fixed pub sub activated, listening to a `(p)messageBuffer`, no Buffer returns
|
||||
and monitoring resulting in a crash.
|
||||
|
||||
Features
|
||||
- Native promise support
|
||||
- Auto pipelining
|
||||
- The client is now exported directly and be instantiated directly
|
||||
|
||||
Breaking Changes
|
||||
|
||||
- Dropped support for `UPPER_CASE` commands
|
||||
- Dropped support for `snake_case`
|
||||
- Dropped support for domains
|
||||
- Dropped support for Redis 2.4
|
||||
@@ -36,9 +40,7 @@ Breaking Changes
|
||||
- Removed `parser` option
|
||||
- Removed `retryMaxDelay` (max_delay) option
|
||||
- Removed `maxAttempts` (max_attempts) option
|
||||
- Removed `socketNoDelay` (socket_no_delay) option
|
||||
- Removed `authPass` (auth_pass) option. Please use `password` instead
|
||||
- Removed `Redis.print` helper function
|
||||
- Removed `socketNoDelay` (socket\_no_delay) option
|
||||
- Removed backpressure indicator from function return value
|
||||
- Removed the `stream` parameter from the RedisClient constructor.
|
||||
- Please set the stream in the options instead
|
||||
@@ -60,11 +62,12 @@ Breaking Changes
|
||||
- `restore-asking` is now `restore_asking_`
|
||||
- `host:` is now `host`
|
||||
- Changed the `serverInfo` into a nested object and to parse numbers
|
||||
- Changed the `serverInfo.versions` to `serverInfo.version`
|
||||
- Changed the `serverInfo.versions` to `serverInfo.server.version`
|
||||
- Changed the `message` and `pmessage` listener to always return a string
|
||||
- If you want to receive a buffer, please listen to the `messageBuffer` or `pmessageBuffer`
|
||||
- Using `.end` without the flush parameter is now going to throw an TypeError
|
||||
- Only emit ready when all commands were truly send to Redis
|
||||
- `UPPER_CASE` commands are not enumerated anymore
|
||||
|
||||
## v.2.7.2 - 14 Mar, 2017
|
||||
|
||||
|
42
index.js
42
index.js
@@ -20,6 +20,7 @@ const offlineCommand = require('./lib/offlineCommand')
|
||||
const utils = require('./lib/utils')
|
||||
const normalizeAndWriteCommand = require('./lib/writeCommands')
|
||||
const noop = function () {}
|
||||
var connectionId = 0
|
||||
|
||||
// Attention: The second parameter might be removed at will and is not officially supported.
|
||||
// Do not rely on this
|
||||
@@ -34,8 +35,8 @@ class RedisClient extends EventEmitter {
|
||||
super()
|
||||
// Copy the options so they are not mutated
|
||||
options = utils.clone(options)
|
||||
// TODO: Add a more restrictive options validation
|
||||
const cnxOptions = {}
|
||||
/* istanbul ignore next: travis does not work with stunnel atm. Therefore the tls tests are skipped on travis */
|
||||
for (const tlsOption in options.tls) {
|
||||
if (options.tls.hasOwnProperty(tlsOption)) {
|
||||
cnxOptions[tlsOption] = options.tls[tlsOption]
|
||||
@@ -140,6 +141,8 @@ class RedisClient extends EventEmitter {
|
||||
// Do not call internalSendCommand directly, if you are not absolutely certain 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: Check how others can intercept (monkey patch) essential parts (e.g. opbeat)
|
||||
// after making this private.
|
||||
internalSendCommand (commandObj) {
|
||||
if (this.ready === false || this._stream.writable === false) {
|
||||
// Handle offline commands right away
|
||||
@@ -154,7 +157,6 @@ class RedisClient extends EventEmitter {
|
||||
}
|
||||
// Handle `CLIENT REPLY ON|OFF|SKIP`
|
||||
// This has to be checked after callOnWrite
|
||||
/* istanbul ignore else: TODO: Remove this as soon as we test Redis 3.2 on travis */
|
||||
if (this._reply === 'ON') {
|
||||
this.commandQueue.push(commandObj)
|
||||
} else {
|
||||
@@ -229,6 +231,10 @@ class RedisClient extends EventEmitter {
|
||||
}
|
||||
|
||||
// TODO: promisify this
|
||||
// This can not be done without removing support to return the client sync.
|
||||
// This would be another BC and it should be fine to return the client sync.
|
||||
// Therefore a option could be to accept a resolved promise instead of a callback
|
||||
// to return a promise.
|
||||
duplicate (options, callback) {
|
||||
if (typeof options === 'function') {
|
||||
callback = options
|
||||
@@ -261,33 +267,31 @@ class RedisClient extends EventEmitter {
|
||||
|
||||
// Note: this overrides a native function!
|
||||
multi (args) {
|
||||
return new Multi(this, 'multi', args)
|
||||
return new Multi(this, args, 'multi')
|
||||
}
|
||||
|
||||
// Note: This is not a native function but is still handled as a individual command as it behaves just the same as multi
|
||||
batch (args) {
|
||||
return new Multi(this, 'batch', args)
|
||||
return new Multi(this, args, 'batch')
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
RedisClient.connectionId = 0
|
||||
RedisClient.debugMode = /\bredis\b/i.test(process.env.NODE_DEBUG)
|
||||
RedisClient.RedisClient = RedisClient
|
||||
RedisClient.Multi = Multi
|
||||
RedisClient.AbortError = Errors.AbortError
|
||||
RedisClient.ParserError = Errors.ParserError
|
||||
RedisClient.RedisError = Errors.RedisError
|
||||
RedisClient.ReplyError = Errors.ReplyError
|
||||
RedisClient.InterruptError = Errors.InterruptError
|
||||
RedisClient.print = utils.print
|
||||
RedisClient.createClient = function () {
|
||||
return new RedisClient(unifyOptions.apply(null, arguments))
|
||||
}
|
||||
|
||||
Commands.list.forEach((name) => addCommand(RedisClient.prototype, Multi.prototype, name))
|
||||
|
||||
module.exports = {
|
||||
debugMode: /\bredis\b/i.test(process.env.NODE_DEBUG),
|
||||
RedisClient,
|
||||
Multi,
|
||||
AbortError: Errors.AbortError,
|
||||
ParserError: Errors.ParserError,
|
||||
RedisError: Errors.RedisError,
|
||||
ReplyError: Errors.ReplyError,
|
||||
InterruptError: Errors.InterruptError,
|
||||
createClient () {
|
||||
return new RedisClient(unifyOptions.apply(null, arguments))
|
||||
}
|
||||
}
|
||||
module.exports = RedisClient
|
||||
|
||||
// Add all redis commands / nodeRedis api to the client
|
||||
// TODO: Change the way this is included...
|
||||
|
@@ -23,6 +23,12 @@ function addCommand (clientProto, multiProto, command) {
|
||||
})
|
||||
}
|
||||
}
|
||||
Object.defineProperty(clientProto, commandName.toUpperCase(), {
|
||||
enumerable: false,
|
||||
configurable: false,
|
||||
writable: false,
|
||||
value: clientProto[commandName]
|
||||
})
|
||||
|
||||
// Do not override existing functions
|
||||
if (!multiProto[command] && command !== 'multi') {
|
||||
@@ -41,6 +47,12 @@ function addCommand (clientProto, multiProto, command) {
|
||||
})
|
||||
}
|
||||
}
|
||||
Object.defineProperty(multiProto, commandName.toUpperCase(), {
|
||||
enumerable: false,
|
||||
configurable: false,
|
||||
writable: false,
|
||||
value: clientProto[commandName]
|
||||
})
|
||||
}
|
||||
|
||||
module.exports = addCommand
|
||||
|
@@ -10,9 +10,9 @@ const replyHandler = require('./replyHandler')
|
||||
const onResult = replyHandler.onResult
|
||||
const onError = replyHandler.onError
|
||||
|
||||
var reconnect = function (client, why, err) {
|
||||
reconnect = require('./reconnect')
|
||||
reconnect(client, why, err)
|
||||
var lazyReconnect = function (client, why, err) {
|
||||
lazyReconnect = require('./reconnect')
|
||||
lazyReconnect(client, why, err)
|
||||
}
|
||||
|
||||
function onStreamError (client, err) {
|
||||
@@ -31,7 +31,7 @@ function onStreamError (client, err) {
|
||||
}
|
||||
// 'error' events get turned into exceptions if they aren't listened for. If the user handled this error
|
||||
// then we should try to reconnect.
|
||||
reconnect(client, 'error', err)
|
||||
lazyReconnect(client, 'error', err)
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -91,9 +91,19 @@ function connect (client) {
|
||||
client._stream.destroy()
|
||||
}
|
||||
|
||||
/* istanbul ignore if: travis does not work with stunnel atm. Therefore the tls tests are skipped on travis */
|
||||
if (client._options.tls) {
|
||||
client._stream = tls.connect(client._connectionOptions)
|
||||
|
||||
// Whenever a handshake times out.
|
||||
// Older Node.js versions use "clientError", newer versions use tlsClientError.
|
||||
stream.once('clientError', (err) => {
|
||||
debug('clientError occurred')
|
||||
onStreamError(client, err)
|
||||
})
|
||||
stream.once('tlsClientError', (err) => {
|
||||
debug('clientError occurred')
|
||||
onStreamError(client, err)
|
||||
})
|
||||
} else {
|
||||
client._stream = net.createConnection(client._connectionOptions)
|
||||
}
|
||||
@@ -105,11 +115,10 @@ function connect (client) {
|
||||
// TODO: Investigate why this is not properly triggered
|
||||
stream.setTimeout(client._options.connectTimeout, () => {
|
||||
// Note: This is only tested if a internet connection is established
|
||||
reconnect(client, 'timeout')
|
||||
lazyReconnect(client, 'timeout')
|
||||
})
|
||||
}
|
||||
|
||||
/* istanbul ignore next: travis does not work with stunnel atm. Therefore the tls tests are skipped on travis */
|
||||
const connectEvent = client._options.tls ? 'secureConnect' : 'connect'
|
||||
stream.once(connectEvent, () => {
|
||||
stream.removeAllListeners('timeout')
|
||||
@@ -126,18 +135,12 @@ function connect (client) {
|
||||
onStreamError(client, err)
|
||||
})
|
||||
|
||||
/* istanbul ignore next: difficult to test and not important as long as we keep this listener */
|
||||
stream.on('clientError', (err) => {
|
||||
debug('clientError occurred')
|
||||
onStreamError(client, err)
|
||||
})
|
||||
|
||||
stream.once('close', (hadError) => {
|
||||
reconnect(client, 'close')
|
||||
lazyReconnect(client, 'close')
|
||||
})
|
||||
|
||||
stream.once('end', () => {
|
||||
reconnect(client, 'end')
|
||||
lazyReconnect(client, 'end')
|
||||
})
|
||||
|
||||
stream.setNoDelay()
|
||||
|
@@ -3,7 +3,9 @@
|
||||
const utils = require('./utils')
|
||||
const URL = require('url')
|
||||
|
||||
module.exports = function createClient (portArg, hostArg, options) {
|
||||
// TODO: Improve the unify performance by checking for the arguments length
|
||||
// before trying to access that argument.
|
||||
function unifyOptions (portArg, hostArg, options) {
|
||||
if (typeof portArg === 'number' || (typeof portArg === 'string' && /^\d+$/.test(portArg))) {
|
||||
var host
|
||||
if (typeof hostArg === 'string') {
|
||||
@@ -75,3 +77,5 @@ module.exports = function createClient (portArg, hostArg, options) {
|
||||
|
||||
return options
|
||||
}
|
||||
|
||||
module.exports = unifyOptions
|
||||
|
@@ -186,7 +186,7 @@ function authCallback (client, pass) {
|
||||
if (err) {
|
||||
if (noPasswordIsSet.test(err.message)) {
|
||||
utils.warn(client, 'Warning: Redis server does not require a password, but a password was supplied.')
|
||||
return 'OK' // TODO: Fix this
|
||||
return 'OK'
|
||||
}
|
||||
return err
|
||||
}
|
||||
@@ -224,7 +224,6 @@ RedisClient.prototype.client = function client () {
|
||||
}
|
||||
var callOnWrite
|
||||
// CLIENT REPLY ON|OFF|SKIP
|
||||
/* istanbul ignore next: TODO: Remove this as soon as Travis runs Redis 3.2 */
|
||||
if (arr.length === 2 && arr[0].toString().toUpperCase() === 'REPLY') {
|
||||
const replyOnOff = arr[1].toString().toUpperCase()
|
||||
if (replyOnOff === 'ON' || replyOnOff === 'OFF' || replyOnOff === 'SKIP') {
|
||||
@@ -244,7 +243,6 @@ Multi.prototype.client = function client () {
|
||||
}
|
||||
var callOnWrite
|
||||
// CLIENT REPLY ON|OFF|SKIP
|
||||
/* istanbul ignore next: TODO: Remove this as soon as Travis runs Redis 3.2 */
|
||||
if (arr.length === 2 && arr[0].toString().toUpperCase() === 'REPLY') {
|
||||
const replyOnOff = arr[1].toString().toUpperCase()
|
||||
if (replyOnOff === 'ON' || replyOnOff === 'OFF' || replyOnOff === 'SKIP') {
|
||||
|
@@ -145,14 +145,14 @@ class Multi {
|
||||
/**
|
||||
* Creates an instance of Multi.
|
||||
* @param {RedisClient} client
|
||||
* @param {string} type
|
||||
* @param {any[]} [args]
|
||||
* @param {string} [type]
|
||||
*
|
||||
* @memberof Multi
|
||||
*/
|
||||
constructor (client, type, args) {
|
||||
constructor (client, args, type) {
|
||||
this._client = client
|
||||
this._type = type
|
||||
this._type = typeof type === 'string' ? type : 'multi'
|
||||
this._queue = new Queue()
|
||||
// Either undefined or an array. Fail hard if it's not an array
|
||||
if (args) {
|
||||
|
@@ -105,7 +105,6 @@ function readyCheck (client) {
|
||||
// Always fire client info command as first command even if other commands are already queued up
|
||||
client.ready = true
|
||||
client.info().then((res) => {
|
||||
/* istanbul ignore if: some servers might not respond with any info data. client is just a safety check that is difficult to test */
|
||||
if (!res) {
|
||||
debug('The info command returned without any data.')
|
||||
readyHandler(client)
|
||||
|
@@ -40,7 +40,7 @@ function onResult (client, reply) {
|
||||
// If in monitor mode, all normal commands are still working and we only want to emit the streamlined commands
|
||||
// As this is not the average use case and 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) {
|
||||
if (client._monitoring === true) {
|
||||
var replyStr
|
||||
if (client.buffers && Buffer.isBuffer(reply)) {
|
||||
replyStr = reply.toString()
|
||||
@@ -63,6 +63,7 @@ function onResult (client, reply) {
|
||||
} else if (client._pubSubMode !== 1) {
|
||||
client._pubSubMode--
|
||||
normalReply(client, reply)
|
||||
// TODO: Have another look at this if this could be further improved
|
||||
} else if (!(reply instanceof Array) || reply.length <= 2) {
|
||||
// Only PING and QUIT are allowed in this context besides the pub sub commands
|
||||
// Ping replies with ['pong', null|value] and quit with 'OK'
|
||||
|
46
lib/utils.js
46
lib/utils.js
@@ -46,25 +46,29 @@ function replyToStrings (reply) {
|
||||
* @description Deep clone arbitrary objects with arrays.
|
||||
* Can't handle cyclic structures (results in a range error).
|
||||
* Any attribute with a non primitive value besides object
|
||||
* and array will be passed by reference (e.g. Buffers, Maps, Functions)
|
||||
* and array will be passed by reference (e.g. Buffers, Maps, Functions).
|
||||
*
|
||||
* @param {any} obj
|
||||
* @returns any
|
||||
*/
|
||||
function clone (obj) {
|
||||
var copy
|
||||
if (Array.isArray(obj)) {
|
||||
copy = new Array(obj.length)
|
||||
const copy = new Array(obj.length)
|
||||
for (var i = 0; i < obj.length; i++) {
|
||||
copy[i] = clone(obj[i])
|
||||
}
|
||||
return copy
|
||||
}
|
||||
if (Object.prototype.toString.call(obj) === '[object Object]') {
|
||||
copy = {}
|
||||
const elements = Object.keys(obj)
|
||||
for (var elem = elements.pop(); elem !== undefined; elem = elements.pop()) {
|
||||
copy[elem] = clone(obj[elem])
|
||||
const copy = {}
|
||||
const keys = Object.keys(obj)
|
||||
while (keys.length) {
|
||||
const key = keys.pop()
|
||||
if (key === 'stream') {
|
||||
copy[key] = obj[key]
|
||||
} else {
|
||||
copy[key] = clone(obj[key])
|
||||
}
|
||||
}
|
||||
return copy
|
||||
}
|
||||
@@ -96,12 +100,10 @@ function convenienceClone (obj) {
|
||||
* @param {Denque} queue
|
||||
*/
|
||||
function replyInOrder (client, callback, err, res, queue) {
|
||||
var commandObj
|
||||
if (queue) {
|
||||
commandObj = queue.peekBack()
|
||||
} else {
|
||||
commandObj = client.offlineQueue.peekBack() || client.commandQueue.peekBack()
|
||||
}
|
||||
const commandObj = queue
|
||||
? queue.peekBack()
|
||||
: (client.offlineQueue.peekBack() || client.commandQueue.peekBack())
|
||||
|
||||
if (!commandObj) {
|
||||
process.nextTick(callback, err, res)
|
||||
} else {
|
||||
@@ -149,6 +151,21 @@ function handleReply (client, reply, command) {
|
||||
return reply
|
||||
}
|
||||
|
||||
/**
|
||||
* @description Callback result print helper
|
||||
*
|
||||
* @param {Error|null} err
|
||||
* @param {any} reply
|
||||
*/
|
||||
function print (err, reply) {
|
||||
if (err) {
|
||||
// A error always begins with Error:
|
||||
console.error(err.toString())
|
||||
} else {
|
||||
console.log('Reply: ' + reply)
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @description Set default reconnect variables
|
||||
*
|
||||
@@ -171,5 +188,6 @@ module.exports = {
|
||||
replyInOrder,
|
||||
warn,
|
||||
handleReply,
|
||||
setReconnectDefaults
|
||||
setReconnectDefaults,
|
||||
print
|
||||
}
|
||||
|
@@ -14,9 +14,7 @@ if (process.platform !== 'win32') {
|
||||
})
|
||||
})
|
||||
|
||||
helper.allTests({
|
||||
allConnections: true
|
||||
}, (ip, args) => {
|
||||
helper.allTests((ip, args) => {
|
||||
describe(`using ${ip}`, () => {
|
||||
const auth = 'porkchopsandwiches'
|
||||
let client = null
|
||||
|
@@ -4,7 +4,7 @@ const assert = require('assert')
|
||||
const config = require('./lib/config')
|
||||
const connect = require('../lib/connect')
|
||||
const helper = require('./helper')
|
||||
const redis = config.redis
|
||||
const Redis = config.redis
|
||||
const intercept = require('intercept-stdout')
|
||||
const net = require('net')
|
||||
let client
|
||||
@@ -22,7 +22,7 @@ describe('connection tests', () => {
|
||||
// Besides that some functions also have to be monkey patched to be safe from errors in this case.
|
||||
// Therefore this is not officially supported!
|
||||
const socket = new net.Socket()
|
||||
client = new redis.RedisClient({
|
||||
client = new Redis({
|
||||
prefix: 'test',
|
||||
stream: socket
|
||||
})
|
||||
@@ -38,7 +38,7 @@ describe('connection tests', () => {
|
||||
describe('quit on lost connections', () => {
|
||||
it('calling quit while the connection is down should not end in reconnecting version a', (done) => {
|
||||
let called = 0
|
||||
client = redis.createClient({
|
||||
client = Redis.createClient({
|
||||
connectTimeout: 5,
|
||||
port: 9999,
|
||||
retryStrategy (options) {
|
||||
@@ -59,7 +59,7 @@ describe('connection tests', () => {
|
||||
|
||||
it('calling quit while the connection is down should not end in reconnecting version b', () => {
|
||||
let called = false
|
||||
client = redis.createClient(9999)
|
||||
client = Redis.createClient(9999)
|
||||
client.set('foo', 'bar').catch((err) => {
|
||||
assert.strictEqual(err.message, 'Stream connection ended and command aborted.')
|
||||
called = true
|
||||
@@ -72,7 +72,7 @@ describe('connection tests', () => {
|
||||
|
||||
it('calling quit while the connection is down without offline queue should end the connection right away', () => {
|
||||
let called = false
|
||||
client = redis.createClient(9999, {
|
||||
client = Redis.createClient(9999, {
|
||||
enableOfflineQueue: false
|
||||
})
|
||||
client.set('foo', 'bar').catch((err) => {
|
||||
@@ -87,7 +87,7 @@ describe('connection tests', () => {
|
||||
|
||||
it('calling quit while connected without offline queue should end the connection when all commands have finished', (done) => {
|
||||
let called = false
|
||||
client = redis.createClient({
|
||||
client = Redis.createClient({
|
||||
enableOfflineQueue: false
|
||||
})
|
||||
client.on('ready', () => {
|
||||
@@ -104,7 +104,7 @@ describe('connection tests', () => {
|
||||
})
|
||||
|
||||
it('do not quit before connected or a connection issue is detected', () => {
|
||||
client = redis.createClient()
|
||||
client = Redis.createClient()
|
||||
return Promise.all([
|
||||
client.set('foo', 'bar').then(helper.isString('OK')),
|
||||
client.quit()
|
||||
@@ -112,7 +112,7 @@ describe('connection tests', () => {
|
||||
})
|
||||
|
||||
it('quit "succeeds" even if the client connection is closed while doing so', () => {
|
||||
client = redis.createClient()
|
||||
client = Redis.createClient()
|
||||
return client.set('foo', 'bar').then((res) => {
|
||||
assert.strictEqual(res, 'OK')
|
||||
const promise = client.quit().then((res) => {
|
||||
@@ -124,7 +124,7 @@ describe('connection tests', () => {
|
||||
})
|
||||
|
||||
it('quit right away if connection drops while quit command is on the fly', (done) => {
|
||||
client = redis.createClient()
|
||||
client = Redis.createClient()
|
||||
client.once('ready', () => {
|
||||
client.set('foo', 'bar').catch(helper.isError())
|
||||
client.quit().then(() => done())
|
||||
@@ -138,7 +138,7 @@ describe('connection tests', () => {
|
||||
describe('on lost connection', () => {
|
||||
it('end connection while retry is still ongoing', (done) => {
|
||||
const connectTimeout = 1000 // in ms
|
||||
client = redis.createClient({
|
||||
client = Redis.createClient({
|
||||
connectTimeout
|
||||
})
|
||||
|
||||
@@ -160,7 +160,7 @@ describe('connection tests', () => {
|
||||
family: ip,
|
||||
retryStrategy () {}
|
||||
}
|
||||
client = redis.createClient(options)
|
||||
client = Redis.createClient(options)
|
||||
assert.strictEqual(client._connectionOptions.family, ip === 'IPv6' ? 6 : 4)
|
||||
assert.strictEqual(Object.keys(options).length, 4)
|
||||
const end = helper.callFuncAfter(done, 2)
|
||||
@@ -172,7 +172,7 @@ describe('connection tests', () => {
|
||||
})
|
||||
|
||||
it('retryStrategy used to reconnect with individual error', (done) => {
|
||||
client = redis.createClient({
|
||||
client = Redis.createClient({
|
||||
retryStrategy (options) {
|
||||
if (options.totalRetryTime > 150) {
|
||||
client.set('foo', 'bar').then(assert, (err) => {
|
||||
@@ -191,7 +191,7 @@ describe('connection tests', () => {
|
||||
})
|
||||
|
||||
it('retryStrategy used to reconnect', (done) => {
|
||||
client = redis.createClient({
|
||||
client = Redis.createClient({
|
||||
retryStrategy (options) {
|
||||
if (options.totalRetryTime > 150) {
|
||||
client.set('foo', 'bar').catch((err) => {
|
||||
@@ -213,17 +213,17 @@ describe('connection tests', () => {
|
||||
const unhookIntercept = intercept(() => {
|
||||
return ''
|
||||
})
|
||||
redis.debugMode = true
|
||||
client = redis.createClient({
|
||||
Redis.debugMode = true
|
||||
client = Redis.createClient({
|
||||
retryStrategy (options) {
|
||||
client.set('foo', 'bar').catch((err) => {
|
||||
assert.strictEqual(err.code, 'NR_CLOSED')
|
||||
assert.strictEqual(err.message, 'Stream connection ended and command aborted.')
|
||||
unhookIntercept()
|
||||
redis.debugMode = false
|
||||
Redis.debugMode = false
|
||||
done()
|
||||
})
|
||||
assert(redis.debugMode)
|
||||
assert(Redis.debugMode)
|
||||
return null
|
||||
}
|
||||
})
|
||||
@@ -237,7 +237,7 @@ describe('connection tests', () => {
|
||||
// TODO: Fix this test
|
||||
it.skip('emit an error after the socket timeout exceeded the connectTimeout time', (done) => {
|
||||
const connectTimeout = 500 // in ms
|
||||
client = redis.createClient({
|
||||
client = Redis.createClient({
|
||||
// Auto detect ipv4 and use non routeable ip to trigger the timeout
|
||||
host: '10.255.255.1',
|
||||
connectTimeout,
|
||||
@@ -271,7 +271,7 @@ describe('connection tests', () => {
|
||||
})
|
||||
|
||||
it('use the system socket timeout if the connectTimeout has not been provided', (done) => {
|
||||
client = redis.createClient({
|
||||
client = Redis.createClient({
|
||||
host: '2001:db8::ff00:42:8329' // auto detect ip v6
|
||||
})
|
||||
assert.strictEqual(client.address, '2001:db8::ff00:42:8329:6379')
|
||||
@@ -284,7 +284,7 @@ describe('connection tests', () => {
|
||||
})
|
||||
|
||||
it('clears the socket timeout after a connection has been established', (done) => {
|
||||
client = redis.createClient({
|
||||
client = Redis.createClient({
|
||||
connectTimeout: 1000
|
||||
})
|
||||
process.nextTick(assert.strictEqual, client._stream._idleTimeout, 1000)
|
||||
@@ -296,7 +296,7 @@ describe('connection tests', () => {
|
||||
})
|
||||
|
||||
it('connect with host and port provided in the options object', (done) => {
|
||||
client = redis.createClient({
|
||||
client = Redis.createClient({
|
||||
host: 'localhost',
|
||||
port: '6379',
|
||||
connectTimeout: 1000
|
||||
@@ -309,7 +309,7 @@ describe('connection tests', () => {
|
||||
if (process.platform === 'win32') {
|
||||
this.skip()
|
||||
}
|
||||
client = redis.createClient({
|
||||
client = Redis.createClient({
|
||||
path: '/tmp/redis.sock',
|
||||
connectTimeout: 1000
|
||||
})
|
||||
@@ -317,7 +317,7 @@ describe('connection tests', () => {
|
||||
})
|
||||
|
||||
it('connects correctly with args', (done) => {
|
||||
client = redis.createClient.apply(null, args)
|
||||
client = Redis.createClient.apply(null, args)
|
||||
client.on('error', done)
|
||||
|
||||
client.once('ready', () => {
|
||||
@@ -327,7 +327,7 @@ describe('connection tests', () => {
|
||||
})
|
||||
|
||||
it('connects correctly with default values', (done) => {
|
||||
client = redis.createClient()
|
||||
client = Redis.createClient()
|
||||
client.on('error', done)
|
||||
|
||||
client.once('ready', () => {
|
||||
@@ -337,7 +337,7 @@ describe('connection tests', () => {
|
||||
})
|
||||
|
||||
it('connects with a port only', (done) => {
|
||||
client = redis.createClient(6379)
|
||||
client = Redis.createClient(6379)
|
||||
assert.strictEqual(client._connectionOptions.family, 4)
|
||||
client.on('error', done)
|
||||
|
||||
@@ -348,7 +348,7 @@ describe('connection tests', () => {
|
||||
})
|
||||
|
||||
it('connects correctly to localhost', (done) => {
|
||||
client = redis.createClient(null, null)
|
||||
client = Redis.createClient(null, null)
|
||||
client.on('error', done)
|
||||
|
||||
client.once('ready', () => {
|
||||
@@ -358,7 +358,7 @@ describe('connection tests', () => {
|
||||
})
|
||||
|
||||
it('connects correctly to the provided host with the port set to null', (done) => {
|
||||
client = redis.createClient(null, 'localhost')
|
||||
client = Redis.createClient(null, 'localhost')
|
||||
client.on('error', done)
|
||||
assert.strictEqual(client.address, 'localhost:6379')
|
||||
|
||||
@@ -371,7 +371,7 @@ describe('connection tests', () => {
|
||||
})
|
||||
|
||||
it('connects correctly to localhost and no ready check', (done) => {
|
||||
client = redis.createClient(undefined, undefined, {
|
||||
client = Redis.createClient(undefined, undefined, {
|
||||
noReadyCheck: true
|
||||
})
|
||||
client.on('error', done)
|
||||
@@ -385,7 +385,7 @@ describe('connection tests', () => {
|
||||
})
|
||||
|
||||
it('connects correctly to the provided host with the port set to undefined', (done) => {
|
||||
client = redis.createClient(undefined, 'localhost', {
|
||||
client = Redis.createClient(undefined, 'localhost', {
|
||||
noReadyCheck: true
|
||||
})
|
||||
client.on('error', done)
|
||||
@@ -400,7 +400,7 @@ describe('connection tests', () => {
|
||||
})
|
||||
|
||||
it('connects correctly even if the info command is not present on the redis server', (done) => {
|
||||
client = redis.createClient.apply(null, args)
|
||||
client = Redis.createClient.apply(null, args)
|
||||
const end = helper.callFuncAfter(done, 2)
|
||||
client.info = function () {
|
||||
// Mock the result
|
||||
@@ -415,13 +415,13 @@ describe('connection tests', () => {
|
||||
|
||||
if (ip === 'IPv4') {
|
||||
it('allows connecting with the redis url to the default host and port, select db 3 and warn about duplicate db option', (done) => {
|
||||
client = redis.createClient('redis:///3?db=3')
|
||||
client = Redis.createClient('redis:///3?db=3')
|
||||
assert.strictEqual(client.selectedDb, '3')
|
||||
client.on('ready', done)
|
||||
})
|
||||
|
||||
it('allows connecting with the redis url and the default port and auth provided even though it is not required', (done) => {
|
||||
client = redis.createClient(`redis://:porkchopsandwiches@${config.HOST[ip]}/`)
|
||||
client = Redis.createClient(`redis://:porkchopsandwiches@${config.HOST[ip]}/`)
|
||||
const end = helper.callFuncAfter(done, 2)
|
||||
client.on('warning', (msg) => {
|
||||
assert.strictEqual(msg, 'Warning: Redis server does not require a password, but a password was supplied.')
|
||||
@@ -431,7 +431,7 @@ describe('connection tests', () => {
|
||||
})
|
||||
|
||||
it('allows connecting with the redis url as first parameter and the options as second parameter', (done) => {
|
||||
client = redis.createClient('//127.0.0.1', {
|
||||
client = Redis.createClient('//127.0.0.1', {
|
||||
connectTimeout: 1000
|
||||
})
|
||||
assert.strictEqual(client._options.connectTimeout, 1000)
|
||||
@@ -439,7 +439,7 @@ describe('connection tests', () => {
|
||||
})
|
||||
|
||||
it('allows connecting with the redis url in the options object and works with protocols other than the redis protocol (e.g. http)', (done) => {
|
||||
client = redis.createClient({
|
||||
client = Redis.createClient({
|
||||
url: `http://foo:porkchopsandwiches@${config.HOST[ip]}/3`
|
||||
})
|
||||
assert.strictEqual(client._options.password, 'porkchopsandwiches')
|
||||
@@ -453,13 +453,13 @@ describe('connection tests', () => {
|
||||
const options = {
|
||||
detectBuffers: false
|
||||
}
|
||||
client = redis.createClient(`redis://${config.HOST[ip]}:${config.PORT}`, options)
|
||||
client = Redis.createClient(`redis://${config.HOST[ip]}:${config.PORT}`, options)
|
||||
assert.strictEqual(Object.keys(options).length, 1)
|
||||
client.on('ready', done)
|
||||
})
|
||||
|
||||
it('allows connecting with the redis url and no auth and options as third parameter', (done) => {
|
||||
client = redis.createClient(`redis://${config.HOST[ip]}:${config.PORT}`, null, {
|
||||
client = Redis.createClient(`redis://${config.HOST[ip]}:${config.PORT}`, null, {
|
||||
detectBuffers: false
|
||||
})
|
||||
client.on('ready', done)
|
||||
@@ -467,7 +467,7 @@ describe('connection tests', () => {
|
||||
}
|
||||
|
||||
it('redis still loading <= 500', (done) => {
|
||||
client = redis.createClient.apply(null, args)
|
||||
client = Redis.createClient.apply(null, args)
|
||||
const tmp = client.info.bind(client)
|
||||
const end = helper.callFuncAfter(done, 3)
|
||||
let delayed = false
|
||||
@@ -496,7 +496,7 @@ describe('connection tests', () => {
|
||||
})
|
||||
|
||||
it('redis still loading > 1000ms', (done) => {
|
||||
client = redis.createClient.apply(null, args)
|
||||
client = Redis.createClient.apply(null, args)
|
||||
const tmp = client.info.bind(client)
|
||||
const end = helper.callFuncAfter(done, 3)
|
||||
let delayed = false
|
||||
|
@@ -2,9 +2,34 @@
|
||||
|
||||
const assert = require('assert')
|
||||
const Queue = require('denque')
|
||||
const intercept = require('intercept-stdout')
|
||||
const utils = require('../lib/utils')
|
||||
|
||||
describe('utils.js', () => {
|
||||
describe('print helper', function () {
|
||||
it('callback with reply', function () {
|
||||
var text = ''
|
||||
const unhookIntercept = intercept(function (data) {
|
||||
text += data
|
||||
return ''
|
||||
})
|
||||
utils.print(null, 'abc')
|
||||
unhookIntercept()
|
||||
assert.strictEqual(text, 'Reply: abc\n')
|
||||
})
|
||||
|
||||
it('callback with error', function () {
|
||||
var text = ''
|
||||
const unhookIntercept = intercept(function (data) {
|
||||
text += data
|
||||
return ''
|
||||
})
|
||||
utils.print(new Error('Wonderful exception'))
|
||||
unhookIntercept()
|
||||
assert.strictEqual(text, 'Error: Wonderful exception\n')
|
||||
})
|
||||
})
|
||||
|
||||
describe('clone', () => {
|
||||
it('ignore the object prototype and clone a nested array / object', () => {
|
||||
const obj = {
|
||||
|
Reference in New Issue
Block a user