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

chore: use standard

This commit is contained in:
Ruben Bridgewater
2017-05-06 07:06:52 +02:00
parent 5d29f541e9
commit f1a7bcd735
106 changed files with 10706 additions and 10978 deletions

View File

@@ -1,95 +1,91 @@
'use strict'; 'use strict'
var fs = require('fs'); // `node diffMultiBenchOutput.js beforeBench.txt afterBench.txt`
var metrics = require('metrics');
// `node diffMultiBenchOutput.js beforeBench.txt afterBench.txt` var fs = require('fs')
var file1 = process.argv[2]; var file1 = process.argv[2]
var file2 = process.argv[3]; var 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; var 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.')
return; process.exit(1)
} }
var beforeLines = fs.readFileSync(file1, 'utf8').split('\n'); var beforeLines = fs.readFileSync(file1, 'utf8').split('\n')
var afterLines = fs.readFileSync(file2, 'utf8').split('\n'); var afterLines = fs.readFileSync(file2, 'utf8').split('\n')
var totalOps = new metrics.Histogram.createUniformHistogram();
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)')
function isWhitespace (s) { function isWhitespace (s) {
return !!s.trim(); return !!s.trim()
} }
function pad (input, len, chr, right) { function pad (input, len, chr, right) {
var str = input.toString(); var str = input.toString()
chr = chr || ' '; chr = chr || ' '
if (right) { if (right) {
while (str.length < len) { while (str.length < len) {
str += chr; str += chr
}
} else {
while (str.length < len) {
str = chr + str;
}
} }
return str; } else {
while (str.length < len) {
str = chr + 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(' '); var line = words.join(' ')
return line.substr(0, line.indexOf(',')); return line.substr(0, line.indexOf(','))
} }
beforeLines.forEach(function (b, i) { beforeLines.forEach(function (b, i) {
var a = afterLines[i]; var 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); var bWords = b.split(' ').filter(isWhitespace)
var aWords = a.split(' ').filter(isWhitespace); var aWords = a.split(' ').filter(isWhitespace)
var ops = [bWords, aWords].map(function (words) { var ops = [bWords, aWords].map(function (words) {
// console.log(words); // console.log(words);
return words.slice(-2, -1) | 0; return words.slice(-2, -1) | 0
}).filter(function (num) { }).filter(function (num) {
var isNaN = !num && num !== 0; var isNaN = !num && num !== 0
return !isNaN; return !isNaN
}); })
if (ops.length !== 2) { if (ops.length !== 2) {
return; return
} }
var delta = ops[1] - ops[0]; var delta = ops[1] - ops[0]
var pct = +((delta / ops[0]) * 100); var 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)
totalOps.update(delta); delta = humanizeDiff(delta)
delta = humanizeDiff(delta); var smallDelta = pct < 3 && pct > -3
var 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' : ''
var 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) +
var 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); })
});
console.log('Mean difference in ops/sec:', humanizeDiff(totalOps.mean(), '', 1));

View File

@@ -1,295 +1,298 @@
'use strict'; 'use strict'
var path = require('path'); var Buffer = require('safe-buffer').Buffer
var RedisProcess = require('../test/lib/redis-process'); var path = require('path')
var rp; var RedisProcess = require('../test/lib/redis-process')
var clientNr = 0; var rp
var redis = require('../index'); var clientNr = 0
var totalTime = 0; var redis = require('../index')
var metrics = require('metrics'); var totalTime = 0
var tests = []; var metrics = require('metrics')
var tests = []
// var bluebird = require('bluebird'); // var bluebird = require('bluebird');
// bluebird.promisifyAll(redis.RedisClient.prototype); // bluebird.promisifyAll(redis.RedisClient.prototype);
// bluebird.promisifyAll(redis.Multi.prototype); // bluebird.promisifyAll(redis.Multi.prototype);
function returnArg (name, def) { function returnArg (name, def) {
var matches = process.argv.filter(function (entry) { var matches = process.argv.filter(function (entry) {
return entry.indexOf(name + '=') === 0; return entry.indexOf(name + '=') === 0
}); })
if (matches.length) { if (matches.length) {
return matches[0].substr(name.length + 1); return matches[0].substr(name.length + 1)
} }
return def; return def
} }
var numClients = returnArg('clients', 1); var numClients = returnArg('clients', 1)
var runTime = returnArg('time', 2500); // ms var runTime = returnArg('time', 2500) // ms
var pipeline = returnArg('pipeline', 1); // number of concurrent commands var pipeline = returnArg('pipeline', 1) // number of concurrent commands
var versionsLogged = false; var versionsLogged = false
var clientOptions = { var clientOptions = {
path: returnArg('socket') // '/tmp/redis.sock' path: returnArg('socket') // '/tmp/redis.sock'
}; }
var smallStr, largeStr, smallBuf, largeBuf, veryLargeStr, veryLargeBuf, mgetArray; var smallStr, largeStr, smallBuf, largeBuf, veryLargeStr, veryLargeBuf, mgetArray
function lpad (input, len, chr) { function lpad (input, len, chr) {
var str = input.toString(); var str = input.toString()
chr = chr || ' '; chr = chr || ' '
while (str.length < len) { while (str.length < len) {
str = chr + str; str = chr + str
} }
return str; return str
} }
metrics.Histogram.prototype.printLine = function () { metrics.Histogram.prototype.printLine = function () {
var obj = this.printObj(); var obj = this.printObj()
return lpad((obj.mean / 1e6).toFixed(2), 6) + '/' + lpad((obj.max / 1e6).toFixed(2), 6); return lpad((obj.mean / 1e6).toFixed(2), 6) + '/' + lpad((obj.max / 1e6).toFixed(2), 6)
}; }
function Test (args) { function Test (args) {
this.args = args; this.args = args
this.args.pipeline = +pipeline; this.args.pipeline = +pipeline
this.callback = null; this.callback = null
this.clients = []; this.clients = []
this.clientsReady = 0; this.clientsReady = 0
this.commandsSent = 0; this.commandsSent = 0
this.commandsCompleted = 0; this.commandsCompleted = 0
this.maxPipeline = +pipeline; this.maxPipeline = +pipeline
this.batchPipeline = this.args.batch || 0; this.batchPipeline = this.args.batch || 0
this.clientOptions = args.clientOptions || {}; this.clientOptions = args.clientOptions || {}
this.clientOptions.connectTimeout = 1000; this.clientOptions.connectTimeout = 1000
if (clientOptions.path) { if (clientOptions.path) {
this.clientOptions.path = clientOptions.path; this.clientOptions.path = clientOptions.path
} }
this.connectLatency = new metrics.Histogram(); this.connectLatency = new metrics.Histogram()
this.readyLatency = new metrics.Histogram(); this.readyLatency = new metrics.Histogram()
this.commandLatency = new metrics.Histogram(); this.commandLatency = new metrics.Histogram()
} }
Test.prototype.run = function (callback) { Test.prototype.run = function (callback) {
var i; var i
this.callback = callback; this.callback = callback
for (i = 0; i < numClients ; i++) { for (i = 0; i < numClients; i++) {
this.newClient(i); this.newClient(i)
} }
};
Test.prototype.newClient = function (id) {
var self = this, newClient;
newClient = redis.createClient(this.clientOptions);
newClient.createTime = Date.now();
newClient.on('connect', function () {
self.connectLatency.update(Date.now() - newClient.createTime);
});
newClient.on('ready', function () {
if (!versionsLogged) {
console.log(
'clients: ' + numClients +
', NodeJS: ' + process.versions.node +
', Redis: ' + newClient.serverInfo.redis_version +
', connected by: ' + (clientOptions.path ? 'socket' : 'tcp')
);
versionsLogged = true;
}
self.readyLatency.update(Date.now() - newClient.createTime);
self.clientsReady++;
if (self.clientsReady === self.clients.length) {
self.onClientsReady();
}
});
// If no redis server is running, start one
newClient.on('error', function (err) {
if (err.code === 'CONNECTION_BROKEN') {
throw err;
}
if (rp) {
return;
}
rp = true;
var conf = '../test/conf/redis.conf';
RedisProcess.start(function (err, Rp) {
if (err) {
throw err;
}
rp = Rp;
}, path.resolve(__dirname, conf));
});
self.clients[id] = newClient;
};
Test.prototype.onClientsReady = function () {
process.stdout.write(lpad(this.args.descr, 13) + ', ' + (this.args.batch ? lpad('batch ' + this.args.batch, 9) : lpad(this.args.pipeline, 9)) + '/' + this.clientsReady + ' ');
this.testStart = Date.now();
this.fillPipeline();
};
Test.prototype.fillPipeline = function () {
var pipeline = this.commandsSent - this.commandsCompleted;
if (this.testStart < Date.now() - runTime) {
if (this.ended) {
return;
}
this.ended = true;
this.printStats();
this.stopClients();
return;
}
if (this.batchPipeline) {
this.batch();
} else {
while (pipeline < this.maxPipeline) {
this.commandsSent++;
pipeline++;
this.sendNext();
}
}
};
Test.prototype.batch = function () {
var self = this,
curClient = clientNr++ % this.clients.length,
start = process.hrtime(),
i = 0,
batch = this.clients[curClient].batch();
while (i++ < this.batchPipeline) {
this.commandsSent++;
batch[this.args.command](this.args.args);
}
batch.exec(function (err, res) {
if (err) {
throw err;
}
self.commandsCompleted += res.length;
self.commandLatency.update(process.hrtime(start)[1]);
self.fillPipeline();
});
};
Test.prototype.stopClients = function () {
var self = this;
this.clients.forEach(function (client, pos) {
if (pos === self.clients.length - 1) {
client.quit(function (err, res) {
self.callback();
});
} else {
client.quit();
}
});
};
Test.prototype.sendNext = function () {
var self = this,
curClient = this.commandsSent % this.clients.length,
start = process.hrtime();
this.clients[curClient][this.args.command](this.args.args, function (err, res) {
if (err) {
throw err;
}
self.commandsCompleted++;
self.commandLatency.update(process.hrtime(start)[1]);
self.fillPipeline();
});
};
Test.prototype.printStats = function () {
var duration = Date.now() - this.testStart;
totalTime += duration;
console.log('avg/max: ' + this.commandLatency.printLine() + lpad(duration, 5) + 'ms total, ' +
lpad(Math.round(this.commandsCompleted / (duration / 1000)), 7) + ' ops/sec');
};
smallStr = '1234';
smallBuf = new Buffer(smallStr);
largeStr = (new Array(4096 + 1).join('-'));
largeBuf = new Buffer(largeStr);
veryLargeStr = (new Array((4 * 1024 * 1024) + 1).join('-'));
veryLargeBuf = new Buffer(veryLargeStr);
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: [], 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], 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], 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'], batch: 50}));
tests.push(new Test({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], 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], 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'], batch: 50}));
tests.push(new Test({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'], batch: 50}));
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: '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 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: '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 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: '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 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, batch: 20}));
tests.push(new Test({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 () {
var test = tests.shift();
if (test) {
test.run(function () {
next();
});
} else if (rp) {
// Stop the redis process if started by the benchmark
rp.stop(function () {
rp = undefined;
next();
});
} else {
console.log('End of tests. Total time elapsed:', totalTime, 'ms');
process.exit(0);
}
} }
next(); Test.prototype.newClient = function (id) {
var self = this
var newClient
newClient = redis.createClient(this.clientOptions)
newClient.createTime = Date.now()
newClient.on('connect', function () {
self.connectLatency.update(Date.now() - newClient.createTime)
})
newClient.on('ready', function () {
if (!versionsLogged) {
console.log(
'clients: ' + numClients +
', NodeJS: ' + process.versions.node +
', Redis: ' + newClient.serverInfo.redis_version +
', connected by: ' + (clientOptions.path ? 'socket' : 'tcp')
)
versionsLogged = true
}
self.readyLatency.update(Date.now() - newClient.createTime)
self.clientsReady++
if (self.clientsReady === self.clients.length) {
self.onClientsReady()
}
})
// If no redis server is running, start one
newClient.on('error', function (err) {
if (err.code === 'CONNECTION_BROKEN') {
throw err
}
if (rp) {
return
}
rp = true
var conf = '../test/conf/redis.conf'
RedisProcess.start(function (err, Rp) {
if (err) {
throw err
}
rp = Rp
}, path.resolve(__dirname, conf))
})
self.clients[id] = newClient
}
Test.prototype.onClientsReady = function () {
process.stdout.write(lpad(this.args.descr, 13) + ', ' + (this.args.batch ? lpad('batch ' + this.args.batch, 9) : lpad(this.args.pipeline, 9)) + '/' + this.clientsReady + ' ')
this.testStart = Date.now()
this.fillPipeline()
}
Test.prototype.fillPipeline = function () {
var pipeline = this.commandsSent - this.commandsCompleted
if (this.testStart < Date.now() - runTime) {
if (this.ended) {
return
}
this.ended = true
this.printStats()
this.stopClients()
return
}
if (this.batchPipeline) {
this.batch()
} else {
while (pipeline < this.maxPipeline) {
this.commandsSent++
pipeline++
this.sendNext()
}
}
}
Test.prototype.batch = function () {
var self = this
var curClient = clientNr++ % this.clients.length
var start = process.hrtime()
var i = 0
var batch = this.clients[curClient].batch()
while (i++ < this.batchPipeline) {
this.commandsSent++
batch[this.args.command](this.args.args)
}
batch.exec(function (err, res) {
if (err) {
throw err
}
self.commandsCompleted += res.length
self.commandLatency.update(process.hrtime(start)[1])
self.fillPipeline()
})
}
Test.prototype.stopClients = function () {
var self = this
this.clients.forEach(function (client, pos) {
if (pos === self.clients.length - 1) {
client.quit(function (err, res) {
if (err) throw err
self.callback()
})
} else {
client.quit()
}
})
}
Test.prototype.sendNext = function () {
var self = this
var curClient = this.commandsSent % this.clients.length
var start = process.hrtime()
this.clients[curClient][this.args.command](this.args.args, function (err, res) {
if (err) {
throw err
}
self.commandsCompleted++
self.commandLatency.update(process.hrtime(start)[1])
self.fillPipeline()
})
}
Test.prototype.printStats = function () {
var duration = Date.now() - this.testStart
totalTime += duration
console.log('avg/max: ' + this.commandLatency.printLine() + lpad(duration, 5) + 'ms total, ' +
lpad(Math.round(this.commandsCompleted / (duration / 1000)), 7) + ' ops/sec')
}
smallStr = '1234'
smallBuf = Buffer.from(smallStr)
largeStr = (new Array(4096 + 1).join('-'))
largeBuf = Buffer.from(largeStr)
veryLargeStr = (new Array((4 * 1024 * 1024) + 1).join('-'))
veryLargeBuf = Buffer.from(veryLargeStr)
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: [], 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], 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], 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'], batch: 50}))
tests.push(new Test({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], 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], 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'], batch: 50}))
tests.push(new Test({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'], batch: 50}))
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: '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 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: '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 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: '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 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, batch: 20}))
tests.push(new Test({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 () {
var test = tests.shift()
if (test) {
test.run(function () {
next()
})
} else if (rp) {
// Stop the redis process if started by the benchmark
rp.stop(function () {
rp = undefined
next()
})
} else {
console.log('End of tests. Total time elapsed:', totalTime, 'ms')
process.exit(0)
}
}
next()

View File

@@ -1,7 +1,7 @@
'use strict'; 'use strict'
var redis = require('redis'); var redis = require('redis')
// The client stashes the password and will reauthenticate on every connect. // The client stashes the password and will re-authenticate on every connect.
redis.createClient({ redis.createClient({
password: 'somepass' password: 'some pass'
}); })

View File

@@ -1,14 +1,14 @@
'use strict'; 'use strict'
var redis = require('../index'); var redis = require('../index')
var client = redis.createClient(); var client = redis.createClient()
client.eval('return 100.5', 0, function (err, res) { client.eval('return 100.5', 0, function (err, res) {
console.dir(err); console.dir(err)
console.dir(res); console.dir(res)
}); })
client.eval([ 'return 100.5', 0 ], function (err, res) { client.eval([ 'return 100.5', 0 ], function (err, res) {
console.dir(err); console.dir(err)
console.dir(res); console.dir(res)
}); })

View File

@@ -1,26 +1,27 @@
'use strict'; 'use strict'
var redis = require('redis'); var redis = require('redis')
var client = redis.createClient(); var client = redis.createClient()
// Extend the RedisClient prototype to add a custom method // Extend the RedisClient prototype to add a custom method
// This one converts the results from 'INFO' into a JavaScript Object // This one converts the results from 'INFO' into a JavaScript Object
redis.RedisClient.prototype.parseInfo = function (callback) { redis.RedisClient.prototype.parseInfo = function (callback) {
this.info(function (err, res) { this.info(function (err, res) {
var lines = res.toString().split('\r\n').sort(); if (err) throw err
var obj = {}; var lines = res.toString().split('\r\n').sort()
lines.forEach(function (line) { var obj = {}
var parts = line.split(':'); lines.forEach(function (line) {
if (parts[1]) { var parts = line.split(':')
obj[parts[0]] = parts[1]; if (parts[1]) {
} obj[parts[0]] = parts[1]
}); }
callback(obj); })
}); callback(obj)
}; })
}
client.parseInfo(function (info) { client.parseInfo(function (info) {
console.dir(info); console.dir(info)
client.quit(); client.quit()
}); })

View File

@@ -1,14 +1,14 @@
'use strict'; 'use strict'
// Read a file from disk, store it in Redis, then read it back from Redis. // Read a file from disk, store it in Redis, then read it back from Redis.
var redis = require('redis'); var redis = require('redis')
var client = redis.createClient({ var client = redis.createClient({
returnBuffers: true returnBuffers: true
}); })
var fs = require('fs'); var fs = require('fs')
var assert = require('assert'); var assert = require('assert')
var filename = 'grumpyCat.jpg'; var filename = 'grumpyCat.jpg'
// Get the file I use for testing like this: // Get the file I use for testing like this:
// curl http://media4.popsugar-assets.com/files/2014/08/08/878/n/1922507/caef16ec354ca23b_thumb_temp_cover_file32304521407524949.xxxlarge/i/Funny-Cat-GIFs.jpg -o grumpyCat.jpg // curl http://media4.popsugar-assets.com/files/2014/08/08/878/n/1922507/caef16ec354ca23b_thumb_temp_cover_file32304521407524949.xxxlarge/i/Funny-Cat-GIFs.jpg -o grumpyCat.jpg
@@ -16,23 +16,23 @@ var filename = 'grumpyCat.jpg';
// Read a file from fs, store it in Redis, get it back from Redis, write it back to fs. // Read a file from fs, store it in Redis, get it back from Redis, write it back to fs.
fs.readFile(filename, function (err, data) { fs.readFile(filename, function (err, data) {
if (err) throw err; if (err) throw err
console.log('Read ' + data.length + ' bytes from filesystem.'); console.log('Read ' + data.length + ' bytes from filesystem.')
client.set(filename, data, console.log); // set entire file client.set(filename, data, console.log) // set entire file
client.get(filename, function (err, reply) { // get entire file client.get(filename, function (err, reply) { // get entire file
if (err) {
console.log('Get error: ' + err)
} else {
assert.strictEqual(data.inspect(), reply.inspect())
fs.writeFile('duplicate_' + filename, reply, function (err) {
if (err) { if (err) {
console.log('Get error: ' + err); console.log('Error on write: ' + err)
} else { } else {
assert.strictEqual(data.inspect(), reply.inspect()); console.log('File written.')
fs.writeFile('duplicate_' + filename, reply, function (err) {
if (err) {
console.log('Error on write: ' + err);
} else {
console.log('File written.');
}
client.end();
});
} }
}); client.end()
}); })
}
})
})

View File

@@ -1,7 +1,8 @@
'use strict'; 'use strict'
var client = require('redis').createClient(); var client = require('redis').createClient()
client.mget(['sessions started', 'sessions started', 'foo'], function (err, res) { client.mget(['sessions started', 'sessions started', 'foo'], function (err, res) {
console.dir(res); if (err) throw err
}); console.dir(res)
})

View File

@@ -1,12 +1,13 @@
'use strict'; 'use strict'
var client = require('../index').createClient(); var client = require('../index').createClient()
var util = require('util'); var util = require('util')
client.monitor(function (err, res) { client.monitor(function (err, res) {
console.log('Entering monitoring mode.'); if (err) throw err
}); console.log('Entering monitoring mode.')
})
client.on('monitor', function (time, args) { client.on('monitor', function (time, args) {
console.log(time + ': ' + util.inspect(args)); console.log(time + ': ' + util.inspect(args))
}); })

View File

@@ -1,15 +1,15 @@
'use strict'; 'use strict'
var redis = require('redis'); var redis = require('redis')
var client = redis.createClient(); var client = redis.createClient()
var setSize = 20; var setSize = 20
client.sadd('bigset', 'a member'); client.sadd('bigset', 'a member')
client.sadd('bigset', 'another member'); client.sadd('bigset', 'another member')
while (setSize > 0) { while (setSize > 0) {
client.sadd('bigset', 'member ' + setSize); client.sadd('bigset', 'member ' + setSize)
setSize -= 1; setSize -= 1
} }
// multi chain with an individual callback // multi chain with an individual callback
@@ -17,33 +17,37 @@ client.multi()
.scard('bigset') .scard('bigset')
.smembers('bigset') .smembers('bigset')
.keys('*', function (err, replies) { .keys('*', function (err, replies) {
client.mget(replies, console.log); if (err) throw err
client.mget(replies, console.log)
}) })
.dbsize() .dbsize()
.exec(function (err, replies) { .exec(function (err, replies) {
console.log('MULTI got ' + replies.length + ' replies'); if (err) throw err
replies.forEach(function (reply, index) { console.log('MULTI got ' + replies.length + ' replies')
console.log('Reply ' + index + ': ' + reply.toString()); replies.forEach(function (reply, index) {
}); console.log('Reply ' + index + ': ' + reply.toString())
}); })
})
client.mset('incr thing', 100, 'incr other thing', 1, console.log); client.mset('incr thing', 100, 'incr other thing', 1, console.log)
// start a separate multi command queue // start a separate multi command queue
var multi = client.multi(); var multi = client.multi()
multi.incr('incr thing', console.log); multi.incr('incr thing', console.log)
multi.incr('incr other thing', console.log); multi.incr('incr other thing', console.log)
// runs immediately // runs immediately
client.get('incr thing', console.log); // 100 client.get('incr thing', console.log) // 100
// drains multi queue and runs atomically // drains multi queue and runs atomically
multi.exec(function (err, replies) { multi.exec(function (err, replies) {
console.log(replies); // 101, 2 if (err) throw err
}); console.log(replies) // 101, 2
})
// you can re-run the same transaction if you like // you can re-run the same transaction if you like
multi.exec(function (err, replies) { multi.exec(function (err, replies) {
console.log(replies); // 102, 3 if (err) throw err
client.quit(); console.log(replies) // 102, 3
}); client.quit()
})

View File

@@ -1,31 +1,34 @@
'use strict'; 'use strict'
var redis = require('redis'); var redis = require('redis')
var client = redis.createClient(); var client = redis.createClient()
// start a separate command queue for multi // start a separate command queue for multi
var multi = client.multi(); var multi = client.multi()
multi.incr('incr thing', console.log); multi.incr('incr thing', console.log)
multi.incr('incr other thing', console.log); multi.incr('incr other thing', console.log)
// runs immediately // runs immediately
client.mset('incr thing', 100, 'incr other thing', 1, console.log); client.mset('incr thing', 100, 'incr other thing', 1, console.log)
// drains multi queue and runs atomically // drains multi queue and runs atomically
multi.exec(function (err, replies) { multi.exec(function (err, replies) {
console.log(replies); // 101, 2 if (err) throw err
}); console.log(replies) // 101, 2
})
// you can re-run the same transaction if you like // you can re-run the same transaction if you like
multi.exec(function (err, replies) { multi.exec(function (err, replies) {
console.log(replies); // 102, 3 if (err) throw err
client.quit(); console.log(replies) // 102, 3
}); client.quit()
})
client.multi([ client.multi([
['mget', 'multifoo', 'multibar', console.log], ['mget', 'multifoo', 'multibar', console.log],
['incr', 'multifoo'], ['incr', 'multifoo'],
['incr', 'multibar'] ['incr', 'multibar']
]).exec(function (err, replies) { ]).exec(function (err, replies) {
console.log(replies.toString()); if (err) throw err
}); console.log(replies.toString())
})

View File

@@ -1,33 +1,33 @@
'use strict'; 'use strict'
var redis = require('redis'); var redis = require('redis')
var client1 = redis.createClient(); var client1 = redis.createClient()
var client2 = redis.createClient(); var client2 = redis.createClient()
var client3 = redis.createClient(); var client3 = redis.createClient()
var client4 = redis.createClient(); var client4 = redis.createClient()
var msgCount = 0; var msgCount = 0
client1.on('psubscribe', function (pattern, count) { client1.on('psubscribe', function (pattern, count) {
console.log('client1 psubscribed to ' + pattern + ', ' + count + ' total subscriptions'); console.log('client1 psubscribed to ' + pattern + ', ' + count + ' total subscriptions')
client2.publish('channeltwo', 'Me!'); client2.publish('channeltwo', 'Me!')
client3.publish('channelthree', 'Me too!'); client3.publish('channelthree', 'Me too!')
client4.publish('channelfour', 'And me too!'); client4.publish('channelfour', 'And me too!')
}); })
client1.on('punsubscribe', function (pattern, count) { client1.on('punsubscribe', function (pattern, count) {
console.log('client1 punsubscribed from ' + pattern + ', ' + count + ' total subscriptions'); console.log('client1 punsubscribed from ' + pattern + ', ' + count + ' total subscriptions')
client4.end(); client4.end()
client3.end(); client3.end()
client2.end(); client2.end()
client1.end(); client1.end()
}); })
client1.on('pmessage', function (pattern, channel, message) { client1.on('pmessage', function (pattern, channel, message) {
console.log('(' + pattern + ') client1 received message on ' + channel + ': ' + message); console.log('(' + pattern + ') client1 received message on ' + channel + ': ' + message)
msgCount += 1; msgCount += 1
if (msgCount === 3) { if (msgCount === 3) {
client1.punsubscribe(); client1.punsubscribe()
} }
}); })
client1.psubscribe('channel*'); client1.psubscribe('channel*')

View File

@@ -1,42 +1,42 @@
'use strict'; 'use strict'
var redis = require('redis'); var redis = require('redis')
var client1 = redis.createClient(); var client1 = redis.createClient()
var msgCount = 0; var msgCount = 0
var client2 = redis.createClient(); var client2 = redis.createClient()
// Most clients probably don't do much on 'subscribe'. This example uses it to coordinate things within one program. // Most clients probably don't do much on 'subscribe'. This example uses it to coordinate things within one program.
client1.on('subscribe', function (channel, count) { client1.on('subscribe', function (channel, count) {
console.log('client1 subscribed to ' + channel + ', ' + count + ' total subscriptions'); console.log('client1 subscribed to ' + channel + ', ' + count + ' total subscriptions')
if (count === 2) { if (count === 2) {
client2.publish('a nice channel', 'I am sending a message.'); client2.publish('a nice channel', 'I am sending a message.')
client2.publish('another one', 'I am sending a second message.'); client2.publish('another one', 'I am sending a second message.')
client2.publish('a nice channel', 'I am sending my last message.'); client2.publish('a nice channel', 'I am sending my last message.')
} }
}); })
client1.on('unsubscribe', function (channel, count) { client1.on('unsubscribe', function (channel, count) {
console.log('client1 unsubscribed from ' + channel + ', ' + count + ' total subscriptions'); console.log('client1 unsubscribed from ' + channel + ', ' + count + ' total subscriptions')
if (count === 0) { if (count === 0) {
client2.end(); client2.end()
client1.end(); client1.end()
} }
}); })
client1.on('message', function (channel, message) { client1.on('message', function (channel, message) {
console.log('client1 channel ' + channel + ': ' + message); console.log('client1 channel ' + channel + ': ' + message)
msgCount += 1; msgCount += 1
if (msgCount === 3) { if (msgCount === 3) {
client1.unsubscribe(); client1.unsubscribe()
} }
}); })
client1.on('ready', function () { client1.on('ready', function () {
// if you need auth, do it here // if you need auth, do it here
client1.incr('did a thing'); client1.incr('did a thing')
client1.subscribe('a nice channel', 'another one'); client1.subscribe('a nice channel', 'another one')
}); })
client2.on('ready', function () { client2.on('ready', function () {
// if you need auth, do it here // if you need auth, do it here
}); })

View File

@@ -1,51 +1,51 @@
'use strict'; 'use strict'
var redis = require('redis'); var redis = require('redis')
var client = redis.createClient(); var client = redis.createClient()
var cursor = '0'; var cursor = '0'
function scan () { function scan () {
client.scan( client.scan(
cursor, cursor,
'MATCH', 'q:job:*', 'MATCH', 'q:job:*',
'COUNT', '10', 'COUNT', '10',
function (err, res) { function (err, res) {
if (err) throw err; if (err) throw err
// Update the cursor position for the next scan // Update the cursor position for the next scan
cursor = res[0]; cursor = res[0]
// get the SCAN result for this iteration // get the SCAN result for this iteration
var keys = res[1]; var keys = res[1]
// Remember: more or less than COUNT or no keys may be returned // Remember: more or less than COUNT or no keys may be returned
// See http://redis.io/commands/scan#the-count-option // See http://redis.io/commands/scan#the-count-option
// Also, SCAN may return the same key multiple times // Also, SCAN may return the same key multiple times
// See http://redis.io/commands/scan#scan-guarantees // See http://redis.io/commands/scan#scan-guarantees
// Additionally, you should always have the code that uses the keys // Additionally, you should always have the code that uses the keys
// before the code checking the cursor. // before the code checking the cursor.
if (keys.length > 0) { if (keys.length > 0) {
console.log('Array of matching keys', keys); console.log('Array of matching keys', keys)
} }
// It's important to note that the cursor and returned keys // It's important to note that the cursor and returned keys
// vary independently. The scan is never complete until redis // vary independently. The scan is never complete until redis
// returns a non-zero cursor. However, with MATCH and large // returns a non-zero cursor. However, with MATCH and large
// collections, most iterations will return an empty keys array. // collections, most iterations will return an empty keys array.
// Still, a cursor of zero DOES NOT mean that there are no keys. // Still, a cursor of zero DOES NOT mean that there are no keys.
// A zero cursor just means that the SCAN is complete, but there // A zero cursor just means that the SCAN is complete, but there
// might be one last batch of results to process. // might be one last batch of results to process.
// From <http://redis.io/commands/scan>: // From <http://redis.io/commands/scan>:
// 'An iteration starts when the cursor is set to 0, // 'An iteration starts when the cursor is set to 0,
// and terminates when the cursor returned by the server is 0.' // and terminates when the cursor returned by the server is 0.'
if (cursor === '0') { if (cursor === '0') {
return console.log('Iteration complete'); return console.log('Iteration complete')
} }
return scan(); return scan()
} }
); )
} }
scan(); scan()

View File

@@ -1,26 +1,27 @@
'use strict'; 'use strict'
var redis = require('redis'); var redis = require('redis')
var client = redis.createClient(); var client = redis.createClient()
client.on('error', function (err) { client.on('error', function (err) {
console.log('error event - ' + client.host + ':' + client.port + ' - ' + err); console.log('error event - ' + client.host + ':' + client.port + ' - ' + err)
}); })
client.set('string key', 'string val', console.log); client.set('string key', 'string val', console.log)
client.hset('hash key', 'hashtest 1', 'some value', console.log); client.hset('hash key', 'hashtest 1', 'some value', console.log)
client.hset(['hash key', 'hashtest 2', 'some other value'], console.log); client.hset(['hash key', 'hashtest 2', 'some other value'], console.log)
client.hkeys('hash key', function (err, replies) { client.hkeys('hash key', function (err, replies) {
if (err) { if (err) {
return console.error('error response - ' + err); return console.error('error response - ' + err)
} }
console.log(replies.length + ' replies:'); console.log(replies.length + ' replies:')
replies.forEach(function (reply, i) { replies.forEach(function (reply, i) {
console.log(' ' + i + ': ' + reply); console.log(' ' + i + ': ' + reply)
}); })
}); })
client.quit(function (err, res) { client.quit(function (err, res) {
console.log('Exiting from quit command.'); if (err) throw err
}); console.log('Exiting from quit command.')
})

View File

@@ -1,19 +1,19 @@
'use strict'; 'use strict'
var redis = require('redis'); var redis = require('redis')
var client = redis.createClient(); var client = redis.createClient()
client.sadd('mylist', 1); client.sadd('mylist', 1)
client.sadd('mylist', 2); client.sadd('mylist', 2)
client.sadd('mylist', 3); client.sadd('mylist', 3)
client.set('weight_1', 5); client.set('weight_1', 5)
client.set('weight_2', 500); client.set('weight_2', 500)
client.set('weight_3', 1); client.set('weight_3', 1)
client.set('object_1', 'foo'); client.set('object_1', 'foo')
client.set('object_2', 'bar'); client.set('object_2', 'bar')
client.set('object_3', 'qux'); client.set('object_3', 'qux')
client.sort('mylist', 'by', 'weight_*', 'get', 'object_*', console.log); client.sort('mylist', 'by', 'weight_*', 'get', 'object_*', console.log)
// Prints Reply: qux,foo,bar // Prints Reply: qux,foo,bar

View File

@@ -1,17 +1,19 @@
'use strict'; 'use strict'
// Sending commands in response to other commands. // Sending commands in response to other commands.
// This example runs 'type' against every key in the database // This example runs 'type' against every key in the database
// //
var client = require('redis').createClient(); var client = require('redis').createClient()
client.keys('*', function (err, keys) { client.keys('*', function (err, keys) {
keys.forEach(function (key, pos) { if (err) throw err
client.type(key, function (err, keytype) { keys.forEach(function (key, pos) {
console.log(key + ' is ' + keytype); client.type(key, function (err, keytype) {
if (pos === (keys.length - 1)) { if (err) throw err
client.quit(); console.log(key + ' is ' + keytype)
} if (pos === (keys.length - 1)) {
}); client.quit()
}); }
}); })
})
})

View File

@@ -1,17 +1,19 @@
'use strict'; 'use strict'
var client = require('redis').createClient(); var client = require('redis').createClient()
// build a map of all keys and their types // build a map of all keys and their types
client.keys('*', function (err, allKeys) { client.keys('*', function (err, allKeys) {
var keyTypes = {}; if (err) throw err
var keyTypes = {}
allKeys.forEach(function (key, pos) { // use second arg of forEach to get pos allKeys.forEach(function (key, pos) { // use second arg of forEach to get pos
client.type(key, function (err, type) { client.type(key, function (err, type) {
keyTypes[key] = type; if (err) throw err
if (pos === allKeys.length - 1) { // callbacks all run in order keyTypes[key] = type
console.dir(keyTypes); if (pos === allKeys.length - 1) { // callbacks all run in order
} console.dir(keyTypes)
}); }
}); })
}); })
})

View File

@@ -1,32 +1,33 @@
'use strict'; 'use strict'
var redis = require('redis'); var redis = require('redis')
var client = redis.createClient('/tmp/redis.sock'); var client = redis.createClient('/tmp/redis.sock')
var profiler = require('v8-profiler'); var profiler = require('v8-profiler')
client.on('connect', function () { client.on('connect', function () {
console.log('Got Unix socket connection.'); console.log('Got Unix socket connection.')
}); })
client.on('error', function (err) { client.on('error', function (err) {
console.log(err.message); console.log(err.message)
}); })
client.set('space chars', 'space value'); client.set('space chars', 'space value')
setInterval(function () { setInterval(function () {
client.get('space chars'); client.get('space chars')
}, 100); }, 100)
function done () { function done () {
client.info(function (err, reply) { client.info(function (err, reply) {
console.log(reply.toString()); if (err) throw err
client.quit(); console.log(reply.toString())
}); client.quit()
})
} }
setTimeout(function () { setTimeout(function () {
console.log('Taking snapshot.'); console.log('Taking snapshot.')
profiler.takeSnapshot(); profiler.takeSnapshot()
done(); done()
}, 5000); }, 5000)

View File

@@ -1,33 +1,36 @@
'use strict'; 'use strict'
// A simple web server that generates dyanmic content based on responses from Redis // A simple web server that generates dyanmic content based on responses from Redis
var http = require('http'); var http = require('http')
var redisClient = require('redis').createClient(); var redisClient = require('redis').createClient()
http.createServer(function (request, response) { // The server http.createServer(function (request, response) { // The server
response.writeHead(200, { response.writeHead(200, {
'Content-Type': 'text/plain' 'Content-Type': 'text/plain'
}); })
var redisInfo, totalRequests; var redisInfo, totalRequests
redisClient.info(function (err, reply) { redisClient.info(function (err, reply) {
redisInfo = reply; // stash response in outer scope if (err) throw err
}); redisInfo = reply // stash response in outer scope
redisClient.incr('requests', function (err, reply) { })
totalRequests = reply; // stash response in outer scope redisClient.incr('requests', function (err, reply) {
}); if (err) throw err
redisClient.hincrby('ip', request.connection.remoteAddress, 1); totalRequests = reply // stash response in outer scope
redisClient.hgetall('ip', function (err, reply) { })
redisClient.hincrby('ip', request.connection.remoteAddress, 1)
redisClient.hgetall('ip', function (err, reply) {
if (err) throw err
// This is the last reply, so all of the previous replies must have completed already // This is the last reply, so all of the previous replies must have completed already
response.write('This page was generated after talking to redis.\n\n' + response.write('This page was generated after talking to redis.\n\n' +
'Redis info:\n' + redisInfo + '\n' + 'Redis info:\n' + redisInfo + '\n' +
'Total requests: ' + totalRequests + '\n\n' + 'Total requests: ' + totalRequests + '\n\n' +
'IP count: \n'); 'IP count: \n')
Object.keys(reply).forEach(function (ip) { Object.keys(reply).forEach(function (ip) {
response.write(' ' + ip + ': ' + reply[ip] + '\n'); response.write(' ' + ip + ': ' + reply[ip] + '\n')
}); })
response.end(); response.end()
}); })
}).listen(80); }).listen(80)

1501
index.js

File diff suppressed because it is too large Load Diff

View File

@@ -1,16 +1,16 @@
'use strict'; 'use strict'
var betterStackTraces = /development/i.test(process.env.NODE_ENV) || /\bredis\b/i.test(process.env.NODE_DEBUG); var betterStackTraces = /development/i.test(process.env.NODE_ENV) || /\bredis\b/i.test(process.env.NODE_DEBUG)
function Command (command, args, callback, callOnWrite) { function Command (command, args, callback, callOnWrite) {
this.command = command; this.command = command
this.args = args; this.args = args
this.bufferArgs = false; this.bufferArgs = false
this.callback = callback; this.callback = callback
this.callOnWrite = callOnWrite; this.callOnWrite = callOnWrite
if (betterStackTraces) { if (betterStackTraces) {
this.error = new Error(); this.error = new Error()
} }
} }
module.exports = Command; module.exports = Command

View File

@@ -1,100 +1,99 @@
'use strict'; 'use strict'
var commands = require('redis-commands'); var commands = require('redis-commands')
var Multi = require('./multi'); var Multi = require('./multi')
var RedisClient = require('../').RedisClient; var RedisClient = require('../').RedisClient
var Command = require('./command'); var Command = require('./command')
// TODO: Rewrite this including the individual commands into a Commands class // TODO: Rewrite this including the individual commands into a Commands class
// that provided a functionality to add new commands to the client // that provided a functionality to add new commands to the client
commands.list.forEach(function (command) { commands.list.forEach(function (command) {
// Some rare Redis commands use special characters in their command name
// Convert those to a underscore to prevent using invalid function names
var commandName = command.replace(/(?:^([0-9])|[^a-zA-Z0-9_$])/g, '_$1')
// Some rare Redis commands use special characters in their command name // Do not override existing functions
// Convert those to a underscore to prevent using invalid function names if (!RedisClient.prototype[command]) {
var commandName = command.replace(/(?:^([0-9])|[^a-zA-Z0-9_$])/g, '_$1'); RedisClient.prototype[command] = function () {
var arr
// Do not override existing functions var len = arguments.length
if (!RedisClient.prototype[command]) { var callback
RedisClient.prototype[command] = function () { var i = 0
var arr; if (Array.isArray(arguments[0])) {
var len = arguments.length; arr = arguments[0]
var callback; if (len === 2) {
var i = 0; callback = arguments[1]
if (Array.isArray(arguments[0])) {
arr = arguments[0];
if (len === 2) {
callback = arguments[1];
}
} else if (len > 1 && Array.isArray(arguments[1])) {
if (len === 3) {
callback = arguments[2];
}
len = arguments[1].length;
arr = new Array(len + 1);
arr[0] = arguments[0];
for (; i < len; i += 1) {
arr[i + 1] = arguments[1][i];
}
} else {
// The later should not be the average use case
if (len !== 0 && (typeof arguments[len - 1] === 'function' || typeof arguments[len - 1] === 'undefined')) {
len--;
callback = arguments[len];
}
arr = new Array(len);
for (; i < len; i += 1) {
arr[i] = arguments[i];
}
}
return this.internalSendCommand(new Command(command, arr, callback));
};
if (RedisClient.prototype[command] !== commandName) {
Object.defineProperty(RedisClient.prototype[command], 'name', {
value: commandName
});
} }
} } else if (len > 1 && Array.isArray(arguments[1])) {
if (len === 3) {
// Do not override existing functions callback = arguments[2]
if (!Multi.prototype[command]) {
Multi.prototype[command] = function () {
var arr;
var len = arguments.length;
var callback;
var i = 0;
if (Array.isArray(arguments[0])) {
arr = arguments[0];
if (len === 2) {
callback = arguments[1];
}
} else if (len > 1 && Array.isArray(arguments[1])) {
if (len === 3) {
callback = arguments[2];
}
len = arguments[1].length;
arr = new Array(len + 1);
arr[0] = arguments[0];
for (; i < len; i += 1) {
arr[i + 1] = arguments[1][i];
}
} else {
// The later should not be the average use case
if (len !== 0 && (typeof arguments[len - 1] === 'function' || typeof arguments[len - 1] === 'undefined')) {
len--;
callback = arguments[len];
}
arr = new Array(len);
for (; i < len; i += 1) {
arr[i] = arguments[i];
}
}
this.queue.push(new Command(command, arr, callback));
return this;
};
if (Multi.prototype[command] !== commandName) {
Object.defineProperty(Multi.prototype[command], 'name', {
value: commandName
});
} }
len = arguments[1].length
arr = new Array(len + 1)
arr[0] = arguments[0]
for (; i < len; i += 1) {
arr[i + 1] = arguments[1][i]
}
} else {
// The later should not be the average use case
if (len !== 0 && (typeof arguments[len - 1] === 'function' || typeof arguments[len - 1] === 'undefined')) {
len--
callback = arguments[len]
}
arr = new Array(len)
for (; i < len; i += 1) {
arr[i] = arguments[i]
}
}
return this.internalSendCommand(new Command(command, arr, callback))
} }
}); if (RedisClient.prototype[command] !== commandName) {
Object.defineProperty(RedisClient.prototype[command], 'name', {
value: commandName
})
}
}
// Do not override existing functions
if (!Multi.prototype[command]) {
Multi.prototype[command] = function () {
var arr
var len = arguments.length
var callback
var i = 0
if (Array.isArray(arguments[0])) {
arr = arguments[0]
if (len === 2) {
callback = arguments[1]
}
} else if (len > 1 && Array.isArray(arguments[1])) {
if (len === 3) {
callback = arguments[2]
}
len = arguments[1].length
arr = new Array(len + 1)
arr[0] = arguments[0]
for (; i < len; i += 1) {
arr[i + 1] = arguments[1][i]
}
} else {
// The later should not be the average use case
if (len !== 0 && (typeof arguments[len - 1] === 'function' || typeof arguments[len - 1] === 'undefined')) {
len--
callback = arguments[len]
}
arr = new Array(len)
for (; i < len; i += 1) {
arr[i] = arguments[i]
}
}
this.queue.push(new Command(command, arr, callback))
return this
}
if (Multi.prototype[command] !== commandName) {
Object.defineProperty(Multi.prototype[command], 'name', {
value: commandName
})
}
}
})

View File

@@ -1,80 +1,75 @@
'use strict'; 'use strict'
var utils = require('./utils'); var utils = require('./utils')
var URL = require('url'); var URL = require('url')
module.exports = function createClient (portArg, hostArg, options) { module.exports = function createClient (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
if (typeof hostArg === 'string') {
var host; host = hostArg
if (typeof hostArg === 'string') { } else {
host = hostArg; if (options && hostArg) {
} else { throw new TypeError('Unknown type of connection in createClient()')
if (options && hostArg) { }
throw new TypeError('Unknown type of connection in createClient()'); options = options || hostArg
}
options = options || hostArg;
}
options = utils.clone(options);
options.host = host || options.host;
options.port = portArg;
} else if (typeof portArg === 'string' || portArg && portArg.url) {
options = utils.clone(portArg.url ? portArg : hostArg || options);
var parsed = URL.parse(portArg.url || portArg, true, true);
// [redis:]//[[user][:password]@][host][:port][/db-number][?db=db-number[&password=bar[&option=value]]]
if (parsed.slashes) { // We require slashes
if (parsed.auth) {
options.password = parsed.auth.split(':')[1];
}
if (parsed.protocol && parsed.protocol !== 'redis:') {
console.warn('nodeRedis: WARNING: You passed "' + parsed.protocol.substring(0, parsed.protocol.length - 1) + '" as protocol instead of the "redis" protocol!');
}
if (parsed.pathname && parsed.pathname !== '/') {
options.db = parsed.pathname.substr(1);
}
if (parsed.hostname) {
options.host = parsed.hostname;
}
if (parsed.port) {
options.port = parsed.port;
}
if (parsed.search !== '') {
var elem;
for (elem in parsed.query) {
// If options are passed twice, only the parsed options will be used
if (elem in options) {
if (options[elem] === parsed.query[elem]) {
console.warn('nodeRedis: WARNING: You passed the ' + elem + ' option twice!');
} else {
throw new RangeError('The ' + elem + ' option is added twice and does not match');
}
}
options[elem] = parsed.query[elem];
}
}
} else if (parsed.hostname) {
throw new RangeError('The redis url must begin with slashes "//" or contain slashes after the redis protocol');
} else {
options.path = portArg;
}
} else if (typeof portArg === 'object' || portArg === undefined) {
options = utils.clone(portArg || options);
options.host = options.host || hostArg;
if (portArg && arguments.length !== 1) {
throw new TypeError('To many arguments passed to createClient. Please only pass the options object');
}
} }
options = utils.clone(options)
options.host = host || options.host
options.port = portArg
} else if (typeof portArg === 'string' || (portArg && portArg.url)) {
options = utils.clone(portArg.url ? portArg : (hostArg || options))
if (!options) { var parsed = URL.parse(portArg.url || portArg, true, true)
throw new TypeError('Unknown type of connection in createClient()');
// [redis:]//[[user][:password]@][host][:port][/db-number][?db=db-number[&password=bar[&option=value]]]
if (parsed.slashes) { // We require slashes
if (parsed.auth) {
options.password = parsed.auth.split(':')[1]
}
if (parsed.protocol && parsed.protocol !== 'redis:') {
console.warn('nodeRedis: WARNING: You passed "' + parsed.protocol.substring(0, parsed.protocol.length - 1) + '" as protocol instead of the "redis" protocol!')
}
if (parsed.pathname && parsed.pathname !== '/') {
options.db = parsed.pathname.substr(1)
}
if (parsed.hostname) {
options.host = parsed.hostname
}
if (parsed.port) {
options.port = parsed.port
}
if (parsed.search !== '') {
var elem
for (elem in parsed.query) {
// If options are passed twice, only the parsed options will be used
if (elem in options) {
if (options[elem] === parsed.query[elem]) {
console.warn('nodeRedis: WARNING: You passed the ' + elem + ' option twice!')
} else {
throw new RangeError('The ' + elem + ' option is added twice and does not match')
}
}
options[elem] = parsed.query[elem]
}
}
} else if (parsed.hostname) {
throw new RangeError('The redis url must begin with slashes "//" or contain slashes after the redis protocol')
} else {
options.path = portArg
} }
} else if (typeof portArg === 'object' || portArg === undefined) {
options = utils.clone(portArg || options)
options.host = options.host || hostArg
return options; if (portArg && arguments.length !== 1) {
}; throw new TypeError('To many arguments passed to createClient. Please only pass the options object')
}
}
if (!options) {
throw new TypeError('Unknown type of connection in createClient()')
}
return options
}

View File

@@ -1,59 +1,59 @@
'use strict'; 'use strict'
var util = require('util'); var util = require('util')
var assert = require('assert'); var assert = require('assert')
var RedisError = require('redis-parser').RedisError; var RedisError = require('redis-parser').RedisError
var ADD_STACKTRACE = false; var ADD_STACKTRACE = false
function AbortError (obj, stack) { function AbortError (obj, stack) {
assert(obj, 'The options argument is required'); assert(obj, 'The options argument is required')
assert.strictEqual(typeof obj, 'object', 'The options argument has to be of type object'); assert.strictEqual(typeof obj, 'object', 'The options argument has to be of type object')
RedisError.call(this, obj.message, ADD_STACKTRACE); RedisError.call(this, obj.message, ADD_STACKTRACE)
Object.defineProperty(this, 'message', { Object.defineProperty(this, 'message', {
value: obj.message || '', value: obj.message || '',
configurable: true, configurable: true,
writable: true writable: true
}); })
if (stack || stack === undefined) { if (stack || stack === undefined) {
Error.captureStackTrace(this, AbortError); Error.captureStackTrace(this, AbortError)
} }
for (var keys = Object.keys(obj), key = keys.pop(); key; key = keys.pop()) { for (var keys = Object.keys(obj), key = keys.pop(); key; key = keys.pop()) {
this[key] = obj[key]; this[key] = obj[key]
} }
} }
function AggregateError (obj) { function AggregateError (obj) {
assert(obj, 'The options argument is required'); assert(obj, 'The options argument is required')
assert.strictEqual(typeof obj, 'object', 'The options argument has to be of type object'); assert.strictEqual(typeof obj, 'object', 'The options argument has to be of type object')
AbortError.call(this, obj, ADD_STACKTRACE); AbortError.call(this, obj, ADD_STACKTRACE)
Object.defineProperty(this, 'message', { Object.defineProperty(this, 'message', {
value: obj.message || '', value: obj.message || '',
configurable: true, configurable: true,
writable: true writable: true
}); })
Error.captureStackTrace(this, AggregateError); Error.captureStackTrace(this, AggregateError)
for (var keys = Object.keys(obj), key = keys.pop(); key; key = keys.pop()) { for (var keys = Object.keys(obj), key = keys.pop(); key; key = keys.pop()) {
this[key] = obj[key]; this[key] = obj[key]
} }
} }
util.inherits(AbortError, RedisError); util.inherits(AbortError, RedisError)
util.inherits(AggregateError, AbortError); util.inherits(AggregateError, AbortError)
Object.defineProperty(AbortError.prototype, 'name', { Object.defineProperty(AbortError.prototype, 'name', {
value: 'AbortError', value: 'AbortError',
configurable: true, configurable: true,
writable: true writable: true
}); })
Object.defineProperty(AggregateError.prototype, 'name', { Object.defineProperty(AggregateError.prototype, 'name', {
value: 'AggregateError', value: 'AggregateError',
configurable: true, configurable: true,
writable: true writable: true
}); })
module.exports = { module.exports = {
AbortError: AbortError, AbortError: AbortError,
AggregateError: AggregateError AggregateError: AggregateError
}; }

View File

@@ -1,11 +1,11 @@
'use strict'; 'use strict'
var index = require('../'); var index = require('../')
function debug () { function debug () {
if (index.debugMode) { if (index.debugMode) {
console.error.apply(null, arguments); console.error.apply(null, arguments)
} }
} }
module.exports = debug; module.exports = debug

View File

@@ -1,10 +1,10 @@
'use strict'; 'use strict'
var utils = require('./utils'); var utils = require('./utils')
var debug = require('./debug'); var debug = require('./debug')
var RedisClient = require('../').RedisClient; var RedisClient = require('../').RedisClient
var Command = require('./command'); var Command = require('./command')
var noop = function () {}; var noop = function () {}
/********************************************** /**********************************************
All documented and exposed API belongs in here All documented and exposed API belongs in here
@@ -12,101 +12,101 @@ All documented and exposed API belongs in here
// Redirect calls to the appropriate function and use to send arbitrary / not supported commands // Redirect calls to the appropriate function and use to send arbitrary / not supported commands
RedisClient.prototype.sendCommand = function (command, args, callback) { RedisClient.prototype.sendCommand = function (command, args, callback) {
// Throw to fail early instead of relying in order in this case // Throw to fail early instead of relying in order in this case
if (typeof command !== 'string') { if (typeof command !== 'string') {
throw new TypeError('Wrong input type "' + (command !== null && command !== undefined ? command.constructor.name : command) + '" for command name'); throw new TypeError('Wrong input type "' + (command !== null && command !== undefined ? command.constructor.name : command) + '" for command name')
} }
if (!Array.isArray(args)) { if (!Array.isArray(args)) {
if (args === undefined || args === null) { if (args === undefined || args === null) {
args = []; args = []
} else if (typeof args === 'function' && callback === undefined) { } else if (typeof args === 'function' && callback === undefined) {
callback = args; callback = args
args = []; args = []
} else { } else {
throw new TypeError('Wrong input type "' + args.constructor.name + '" for args'); throw new TypeError('Wrong input type "' + args.constructor.name + '" for args')
}
}
if (typeof callback !== 'function' && callback !== undefined) {
throw new TypeError('Wrong input type "' + (callback !== null ? callback.constructor.name : 'null') + '" for callback function');
} }
}
if (typeof callback !== 'function' && callback !== undefined) {
throw new TypeError('Wrong input type "' + (callback !== null ? callback.constructor.name : 'null') + '" for callback function')
}
// Using the raw multi command is only possible with this function // Using the raw multi command is only possible with this function
// If the command is not yet added to the client, the internal function should be called right away // If the command is not yet added to the client, the internal function should be called right away
// Otherwise we need to redirect the calls to make sure the internal functions don't get skipped // Otherwise we need to redirect the calls to make sure the internal functions don't get skipped
// The internal functions could actually be used for any non hooked function // The internal functions could 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 // 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, callback)); return this.internalSendCommand(new Command(command, args, callback))
} }
if (typeof callback === 'function') { if (typeof callback === 'function') {
args = args.concat([callback]); // Prevent manipulating the input array args = args.concat([callback]) // Prevent manipulating the input array
} }
return this[command].apply(this, args); return this[command].apply(this, args)
}; }
RedisClient.prototype.end = function (flush) { RedisClient.prototype.end = function (flush) {
// Flush queue if wanted // Flush queue if wanted
if (flush) { if (flush) {
this.flushAndError({ this.flushAndError({
message: 'Connection forcefully ended and command aborted.', message: 'Connection forcefully ended and command aborted.',
code: 'NR_CLOSED' code: 'NR_CLOSED'
}); })
} else if (arguments.length === 0) { } else if (arguments.length === 0) {
this.warn( this.warn(
'Using .end() without the flush parameter is deprecated and throws from v.3.0.0 on.\n' + 'Using .end() without the flush parameter is deprecated and throws from v.3.0.0 on.\n' +
'Please check the documentation (https://github.com/NodeRedis/nodeRedis) and explicitly use flush.' 'Please check the documentation (https://github.com/NodeRedis/nodeRedis) and explicitly use flush.'
); )
} }
// Clear retryTimer // Clear retryTimer
if (this.retryTimer) { if (this.retryTimer) {
clearTimeout(this.retryTimer); clearTimeout(this.retryTimer)
this.retryTimer = null; this.retryTimer = null
} }
this.stream.removeAllListeners(); this.stream.removeAllListeners()
this.stream.on('error', noop); this.stream.on('error', noop)
this.connected = false; this.connected = false
this.ready = false; this.ready = false
this.closing = true; this.closing = true
return this.stream.destroySoon(); return this.stream.destroySoon()
}; }
RedisClient.prototype.unref = function () { RedisClient.prototype.unref = function () {
if (this.connected) { if (this.connected) {
debug("Unref'ing the socket connection"); debug('Unref\'ing the socket connection')
this.stream.unref(); this.stream.unref()
} else { } else {
debug('Not connected yet, will unref later'); debug('Not connected yet, will unref later')
this.once('connect', function () { this.once('connect', function () {
this.unref(); this.unref()
}); })
} }
}; }
RedisClient.prototype.duplicate = function (options, callback) { RedisClient.prototype.duplicate = function (options, callback) {
if (typeof options === 'function') { if (typeof options === 'function') {
callback = options; callback = options
options = null; options = null
}
var existingOptions = utils.clone(this.options)
options = utils.clone(options)
for (var elem in options) {
existingOptions[elem] = options[elem]
}
var client = new RedisClient(existingOptions)
client.selectedDb = this.selectedDb
if (typeof callback === 'function') {
var readyListener = function () {
callback(null, client)
client.removeAllListeners(errorListener)
} }
var existingOptions = utils.clone(this.options); var errorListener = function (err) {
options = utils.clone(options); callback(err)
for (var elem in options) { client.end(true)
existingOptions[elem] = options[elem];
} }
var client = new RedisClient(existingOptions); client.once('ready', readyListener)
client.selectedDb = this.selectedDb; client.once('error', errorListener)
if (typeof callback === 'function') { return
var readyListener = function () { }
callback(null, client); return client
client.removeAllListeners(errorListener); }
};
var errorListener = function (err) {
callback(err);
client.end(true);
};
client.once('ready', readyListener);
client.once('error', errorListener);
return;
}
return client;
};

File diff suppressed because it is too large Load Diff

View File

@@ -1,187 +1,187 @@
'use strict'; 'use strict'
var Queue = require('double-ended-queue'); var Queue = require('double-ended-queue')
var utils = require('./utils'); var utils = require('./utils')
var Command = require('./command'); var Command = require('./command')
function Multi (client, args) { function Multi (client, args) {
this._client = client; this._client = client
this.queue = new Queue(); this.queue = new Queue()
var command, tmpArgs; var command, tmpArgs
if (args) { // Either undefined or an array. Fail hard if it's not an array if (args) { // Either undefined or an array. Fail hard if it's not an array
for (var i = 0; i < args.length; i++) { for (var i = 0; i < args.length; i++) {
command = args[i][0]; command = args[i][0]
tmpArgs = args[i].slice(1); tmpArgs = args[i].slice(1)
if (Array.isArray(command)) { if (Array.isArray(command)) {
this[command[0]].apply(this, command.slice(1).concat(tmpArgs)); this[command[0]].apply(this, command.slice(1).concat(tmpArgs))
} else { } else {
this[command].apply(this, tmpArgs); this[command].apply(this, tmpArgs)
} }
}
} }
}
} }
function pipelineTransactionCommand (self, commandObj, index) { function pipelineTransactionCommand (self, commandObj, index) {
// Queueing is done first, then the commands are executed // Queueing is done first, then the commands are executed
var tmp = commandObj.callback; var tmp = commandObj.callback
commandObj.callback = function (err, reply) { commandObj.callback = function (err, reply) {
// Ignore the multi command. This is applied by nodeRedis and the user does not benefit by it // Ignore the multi command. This is applied by nodeRedis and the user does not benefit by it
if (err && index !== -1) { if (err && index !== -1) {
if (tmp) { if (tmp) {
tmp(err); tmp(err)
} }
err.position = index; err.position = index
self.errors.push(err); self.errors.push(err)
} }
// Keep track of who wants buffer responses: // Keep track of who wants buffer responses:
// By the time the callback is called the commandObj got the bufferArgs attribute attached // By the time the callback is called the commandObj got the bufferArgs attribute attached
self.wantsBuffers[index] = commandObj.bufferArgs; self.wantsBuffers[index] = commandObj.bufferArgs
commandObj.callback = tmp; commandObj.callback = tmp
}; }
self._client.internalSendCommand(commandObj); self._client.internalSendCommand(commandObj)
} }
Multi.prototype.execAtomic = function execAtomic (callback) { Multi.prototype.execAtomic = function execAtomic (callback) {
if (this.queue.length < 2) { if (this.queue.length < 2) {
return this.execBatch(callback); return this.execBatch(callback)
} }
return this.exec(callback); return this.exec(callback)
}; }
function multiCallback (self, err, replies) { function multiCallback (self, err, replies) {
var i = 0, commandObj; var i = 0
if (err) {
err.errors = self.errors;
if (self.callback) {
self.callback(err);
// Exclude connection errors so that those errors won't be emitted twice
} else if (err.code !== 'CONNECTION_BROKEN') {
self._client.emit('error', err);
}
return;
}
if (replies) {
while (commandObj = self.queue.shift()) {
if (replies[i] instanceof Error) {
var match = replies[i].message.match(utils.errCode);
// LUA script could return user errors that don't behave like all other errors!
if (match) {
replies[i].code = match[1];
}
replies[i].command = commandObj.command.toUpperCase();
if (typeof commandObj.callback === 'function') {
commandObj.callback(replies[i]);
}
} else {
// If we asked for strings, even in detectBuffers mode, then return strings:
replies[i] = self._client.handleReply(replies[i], commandObj.command, self.wantsBuffers[i]);
if (typeof commandObj.callback === 'function') {
commandObj.callback(null, replies[i]);
}
}
i++;
}
}
if (err) {
err.errors = self.errors
if (self.callback) { if (self.callback) {
self.callback(null, replies); self.callback(err)
// Exclude connection errors so that those errors won't be emitted twice
} else if (err.code !== 'CONNECTION_BROKEN') {
self._client.emit('error', err)
} }
return
}
if (replies) {
for (var commandObj = self.queue.shift(); commandObj !== undefined; commandObj = self.queue.shift()) {
if (replies[i] instanceof Error) {
var match = replies[i].message.match(utils.errCode)
// LUA script could return user errors that don't behave like all other errors!
if (match) {
replies[i].code = match[1]
}
replies[i].command = commandObj.command.toUpperCase()
if (typeof commandObj.callback === 'function') {
commandObj.callback(replies[i])
}
} else {
// If we asked for strings, even in detectBuffers mode, then return strings:
replies[i] = self._client.handleReply(replies[i], commandObj.command, self.wantsBuffers[i])
if (typeof commandObj.callback === 'function') {
commandObj.callback(null, replies[i])
}
}
i++
}
}
if (self.callback) {
self.callback(null, replies)
}
} }
Multi.prototype.execTransaction = function execTransaction (callback) { Multi.prototype.execTransaction = function execTransaction (callback) {
if (this.monitoring || this._client.monitoring) { if (this.monitoring || this._client.monitoring) {
var err = new RangeError( var 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 utils.replyInOrder(this._client, callback, err); return utils.replyInOrder(this._client, callback, err)
} }
var self = this; var self = this
var len = self.queue.length; var len = self.queue.length
self.errors = []; self.errors = []
self.callback = callback; self.callback = callback
self._client.cork(); self._client.cork()
self.wantsBuffers = new Array(len); self.wantsBuffers = new Array(len)
pipelineTransactionCommand(self, new Command('multi', []), -1); pipelineTransactionCommand(self, new Command('multi', []), -1)
// Drain queue, callback will catch 'QUEUED' or error // Drain queue, callback will catch 'QUEUED' or error
for (var index = 0; index < len; index++) { for (var 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
pipelineTransactionCommand(self, self.queue.get(index), index); pipelineTransactionCommand(self, self.queue.get(index), index)
} }
self._client.internalSendCommand(new Command('exec', [], function (err, replies) { self._client.internalSendCommand(new Command('exec', [], function (err, replies) {
multiCallback(self, err, replies); multiCallback(self, err, replies)
})); }))
self._client.uncork(); self._client.uncork()
return !self._client.shouldBuffer; return !self._client.shouldBuffer
}; }
function batchCallback (self, cb, i) { function batchCallback (self, cb, i) {
return function batchCallback (err, res) { return function batchCallback (err, res) {
if (err) { if (err) {
self.results[i] = err; self.results[i] = err
// Add the position to the error // Add the position to the error
self.results[i].position = i; self.results[i].position = i
} else { } else {
self.results[i] = res; self.results[i] = res
} }
cb(err, res); cb(err, res)
}; }
} }
Multi.prototype.exec = Multi.prototype.execBatch = function execBatch (callback) { Multi.prototype.exec = Multi.prototype.execBatch = function execBatch (callback) {
var self = this; var self = this
var len = self.queue.length; var len = self.queue.length
var index = 0; var index = 0
var commandObj; var commandObj
if (len === 0) { if (len === 0) {
utils.replyInOrder(self._client, callback, null, []); utils.replyInOrder(self._client, callback, null, [])
return !self._client.shouldBuffer; return !self._client.shouldBuffer
}
self._client.cork()
if (!callback) {
for (commandObj = self.queue.shift(); commandObj !== undefined; commandObj = self.queue.shift()) {
self._client.internalSendCommand(commandObj)
} }
self._client.cork(); self._client.uncork()
if (!callback) { return !self._client.shouldBuffer
while (commandObj = self.queue.shift()) { }
self._client.internalSendCommand(commandObj); var callbackWithoutOwnCb = function (err, res) {
} if (err) {
self._client.uncork(); self.results.push(err)
return !self._client.shouldBuffer; // Add the position to the error
var i = self.results.length - 1
self.results[i].position = i
} else {
self.results.push(res)
} }
var callbackWithoutOwnCb = function (err, res) { // Do not emit an error here. Otherwise each error would result in one emit.
if (err) { // The errors will be returned in the result anyway
self.results.push(err); }
// Add the position to the error var lastCallback = function (cb) {
var i = self.results.length - 1; return function (err, res) {
self.results[i].position = i; cb(err, res)
} else { callback(null, self.results)
self.results.push(res);
}
// Do not emit an error here. Otherwise each error would result in one emit.
// The errors will be returned in the result anyway
};
var lastCallback = function (cb) {
return function (err, res) {
cb(err, res);
callback(null, self.results);
};
};
self.results = [];
while (commandObj = self.queue.shift()) {
if (typeof commandObj.callback === 'function') {
commandObj.callback = batchCallback(self, commandObj.callback, index);
} else {
commandObj.callback = callbackWithoutOwnCb;
}
if (typeof callback === 'function' && index === len - 1) {
commandObj.callback = lastCallback(commandObj.callback);
}
this._client.internalSendCommand(commandObj);
index++;
} }
self._client.uncork(); }
return !self._client.shouldBuffer; self.results = []
}; for (commandObj = self.queue.shift(); commandObj !== undefined; commandObj = self.queue.shift()) {
if (typeof commandObj.callback === 'function') {
commandObj.callback = batchCallback(self, commandObj.callback, index)
} else {
commandObj.callback = callbackWithoutOwnCb
}
if (typeof callback === 'function' && index === len - 1) {
commandObj.callback = lastCallback(commandObj.callback)
}
this._client.internalSendCommand(commandObj)
index++
}
self._client.uncork()
return !self._client.shouldBuffer
}
module.exports = Multi; module.exports = Multi

View File

@@ -1,105 +1,104 @@
'use strict'; 'use strict'
// hgetall converts its replies to an Object. If the reply is empty, null is returned. // hgetall converts its replies to an Object. If the reply is empty, null is returned.
// These function are only called with internal data and have therefore always the same instanceof X // These function are only called with internal data and have therefore always the same instanceof X
function replyToObject (reply) { function replyToObject (reply) {
// The reply might be a string or a buffer if this is called in a transaction (multi) // The reply might be a string or a buffer if this is called in a transaction (multi)
if (reply.length === 0 || !(reply instanceof Array)) { if (reply.length === 0 || !(reply instanceof Array)) {
return null; return null
} }
var obj = {}; var obj = {}
for (var 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
} }
function replyToStrings (reply) { function replyToStrings (reply) {
if (reply instanceof Buffer) { if (reply instanceof Buffer) {
return reply.toString(); return reply.toString()
} }
if (reply instanceof Array) { if (reply instanceof Array) {
var res = new Array(reply.length); var res = new Array(reply.length)
for (var 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])
}
return res;
} }
return res
}
return reply; return reply
} }
// Deep clone arbitrary objects with arrays. Can't handle cyclic structures (results in a range error) // 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) // Any attribute with a non primitive value besides object and array will be passed by reference (e.g. Buffers, Maps, Functions)
function clone (obj) { function clone (obj) {
var copy; var copy
if (Array.isArray(obj)) { if (Array.isArray(obj)) {
copy = new Array(obj.length); copy = new Array(obj.length)
for (var i = 0; i < obj.length; i++) { for (var i = 0; i < obj.length; i++) {
copy[i] = clone(obj[i]); copy[i] = clone(obj[i])
}
return copy;
} }
if (Object.prototype.toString.call(obj) === '[object Object]') { return copy
copy = {}; }
var elements = Object.keys(obj); if (Object.prototype.toString.call(obj) === '[object Object]') {
var elem; copy = {}
while (elem = elements.pop()) { var elements = Object.keys(obj)
copy[elem] = clone(obj[elem]); for (var elem = elements.pop(); elem !== undefined; elem = elements.pop()) {
} copy[elem] = clone(obj[elem])
return copy;
} }
return obj; return copy
}
return obj
} }
function convenienceClone (obj) { function convenienceClone (obj) {
return clone(obj) || {}; return clone(obj) || {}
} }
function callbackOrEmit (self, callback, err, res) { function callbackOrEmit (self, callback, err, res) {
if (callback) { if (callback) {
callback(err, res); callback(err, res)
} else if (err) { } else if (err) {
self.emit('error', err); self.emit('error', err)
} }
} }
function replyInOrder (self, callback, err, res, queue) { function replyInOrder (self, callback, err, res, queue) {
// If the queue is explicitly passed, use that, otherwise fall back to the offline queue first, // If the queue is explicitly passed, use that, otherwise fall back to the offline queue first,
// as there might be commands in both queues at the same time // as there might be commands in both queues at the same time
var commandObj; var commandObj
if (queue) { if (queue) {
commandObj = queue.peekBack(); commandObj = queue.peekBack()
} else { } else {
commandObj = self.offlineQueue.peekBack() || self.commandQueue.peekBack(); commandObj = self.offlineQueue.peekBack() || self.commandQueue.peekBack()
} }
if (!commandObj) { if (!commandObj) {
process.nextTick(function () { process.nextTick(function () {
callbackOrEmit(self, callback, err, res); callbackOrEmit(self, callback, err, res)
}); })
} else { } else {
var tmp = commandObj.callback; var tmp = commandObj.callback
commandObj.callback = tmp ? commandObj.callback = tmp
function (e, r) { ? function (e, r) {
tmp(e, r); tmp(e, r)
callbackOrEmit(self, callback, err, res); callbackOrEmit(self, callback, err, res)
} : }
function (e, r) { : function (e) {
if (e) { if (e) {
self.emit('error', e); self.emit('error', e)
} }
callbackOrEmit(self, callback, err, res); callbackOrEmit(self, callback, err, res)
}; }
} }
} }
module.exports = { module.exports = {
replyToStrings: replyToStrings, replyToStrings: replyToStrings,
replyToObject: replyToObject, replyToObject: replyToObject,
errCode: /^([A-Z]+)\s+(.+)$/, errCode: /^([A-Z]+)\s+(.+)$/,
monitorRegex: /^[0-9]{10,11}\.[0-9]+ \[[0-9]+ .+\]( ".+?")+$/, monitorRegex: /^[0-9]{10,11}\.[0-9]+ \[[0-9]+ .+]( ".+?")+$/,
clone: convenienceClone, clone: convenienceClone,
callbackOrEmit: callbackOrEmit, callbackOrEmit: callbackOrEmit,
replyInOrder: replyInOrder replyInOrder: replyInOrder
}; }

View File

@@ -23,12 +23,13 @@
"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": "standard --fix"
}, },
"dependencies": { "dependencies": {
"double-ended-queue": "^2.1.0-0", "double-ended-queue": "^2.1.0-0",
"redis-commands": "^1.2.0", "redis-commands": "^1.2.0",
"redis-parser": "^2.6.0" "redis-parser": "^2.6.0",
"safe-buffer": "^5.0.1"
}, },
"engines": { "engines": {
"node": ">=6" "node": ">=6"
@@ -49,6 +50,11 @@
"type": "git", "type": "git",
"url": "git://github.com/NodeRedis/node_redis.git" "url": "git://github.com/NodeRedis/node_redis.git"
}, },
"standard": {
"envs": [
"mocha"
]
},
"bugs": { "bugs": {
"url": "https://github.com/NodeRedis/node_redis/issues" "url": "https://github.com/NodeRedis/node_redis/issues"
}, },

View File

@@ -1,347 +1,351 @@
'use strict'; 'use strict'
var assert = require('assert'); var assert = require('assert')
var config = require('./lib/config'); var config = require('./lib/config')
var helper = require('./helper'); var helper = require('./helper')
var redis = config.redis; var redis = config.redis
if (process.platform === 'win32') { // TODO: Fix redis process spawn on windows
// TODO: Fix redis process spawn on windows if (process.platform !== 'win32') {
return; describe('client authentication', function () {
}
describe('client authentication', function () {
before(function (done) { before(function (done) {
helper.stopRedis(function () { helper.stopRedis(function () {
helper.startRedis('./conf/password.conf', done); helper.startRedis('./conf/password.conf', done)
}); })
}); })
helper.allTests({ helper.allTests({
allConnections: true allConnections: true
}, function (ip, args) { }, function (ip, args) {
describe('using ' + ip, function () {
var auth = 'porkchopsandwiches'
var client = null
describe('using ' + ip, function () { beforeEach(function () {
var auth = 'porkchopsandwiches'; client = null
var client = null; })
afterEach(function () {
// Explicitly ignore still running commands
// The ready command could still be running
client.end(false)
})
beforeEach(function () { it('allows auth to be provided with \'auth\' method', function (done) {
client = null; if (helper.redisProcess().spawnFailed()) this.skip()
});
afterEach(function () {
// Explicitly ignore still running commands
// The ready command could still be running
client.end(false);
});
it("allows auth to be provided with 'auth' method", function (done) { client = redis.createClient.apply(null, args)
if (helper.redisProcess().spawnFailed()) this.skip(); client.auth(auth, function (err, res) {
assert.strictEqual(null, err)
assert.strictEqual('OK', res.toString())
return done(err)
})
})
client = redis.createClient.apply(null, args); it('support redis 2.4 with retrying auth commands if still loading', function (done) {
client.auth(auth, function (err, res) { if (helper.redisProcess().spawnFailed()) this.skip()
assert.strictEqual(null, err);
assert.strictEqual('OK', res.toString());
return done(err);
});
});
it('support redis 2.4 with retrying auth commands if still loading', function (done) { client = redis.createClient.apply(null, args)
if (helper.redisProcess().spawnFailed()) this.skip(); var time = Date.now()
client.auth(auth, function (err, res) {
client = redis.createClient.apply(null, args); assert.strictEqual(err, null)
var time = Date.now(); assert.strictEqual('retry worked', res)
client.auth(auth, function (err, res) { var now = Date.now()
assert.strictEqual('retry worked', res); // Hint: setTimeout sometimes triggers early and therefore the value can be like one or two ms to early
var now = Date.now(); assert(now - time >= 98, 'Time should be above 100 ms (the reconnect time) and is ' + (now - time))
// Hint: setTimeout sometimes triggers early and therefore the value can be like one or two ms to early assert(now - time < 225, 'Time should be below 255 ms (the reconnect should only take a bit above 100 ms) and is ' + (now - time))
assert(now - time >= 98, 'Time should be above 100 ms (the reconnect time) and is ' + (now - time)); done()
assert(now - time < 225, 'Time should be below 255 ms (the reconnect should only take a bit above 100 ms) and is ' + (now - time)); })
done(); var tmp = client.commandQueue.get(0).callback
}); client.commandQueue.get(0).callback = function (err) {
var tmp = client.commandQueue.get(0).callback; assert.strictEqual(err, null)
client.commandQueue.get(0).callback = function (err, res) { client.auth = function (pass, callback) {
client.auth = function (pass, callback) { callback(null, 'retry worked')
callback(null, 'retry worked');
};
tmp(new Error('ERR redis is still LOADING'));
};
});
it('emits error when auth is bad without callback', function (done) {
if (helper.redisProcess().spawnFailed()) this.skip();
client = redis.createClient.apply(null, args);
client.once('error', function (err) {
assert.strictEqual(err.command, 'AUTH');
assert.ok(/ERR invalid password/.test(err.message));
return done();
});
client.auth(auth + 'bad');
});
it('returns an error when auth is bad (empty string) with a callback', function (done) {
if (helper.redisProcess().spawnFailed()) this.skip();
client = redis.createClient.apply(null, args);
client.auth('', function (err, res) {
assert.strictEqual(err.command, 'AUTH');
assert.ok(/ERR invalid password/.test(err.message));
done();
});
});
if (ip === 'IPv4') {
it('allows auth to be provided as part of redis url and do not fire commands before auth is done', function (done) {
if (helper.redisProcess().spawnFailed()) this.skip();
var end = helper.callFuncAfter(done, 2);
client = redis.createClient('redis://:' + auth + '@' + config.HOST[ip] + ':' + config.PORT);
client.on('ready', function () {
end();
});
// The info command may be used while loading but not if not yet authenticated
client.info(function (err, res) {
assert(!err);
end();
});
});
it('allows auth and database to be provided as part of redis url query parameter', function (done) {
if (helper.redisProcess().spawnFailed()) this.skip();
client = redis.createClient('redis://' + config.HOST[ip] + ':' + config.PORT + '?db=2&password=' + auth);
assert.strictEqual(client.options.db, '2');
assert.strictEqual(client.options.password, auth);
assert.strictEqual(client.authPass, auth);
client.on('ready', function () {
// Set a key so the used database is returned in the info command
client.set('foo', 'bar');
client.get('foo');
assert.strictEqual(client.serverInfo.db2, undefined);
// Using the info command should update the serverInfo
client.info(function (err, res) {
assert(typeof client.serverInfo.db2 === 'object');
});
client.flushdb(done);
});
});
} }
tmp(new Error('ERR redis is still LOADING'))
}
})
it('allows auth to be provided as config option for client', function (done) { it('emits error when auth is bad without callback', function (done) {
if (helper.redisProcess().spawnFailed()) this.skip(); if (helper.redisProcess().spawnFailed()) this.skip()
var args = config.configureClient(ip, { client = redis.createClient.apply(null, args)
authPass: auth
});
client = redis.createClient.apply(null, args);
client.on('ready', done);
});
it('allows auth and noReadyCheck to be provided as config option for client', function (done) { client.once('error', function (err) {
if (helper.redisProcess().spawnFailed()) this.skip(); assert.strictEqual(err.command, 'AUTH')
assert.ok(/ERR invalid password/.test(err.message))
return done()
})
var args = config.configureClient(ip, { client.auth(auth + 'bad')
password: auth, })
noReadyCheck: true
});
client = redis.createClient.apply(null, args);
client.on('ready', done);
});
it('allows auth to be provided post-hoc with auth method', function (done) { it('returns an error when auth is bad (empty string) with a callback', function (done) {
if (helper.redisProcess().spawnFailed()) this.skip(); if (helper.redisProcess().spawnFailed()) this.skip()
var args = config.configureClient(ip); client = redis.createClient.apply(null, args)
client = redis.createClient.apply(null, args);
client.auth(auth);
client.on('ready', done);
});
it('reconnects with appropriate authentication while offline commands are present', function (done) { client.auth('', function (err) {
if (helper.redisProcess().spawnFailed()) this.skip(); assert.strictEqual(err.command, 'AUTH')
assert.ok(/ERR invalid password/.test(err.message))
done()
})
})
client = redis.createClient.apply(null, args); if (ip === 'IPv4') {
client.auth(auth); it('allows auth to be provided as part of redis url and do not fire commands before auth is done', function (done) {
client.on('ready', function () { if (helper.redisProcess().spawnFailed()) this.skip()
if (this.timesConnected < 3) {
var interval = setInterval(function () {
if (client.commandQueue.length !== 0) {
return;
}
clearInterval(interval);
interval = null;
client.stream.destroy();
client.set('foo', 'bar');
client.get('foo'); // Errors would bubble
assert.strictEqual(client.offlineQueue.length, 2);
}, 1);
} else {
done();
}
});
client.on('reconnecting', function (params) {
assert.strictEqual(params.error, null);
});
});
it('should return an error if the password is not correct and a callback has been provided', function (done) { var end = helper.callFuncAfter(done, 2)
if (helper.redisProcess().spawnFailed()) this.skip(); client = redis.createClient('redis://:' + auth + '@' + config.HOST[ip] + ':' + config.PORT)
client.on('ready', function () {
end()
})
// The info command may be used while loading but not if not yet authenticated
client.info(function (err) {
assert.strictEqual(err, null)
end(err)
})
})
client = redis.createClient.apply(null, args); it('allows auth and database to be provided as part of redis url query parameter', function (done) {
var async = true; if (helper.redisProcess().spawnFailed()) this.skip()
client.auth(undefined, function (err, res) {
assert.strictEqual(err.message, 'ERR invalid password');
assert.strictEqual(err.command, 'AUTH');
assert.strictEqual(res, undefined);
async = false;
done();
});
assert(async);
});
it('should emit an error if the password is not correct and no callback has been provided', function (done) { client = redis.createClient('redis://' + config.HOST[ip] + ':' + config.PORT + '?db=2&password=' + auth)
if (helper.redisProcess().spawnFailed()) this.skip(); assert.strictEqual(client.options.db, '2')
assert.strictEqual(client.options.password, auth)
assert.strictEqual(client.authPass, auth)
client.on('ready', function () {
// Set a key so the used database is returned in the info command
client.set('foo', 'bar')
client.get('foo')
assert.strictEqual(client.serverInfo.db2, undefined)
// Using the info command should update the serverInfo
client.info(function (err) {
assert.strictEqual(err, null)
assert(typeof client.serverInfo.db2 === 'object')
})
client.flushdb(done)
})
})
}
client = redis.createClient.apply(null, args); it('allows auth to be provided as config option for client', function (done) {
client.on('error', function (err) { if (helper.redisProcess().spawnFailed()) this.skip()
assert.strictEqual(err.message, 'ERR invalid password');
assert.strictEqual(err.command, 'AUTH');
done();
});
client.auth(234567);
});
it('allows auth to be provided post-hoc with auth method again', function (done) { var args = config.configureClient(ip, {
if (helper.redisProcess().spawnFailed()) this.skip(); authPass: auth
})
client = redis.createClient.apply(null, args)
client.on('ready', done)
})
var args = config.configureClient(ip, { it('allows auth and noReadyCheck to be provided as config option for client', function (done) {
authPass: auth if (helper.redisProcess().spawnFailed()) this.skip()
});
client = redis.createClient.apply(null, args);
client.on('ready', function () {
client.auth(auth, helper.isString('OK', done));
});
});
it('does not allow any commands to be processed if not authenticated using noReadyCheck true', function (done) { var args = config.configureClient(ip, {
if (helper.redisProcess().spawnFailed()) this.skip(); password: auth,
noReadyCheck: true
})
client = redis.createClient.apply(null, args)
client.on('ready', done)
})
var args = config.configureClient(ip, { it('allows auth to be provided post-hoc with auth method', function (done) {
noReadyCheck: true if (helper.redisProcess().spawnFailed()) this.skip()
});
client = redis.createClient.apply(null, args);
client.on('ready', function () {
client.set('foo', 'bar', function (err, res) {
assert.equal(err.message, 'NOAUTH Authentication required.');
assert.equal(err.code, 'NOAUTH');
assert.equal(err.command, 'SET');
done();
});
});
});
it('does not allow auth to be provided post-hoc with auth method if not authenticated before', function (done) { var args = config.configureClient(ip)
if (helper.redisProcess().spawnFailed()) this.skip(); client = redis.createClient.apply(null, args)
client = redis.createClient.apply(null, args); client.auth(auth)
client.on('error', function (err) { client.on('ready', done)
assert.equal(err.code, 'NOAUTH'); })
assert.equal(err.message, 'Ready check failed: NOAUTH Authentication required.');
assert.equal(err.command, 'INFO');
done();
});
});
it('should emit an error if the provided password is faulty', function (done) { it('reconnects with appropriate authentication while offline commands are present', function (done) {
if (helper.redisProcess().spawnFailed()) this.skip(); if (helper.redisProcess().spawnFailed()) this.skip()
client = redis.createClient({
password: 'wrongPassword'
});
client.once('error', function (err) {
assert.strictEqual(err.message, 'ERR invalid password');
done();
});
});
it('pubsub working with auth', function (done) { client = redis.createClient.apply(null, args)
if (helper.redisProcess().spawnFailed()) this.skip(); client.auth(auth)
client.on('ready', function () {
if (this.timesConnected < 3) {
var interval = setInterval(function () {
if (client.commandQueue.length !== 0) {
return
}
clearInterval(interval)
interval = null
client.stream.destroy()
client.set('foo', 'bar')
client.get('foo') // Errors would bubble
assert.strictEqual(client.offlineQueue.length, 2)
}, 1)
} else {
done()
}
})
client.on('reconnecting', function (params) {
assert.strictEqual(params.error, null)
})
})
var args = config.configureClient(ip, { it('should return an error if the password is not correct and a callback has been provided', function (done) {
password: auth if (helper.redisProcess().spawnFailed()) this.skip()
});
client = redis.createClient.apply(null, args);
client.set('foo', 'bar');
client.subscribe('somechannel', 'another channel', function (err, res) {
client.once('ready', function () {
assert.strictEqual(client.pubSubMode, 1);
client.get('foo', function (err, res) {
assert(/ERR only \(P\)SUBSCRIBE \/ \(P\)UNSUBSCRIBE/.test(err.message));
done();
});
});
});
client.once('ready', function () {
// Coherent behavior with all other offline commands fires commands before emitting but does not wait till they return
assert.strictEqual(client.pubSubMode, 2);
client.ping(function () { // Make sure all commands were properly processed already
client.stream.destroy();
});
});
});
it('individual commands work properly with batch', function (done) { client = redis.createClient.apply(null, args)
// quit => might return an error instead of "OK" in the exec callback... (if not connected) var async = true
// auth => might return an error instead of "OK" in the exec callback... (if no password is required / still loading on Redis <= 2.4) client.auth(undefined, function (err, res) {
// This could be fixed by checking the return value of the callback in the exec callback and assert.strictEqual(err.message, 'ERR invalid password')
// returning the manipulated [error, result] from the callback. assert.strictEqual(err.command, 'AUTH')
// There should be a better solution though assert.strictEqual(res, undefined)
async = false
done()
})
assert(async)
})
var args = config.configureClient('localhost', { it('should emit an error if the password is not correct and no callback has been provided', function (done) {
noReadyCheck: true if (helper.redisProcess().spawnFailed()) this.skip()
});
client = redis.createClient.apply(null, args); client = redis.createClient.apply(null, args)
assert.strictEqual(client.selectedDb, undefined); client.on('error', function (err) {
var end = helper.callFuncAfter(done, 8); assert.strictEqual(err.message, 'ERR invalid password')
client.on('monitor', function () { assert.strictEqual(err.command, 'AUTH')
end(); // Should be called for each command after monitor done()
}); })
client.batch() client.auth(234567)
.auth(auth) })
.select(5, function (err, res) {
assert.strictEqual(client.selectedDb, 5); it('allows auth to be provided post-hoc with auth method again', function (done) {
assert.strictEqual(res, 'OK'); if (helper.redisProcess().spawnFailed()) this.skip()
assert.notDeepEqual(client.serverInfo.db5, { avgTtl: 0, expires: 0, keys: 1 });
}) var args = config.configureClient(ip, {
.monitor() authPass: auth
.set('foo', 'bar', helper.isString('OK')) })
.info('stats', function (err, res) { client = redis.createClient.apply(null, args)
assert.strictEqual(res.indexOf('# Stats\r\n'), 0); client.on('ready', function () {
assert.strictEqual(client.serverInfo.sync_full, '0'); client.auth(auth, helper.isString('OK', done))
}) })
.get('foo', helper.isString('bar')) })
.subscribe(['foo', 'bar', 'foo'], helper.isUnSubscribe(2, ['foo', 'bar', 'foo']))
.unsubscribe('foo') it('does not allow any commands to be processed if not authenticated using noReadyCheck true', function (done) {
.subscribe('/foo', helper.isUnSubscribe(2, '/foo')) if (helper.redisProcess().spawnFailed()) this.skip()
.psubscribe('*')
.quit(helper.isString('OK')) var args = config.configureClient(ip, {
.exec(function (err, res) { noReadyCheck: true
res[4] = res[4].substr(0, 9); })
assert.deepStrictEqual( client = redis.createClient.apply(null, args)
res, client.on('ready', function () {
['OK', 'OK', 'OK', 'OK', '# Stats\r\n', 'bar', [2, ['foo', 'bar', 'foo']], [1, ['foo']], [2, ['/foo']], [3, ['*']], 'OK'] client.set('foo', 'bar', function (err) {
); assert.strictEqual(err.message, 'NOAUTH Authentication required.')
end(); assert.strictEqual(err.code, 'NOAUTH')
}); assert.strictEqual(err.command, 'SET')
}); done()
}); })
}); })
})
it('does not allow auth to be provided post-hoc with auth method if not authenticated before', function (done) {
if (helper.redisProcess().spawnFailed()) this.skip()
client = redis.createClient.apply(null, args)
client.on('error', function (err) {
assert.strictEqual(err.code, 'NOAUTH')
assert.strictEqual(err.message, 'Ready check failed: NOAUTH Authentication required.')
assert.strictEqual(err.command, 'INFO')
done()
})
})
it('should emit an error if the provided password is faulty', function (done) {
if (helper.redisProcess().spawnFailed()) this.skip()
client = redis.createClient({
password: 'wrongPassword'
})
client.once('error', function (err) {
assert.strictEqual(err.message, 'ERR invalid password')
done()
})
})
it('pubsub working with auth', function (done) {
if (helper.redisProcess().spawnFailed()) this.skip()
var args = config.configureClient(ip, {
password: auth
})
client = redis.createClient.apply(null, args)
client.set('foo', 'bar')
client.subscribe('somechannel', 'another channel', function (err) {
assert.strictEqual(err, null)
client.once('ready', function () {
assert.strictEqual(client.pubSubMode, 1)
client.get('foo', function (err) {
assert(/ERR only \(P\)SUBSCRIBE \/ \(P\)UNSUBSCRIBE/.test(err.message))
done()
})
})
})
client.once('ready', function () {
// Coherent behavior with all other offline commands fires commands before emitting but does not wait till they return
assert.strictEqual(client.pubSubMode, 2)
client.ping(function () { // Make sure all commands were properly processed already
client.stream.destroy()
})
})
})
it('individual commands work properly with batch', function (done) {
// quit => might return an error instead of "OK" in the exec callback... (if not connected)
// auth => might return an error instead of "OK" in the exec callback... (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
var args = config.configureClient('localhost', {
noReadyCheck: true
})
client = redis.createClient.apply(null, args)
assert.strictEqual(client.selectedDb, undefined)
var end = helper.callFuncAfter(done, 8)
client.on('monitor', function () {
end() // Should be called for each command after monitor
})
client.batch()
.auth(auth)
.select(5, function (err, res) {
assert.strictEqual(err, null)
assert.strictEqual(client.selectedDb, 5)
assert.strictEqual(res, 'OK')
assert.notDeepEqual(client.serverInfo.db5, { avgTtl: 0, expires: 0, keys: 1 })
})
.monitor()
.set('foo', 'bar', helper.isString('OK'))
.info('stats', function (err, res) {
assert.strictEqual(err, null)
assert.strictEqual(res.indexOf('# Stats\r\n'), 0)
assert.strictEqual(client.serverInfo.sync_full, '0')
})
.get('foo', helper.isString('bar'))
.subscribe(['foo', 'bar', 'foo'], helper.isDeepEqual([2, ['foo', 'bar', 'foo']]))
.unsubscribe('foo')
.subscribe('/foo', helper.isDeepEqual([2, ['/foo']]))
.psubscribe('*')
.quit(helper.isString('OK'))
.exec(function (err, res) {
assert.strictEqual(err, null)
res[4] = res[4].substr(0, 9)
assert.deepStrictEqual(
res,
['OK', 'OK', 'OK', 'OK', '# Stats\r\n', 'bar', [2, ['foo', 'bar', 'foo']], [1, ['foo']], [2, ['/foo']], [3, ['*']], 'OK']
)
end()
})
})
})
})
after(function (done) { after(function (done) {
if (helper.redisProcess().spawnFailed()) return done(); if (helper.redisProcess().spawnFailed()) return done()
helper.stopRedis(function () { helper.stopRedis(function () {
helper.startRedis('./conf/redis.conf', done); helper.startRedis('./conf/redis.conf', done)
}); })
}); })
}); })
}

View File

@@ -1,350 +1,331 @@
'use strict'; 'use strict'
var assert = require('assert'); var assert = require('assert')
var config = require('./lib/config'); var config = require('./lib/config')
var helper = require('./helper'); var helper = require('./helper')
var redis = config.redis; var redis = config.redis
describe("The 'batch' method", function () { describe('The \'batch\' method', function () {
helper.allTests(function (ip, args) {
describe('using ' + ip, function () {
describe('when not connected', function () {
var client
helper.allTests(function (ip, args) { beforeEach(function (done) {
client = redis.createClient.apply(null, args)
client.once('connect', function () {
client.quit()
})
client.on('end', done)
})
describe('using ' + ip, function () { it('returns an empty array for missing commands', function (done) {
var batch = client.batch()
batch.exec(function (err, res) {
assert.strictEqual(err, null)
assert.strictEqual(res.length, 0)
done()
})
})
describe('when not connected', function () { it('returns an error for batch with commands', function (done) {
var client; var batch = client.batch()
batch.set('foo', 'bar')
batch.exec(function (err, res) {
assert.strictEqual(err, null)
assert.strictEqual(res[0].code, 'NR_CLOSED')
done()
})
})
beforeEach(function (done) { it('returns an empty array for missing commands if promisified', function () {
client = redis.createClient.apply(null, args); return client.batch().execAsync().then(function (res) {
client.once('connect', function () { assert.strictEqual(res.length, 0)
client.quit(); })
}); })
client.on('end', done); })
});
it('returns an empty array for missing commands', function (done) { describe('when connected', function () {
var batch = client.batch(); var client
batch.exec(function (err, res) {
assert.strictEqual(err, null);
assert.strictEqual(res.length, 0);
done();
});
});
it('returns an error for batch with commands', function (done) { beforeEach(function (done) {
var batch = client.batch(); client = redis.createClient.apply(null, args)
batch.set('foo', 'bar'); client.once('ready', function () {
batch.exec(function (err, res) { client.flushdb(function (err) {
assert.strictEqual(err, null); return done(err)
assert.strictEqual(res[0].code, 'NR_CLOSED'); })
done(); })
}); })
});
it('returns an empty array for missing commands if promisified', function () { afterEach(function () {
return client.batch().execAsync().then(function (res) { client.end(true)
assert.strictEqual(res.length, 0); })
});
});
});
describe('when connected', function () { it('returns an empty array and keep the execution order in tact', function (done) {
var client; var called = false
client.set('foo', 'bar', function () {
called = true
})
var batch = client.batch()
batch.exec(function (err, res) {
assert.strictEqual(err, null)
assert.strictEqual(res.length, 0)
assert(called)
done()
})
})
beforeEach(function (done) { it('runs normal calls in-between batch', function (done) {
client = redis.createClient.apply(null, args); var batch = client.batch()
client.once('ready', function () { batch.set('m1', '123')
client.flushdb(function (err) { client.set('m2', '456', done)
return done(err); })
});
});
});
afterEach(function () { it('returns an empty array if promisified', function () {
client.end(true); return client.batch().execAsync().then(function (res) {
}); assert.strictEqual(res.length, 0)
})
})
it('returns an empty array and keep the execution order in tact', function (done) { it('returns an empty result array', function (done) {
var called = false; var batch = client.batch()
client.set('foo', 'bar', function (err, res) { var async = true
called = true; var notBuffering = batch.exec(function (err, res) {
}); assert.strictEqual(err, null)
var batch = client.batch(); assert.strictEqual(res.length, 0)
batch.exec(function (err, res) { async = false
assert.strictEqual(err, null); done()
assert.strictEqual(res.length, 0); })
assert(called); assert(async)
done(); assert.strictEqual(notBuffering, true)
}); })
});
it('runs normal calls in-between batch', function (done) { it('fail individually when one command fails using chaining notation', function (done) {
var batch = client.batch(); var batch1, batch2
batch.set('m1', '123'); batch1 = client.batch()
client.set('m2', '456', done); batch1.mset('batchfoo', '10', 'batchbar', '20', helper.isString('OK'))
});
it('returns an empty array if promisified', function () { // Provoke an error at queue time
return client.batch().execAsync().then(function (res) { batch1.set('foo2', helper.isError())
assert.strictEqual(res.length, 0); batch1.incr('batchfoo')
}); batch1.incr('batchbar')
}); batch1.exec(function () {
// Confirm that the previous command, while containing an error, still worked.
batch2 = client.batch()
batch2.get('foo2', helper.isNull())
batch2.incr('batchbar', helper.isNumber(22))
batch2.incr('batchfoo', helper.isNumber(12))
batch2.exec(function (err, replies) {
assert.strictEqual(err, null)
assert.strictEqual(null, replies[0])
assert.strictEqual(22, replies[1])
assert.strictEqual(12, replies[2])
return done()
})
})
})
it('returns an empty result array', function (done) { it('fail individually when one command fails and emit the error if no callback has been provided', function (done) {
var batch = client.batch(); var batch1
var async = true; client.on('error', function (err) {
var notBuffering = batch.exec(function (err, res) { done(err)
assert.strictEqual(err, null); })
assert.strictEqual(res.length, 0); batch1 = client.batch()
async = false; batch1.mset('batchfoo', '10', 'batchbar', '20', helper.isString('OK'))
done();
});
assert(async);
assert.strictEqual(notBuffering, true);
});
it('fail individually when one command fails using chaining notation', function (done) { // Provoke an error at queue time
var batch1, batch2; batch1.set('foo2')
batch1 = client.batch(); batch1.incr('batchfoo')
batch1.mset('batchfoo', '10', 'batchbar', '20', helper.isString('OK')); batch1.incr('batchbar')
batch1.exec(function (err, res) {
// TODO: This should actually return an error!
assert.strictEqual(err, null)
assert.strictEqual(res[1].command, 'SET')
assert.strictEqual(res[1].code, 'ERR')
done()
})
})
// Provoke an error at queue time it('fail individually when one command in an array of commands fails', function (done) {
batch1.set('foo2', helper.isError()); // test nested batch-bulk replies
batch1.incr('batchfoo'); client.batch([
batch1.incr('batchbar'); ['mget', 'batchfoo', 'batchbar', helper.isDeepEqual([null, null])],
batch1.exec(function () { ['set', 'foo2', helper.isError()],
// Confirm that the previous command, while containing an error, still worked. ['incr', 'batchfoo'],
batch2 = client.batch(); ['incr', 'batchbar']
batch2.get('foo2', helper.isNull()); ]).exec(function (err, replies) {
batch2.incr('batchbar', helper.isNumber(22)); // TODO: This should actually return an error!
batch2.incr('batchfoo', helper.isNumber(12)); assert.strictEqual(err, null)
batch2.exec(function (err, replies) { assert.strictEqual(2, replies[0].length)
assert.strictEqual(null, replies[0]); assert.strictEqual(null, replies[0][0])
assert.strictEqual(22, replies[1]); assert.strictEqual(null, replies[0][1])
assert.strictEqual(12, replies[2]); assert.strictEqual('SET', replies[1].command)
return done(); assert.strictEqual('1', replies[2].toString())
}); assert.strictEqual('1', replies[3].toString())
}); return done()
}); })
})
it('fail individually when one command fails and emit the error if no callback has been provided', function (done) { it('handles multiple operations being applied to a set', function (done) {
var batch1; client.sadd('some set', 'mem 1')
client.on('error', function (err) { client.sadd(['some set', 'mem 2'])
done(err); client.sadd('some set', 'mem 3')
}); client.sadd('some set', 'mem 4')
batch1 = client.batch();
batch1.mset('batchfoo', '10', 'batchbar', '20', helper.isString('OK'));
// Provoke an error at queue time // make sure empty mb reply works
batch1.set('foo2'); client.del('some missing set')
batch1.incr('batchfoo'); client.smembers('some missing set', function (err, reply) {
batch1.incr('batchbar'); assert.strictEqual(err, null)
batch1.exec(function (err, res) { // make sure empty mb reply works
assert.strictEqual(res[1].command, 'SET'); assert.strictEqual(0, reply.length)
assert.strictEqual(res[1].code, 'ERR'); })
done();
});
});
it('fail individually when one command in an array of commands fails', function (done) { // test nested batch-bulk replies with empty mb elements.
// test nested batch-bulk replies client.batch([
client.batch([ ['smembers', ['some set']],
['mget', 'batchfoo', 'batchbar', function (err, res) { ['del', 'some set'],
assert.strictEqual(2, res.length); ['smembers', 'some set', undefined] // The explicit undefined is handled as a callback that is undefined
assert.strictEqual(0, +res[0]); ])
assert.strictEqual(0, +res[1]); .scard('some set')
}], .exec(function (err, replies) {
['set', 'foo2', helper.isError()], assert.strictEqual(err, null)
['incr', 'batchfoo'], assert.strictEqual(4, replies[0].length)
['incr', 'batchbar'] assert.strictEqual(0, replies[2].length)
]).exec(function (err, replies) { return done()
assert.strictEqual(2, replies[0].length); })
assert.strictEqual(null, replies[0][0]); })
assert.strictEqual(null, replies[0][1]);
assert.strictEqual('SET', replies[1].command);
assert.strictEqual('1', replies[2].toString());
assert.strictEqual('1', replies[3].toString());
return done();
});
});
it('handles multiple operations being applied to a set', function (done) { it('allows multiple operations to be performed using constructor with all kinds of syntax', function (done) {
client.sadd('some set', 'mem 1'); var now = Date.now()
client.sadd(['some set', 'mem 2']); var arr = ['batchhmset', 'batchbar', 'batchbaz']
client.sadd('some set', 'mem 3'); var arr2 = ['some manner of key', 'otherTypes']
client.sadd('some set', 'mem 4'); var arr3 = [5768, 'batchbarx', 'batchfoox']
var arr4 = ['mset', [578, 'batchbar'], helper.isString('OK')]
client.batch([
arr4,
[['mset', 'batchfoo2', 'batchbar2', 'batchfoo3', 'batchbar3'], helper.isString('OK')],
['hmset', arr],
[['hmset', 'batchhmset2', 'batchbar2', 'batchfoo3', 'batchbar3', 'test'], helper.isString('OK')],
['hmset', ['batchhmset', 'batchbar', 'batchfoo'], helper.isString('OK')],
['hmset', arr3, helper.isString('OK')],
['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}, helper.isString('OK')],
['hmset', 'batchhmset', ['batchbar', 'batchbaz']],
['hmset', 'batchhmset', ['batchbar', 'batchbaz'], helper.isString('OK')]
])
.hmget(now, 123456789, 'otherTypes')
.hmget('key2', arr2, function noop () {})
.hmget(['batchhmset2', 'some manner of key', 'batchbar3'])
.mget('batchfoo2', ['batchfoo3', 'batchfoo'], function (err, res) {
assert.strictEqual(err, null)
assert.strictEqual(res[0], 'batchbar2')
assert.strictEqual(res[1], 'batchbar3')
assert.strictEqual(res[2], null)
})
.exec(function (err, replies) {
assert.strictEqual(arr.length, 3)
assert.strictEqual(arr2.length, 2)
assert.strictEqual(arr3.length, 3)
assert.strictEqual(arr4.length, 3)
assert.strictEqual(null, err)
assert.strictEqual(replies[10][1], '555')
assert.strictEqual(replies[11][0], 'a type of value')
assert.strictEqual(replies[12][0], null)
assert.strictEqual(replies[12][1], 'test')
assert.strictEqual(replies[13][0], 'batchbar2')
assert.strictEqual(replies[13].length, 3)
assert.strictEqual(replies.length, 14)
return done()
})
})
// make sure empty mb reply works it('converts a non string key to a string', function (done) {
client.del('some missing set'); // TODO: Converting the key might change soon again.
client.smembers('some missing set', function (err, reply) { client.batch().hmset(true, {
// make sure empty mb reply works test: 123,
assert.strictEqual(0, reply.length); bar: 'baz'
}); }).exec(done)
})
// test nested batch-bulk replies with empty mb elements. it('runs a batch without any further commands', function (done) {
client.batch([ var buffering = client.batch().exec(function (err, res) {
['smembers', ['some set']], assert.strictEqual(err, null)
['del', 'some set'], assert.strictEqual(res.length, 0)
['smembers', 'some set', undefined] // The explicit undefined is handled as a callback that is undefined done()
]) })
.scard('some set') assert(typeof buffering === 'boolean')
.exec(function (err, replies) { })
assert.strictEqual(4, replies[0].length);
assert.strictEqual(0, replies[2].length);
return done();
});
});
it('allows multiple operations to be performed using constructor with all kinds of syntax', function (done) { it('runs a batch without any further commands and without callback', function () {
var now = Date.now(); var buffering = client.batch().exec()
var arr = ['batchhmset', 'batchbar', 'batchbaz']; assert.strictEqual(buffering, true)
var arr2 = ['some manner of key', 'otherTypes']; })
var arr3 = [5768, 'batchbarx', 'batchfoox'];
var arr4 = ['mset', [578, 'batchbar'], helper.isString('OK')];
client.batch([
arr4,
[['mset', 'batchfoo2', 'batchbar2', 'batchfoo3', 'batchbar3'], helper.isString('OK')],
['hmset', arr],
[['hmset', 'batchhmset2', 'batchbar2', 'batchfoo3', 'batchbar3', 'test'], helper.isString('OK')],
['hmset', ['batchhmset', 'batchbar', 'batchfoo'], helper.isString('OK')],
['hmset', arr3, helper.isString('OK')],
['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}, helper.isString('OK')],
['hmset', 'batchhmset', ['batchbar', 'batchbaz']],
['hmset', 'batchhmset', ['batchbar', 'batchbaz'], helper.isString('OK')],
])
.hmget(now, 123456789, 'otherTypes')
.hmget('key2', arr2, function noop () {})
.hmget(['batchhmset2', 'some manner of key', 'batchbar3'])
.mget('batchfoo2', ['batchfoo3', 'batchfoo'], function (err, res) {
assert.strictEqual(res[0], 'batchbar2');
assert.strictEqual(res[1], 'batchbar3');
assert.strictEqual(res[2], null);
})
.exec(function (err, replies) {
assert.equal(arr.length, 3);
assert.equal(arr2.length, 2);
assert.equal(arr3.length, 3);
assert.equal(arr4.length, 3);
assert.strictEqual(null, err);
assert.equal(replies[10][1], '555');
assert.equal(replies[11][0], 'a type of value');
assert.strictEqual(replies[12][0], null);
assert.equal(replies[12][1], 'test');
assert.equal(replies[13][0], 'batchbar2');
assert.equal(replies[13].length, 3);
assert.equal(replies.length, 14);
return done();
});
});
it('converts a non string key to a string', function (done) { it('allows multiple operations to be performed using a chaining API', function (done) {
// TODO: Converting the key might change soon again. client.batch()
client.batch().hmset(true, { .mset('some', '10', 'keys', '20')
test: 123, .incr('some')
bar: 'baz' .incr('keys')
}).exec(done); .mget('some', 'keys')
}); .exec(helper.isDeepEqual(['OK', 11, 21, ['11', '21']], done))
})
it('runs a batch without any further commands', function (done) { it('allows multiple commands to work the same as normal to be performed using a chaining API', function (done) {
var buffering = client.batch().exec(function (err, res) { client.batch()
assert.strictEqual(err, null); .mset(['some', '10', 'keys', '20'])
assert.strictEqual(res.length, 0); .incr('some', helper.isNumber(11))
done(); .incr(['keys'], helper.isNumber(21))
}); .mget('some', 'keys')
assert(typeof buffering === 'boolean'); .exec(helper.isDeepEqual(['OK', 11, 21, ['11', '21']], done))
}); })
it('runs a batch without any further commands and without callback', function () { it('allows multiple commands to work the same as normal to be performed using a chaining API promisified', function () {
var buffering = client.batch().exec(); return client.batch()
assert.strictEqual(buffering, true); .mset(['some', '10', 'keys', '20'])
}); .incr('some', helper.isNumber(11))
.incr(['keys'], helper.isNumber(21))
.mget('some', 'keys')
.execAsync()
.then(function (res) {
helper.isDeepEqual(['OK', 11, 21, ['11', '21']])(null, res)
})
})
it('allows multiple operations to be performed using a chaining API', function (done) { it('allows an array to be provided indicating multiple operations to perform', function (done) {
client.batch() // test nested batch-bulk replies with nulls.
.mset('some', '10', 'keys', '20') client.batch([
.incr('some') ['mget', ['batchfoo', 'some', 'random value', 'keys']],
.incr('keys') ['incr', 'batchfoo']
.mget('some', 'keys') ])
.exec(function (err, replies) { .exec(function (err, replies) {
assert.strictEqual(null, err); assert.strictEqual(err, null)
assert.equal('OK', replies[0]); assert.strictEqual(replies.length, 2)
assert.equal(11, replies[1]); assert.strictEqual(replies[0].length, 4)
assert.equal(21, replies[2]); return done()
assert.equal(11, replies[3][0].toString()); })
assert.equal(21, replies[3][1].toString()); })
return done();
});
});
it('allows multiple commands to work the same as normal to be performed using a chaining API', function (done) { it('allows multiple operations to be performed on a hash', function (done) {
client.batch() client.batch()
.mset(['some', '10', 'keys', '20']) .hmset('batchhash', 'a', 'foo', 'b', 1)
.incr('some', helper.isNumber(11)) .hmset('batchhash', {
.incr(['keys'], helper.isNumber(21)) extra: 'fancy',
.mget('some', 'keys') things: 'here'
.exec(function (err, replies) { })
assert.strictEqual(null, err); .hgetall('batchhash')
assert.equal('OK', replies[0]); .exec(done)
assert.equal(11, replies[1]); })
assert.equal(21, replies[2]);
assert.equal(11, replies[3][0].toString());
assert.equal(21, replies[3][1].toString());
return done();
});
});
it('allows multiple commands to work the same as normal to be performed using a chaining API promisified', function () { it('should work without any callback or arguments', function (done) {
return client.batch() var batch = client.batch()
.mset(['some', '10', 'keys', '20']) batch.set('baz', 'binary')
.incr('some', helper.isNumber(11)) batch.set('foo', 'bar')
.incr(['keys'], helper.isNumber(21)) batch.ping()
.mget('some', 'keys') batch.exec()
.execAsync()
.then(function (replies) {
assert.equal('OK', replies[0]);
assert.equal(11, replies[1]);
assert.equal(21, replies[2]);
assert.equal(11, replies[3][0].toString());
assert.equal(21, replies[3][1].toString());
});
});
it('allows an array to be provided indicating multiple operations to perform', function (done) { client.get('foo', helper.isString('bar', done))
// test nested batch-bulk replies with nulls. })
client.batch([ })
['mget', ['batchfoo', 'some', 'random value', 'keys']], })
['incr', 'batchfoo'] })
]) })
.exec(function (err, replies) {
assert.strictEqual(replies.length, 2);
assert.strictEqual(replies[0].length, 4);
return done();
});
});
it('allows multiple operations to be performed on a hash', function (done) {
client.batch()
.hmset('batchhash', 'a', 'foo', 'b', 1)
.hmset('batchhash', {
extra: 'fancy',
things: 'here'
})
.hgetall('batchhash')
.exec(done);
});
it('should work without any callback or arguments', function (done) {
var batch = client.batch();
batch.set('baz', 'binary');
batch.set('foo', 'bar');
batch.ping();
batch.exec();
client.get('foo', helper.isString('bar', done));
});
});
});
});
});

View File

@@ -1,77 +1,75 @@
'use strict'; 'use strict'
var assert = require('assert'); var assert = require('assert')
var config = require('../lib/config'); var config = require('../lib/config')
var helper = require('../helper'); var helper = require('../helper')
var redis = config.redis; var redis = config.redis
var intercept = require('intercept-stdout'); var intercept = require('intercept-stdout')
describe("The 'blpop' method", function () { describe('The \'blpop\' method', function () {
helper.allTests(function (ip, args) {
describe('using ' + ip, function () {
var client
var bclient
helper.allTests(function (ip, args) { beforeEach(function (done) {
client = redis.createClient.apply(null, args)
client.once('ready', function () {
client.flushdb(done)
})
})
describe('using ' + ip, function () { it('pops value immediately if list contains values', function (done) {
var client; bclient = redis.createClient.apply(null, args)
var bclient; redis.debugMode = true
var text = ''
var unhookIntercept = intercept(function (data) {
text += data
return ''
})
client.rpush('blocking list', 'initial value', helper.isNumber(1))
unhookIntercept()
assert(/^Send 127\.0\.0\.1:6379 id [0-9]+: \*3\r\n\$5\r\nrpush\r\n\$13\r\nblocking list\r\n\$13\r\ninitial value\r\n\n$/.test(text))
redis.debugMode = false
bclient.blpop('blocking list', 0, function (err, value) {
assert.strictEqual(value[0], 'blocking list')
assert.strictEqual(value[1], 'initial value')
return done(err)
})
})
beforeEach(function (done) { it('pops value immediately if list contains values using array notation', function (done) {
client = redis.createClient.apply(null, args); bclient = redis.createClient.apply(null, args)
client.once('ready', function () { client.rpush(['blocking list', 'initial value'], helper.isNumber(1))
client.flushdb(done); bclient.blpop(['blocking list', 0], function (err, value) {
}); assert.strictEqual(value[0], 'blocking list')
}); assert.strictEqual(value[1], 'initial value')
return done(err)
})
})
it('pops value immediately if list contains values', function (done) { it('waits for value if list is not yet populated', function (done) {
bclient = redis.createClient.apply(null, args); bclient = redis.createClient.apply(null, args)
redis.debugMode = true; bclient.blpop('blocking list 2', 5, function (err, value) {
var text = ''; assert.strictEqual(value[0], 'blocking list 2')
var unhookIntercept = intercept(function (data) { assert.strictEqual(value[1], 'initial value')
text += data; return done(err)
return ''; })
}); client.rpush('blocking list 2', 'initial value', helper.isNumber(1))
client.rpush('blocking list', 'initial value', helper.isNumber(1)); })
unhookIntercept();
assert(/^Send 127\.0\.0\.1:6379 id [0-9]+: \*3\r\n\$5\r\nrpush\r\n\$13\r\nblocking list\r\n\$13\r\ninitial value\r\n\n$/.test(text));
redis.debugMode = false;
bclient.blpop('blocking list', 0, function (err, value) {
assert.strictEqual(value[0], 'blocking list');
assert.strictEqual(value[1], 'initial value');
return done(err);
});
});
it('pops value immediately if list contains values using array notation', function (done) { it('times out after specified time', function (done) {
bclient = redis.createClient.apply(null, args); bclient = redis.createClient.apply(null, args)
client.rpush(['blocking list', 'initial value'], helper.isNumber(1)); bclient.blpop('blocking list', 1, function (err, res) {
bclient.blpop(['blocking list', 0], function (err, value) { assert.strictEqual(res, null)
assert.strictEqual(value[0], 'blocking list'); return done(err)
assert.strictEqual(value[1], 'initial value'); })
return done(err); })
});
});
it('waits for value if list is not yet populated', function (done) { afterEach(function () {
bclient = redis.createClient.apply(null, args); client.end(true)
bclient.blpop('blocking list 2', 5, function (err, value) { bclient.end(true)
assert.strictEqual(value[0], 'blocking list 2'); })
assert.strictEqual(value[1], 'initial value'); })
return done(err); })
}); })
client.rpush('blocking list 2', 'initial value', helper.isNumber(1));
});
it('times out after specified time', function (done) {
bclient = redis.createClient.apply(null, args);
bclient.blpop('blocking list', 1, function (err, res) {
assert.strictEqual(res, null);
return done(err);
});
});
afterEach(function () {
client.end(true);
bclient.end(true);
});
});
});
});

View File

@@ -1,155 +1,148 @@
'use strict'; 'use strict'
var assert = require('assert'); var Buffer = require('safe-buffer').Buffer
var config = require('../lib/config'); var assert = require('assert')
var helper = require('../helper'); var config = require('../lib/config')
var redis = config.redis; var helper = require('../helper')
var redis = config.redis
describe("The 'client' method", function () { describe('The \'client\' method', function () {
helper.allTests(function (ip, args) {
var pattern = /addr=/
helper.allTests(function (ip, args) { describe('using ' + ip, function () {
var pattern = /addr=/; var client
describe('using ' + ip, function () { beforeEach(function (done) {
var client; client = redis.createClient.apply(null, args)
client.once('ready', function () {
client.flushdb(done)
})
})
beforeEach(function (done) { afterEach(function () {
client = redis.createClient.apply(null, args); client.end(true)
client.once('ready', function () { })
client.flushdb(done);
});
});
afterEach(function () { describe('list', function () {
client.end(true); it('lists connected clients', function (done) {
}); client.client('LIST', helper.match(pattern, done))
})
describe('list', function () { it('lists connected clients when invoked with multi\'s chaining syntax', function (done) {
it('lists connected clients', function (done) { client.multi().client('list', helper.isType.string()).exec(helper.match(pattern, done))
client.client('LIST', helper.match(pattern, done)); })
});
it("lists connected clients when invoked with multi's chaining syntax", function (done) { it('lists connected clients when invoked with array syntax on client', function (done) {
client.multi().client('list', helper.isType.string()).exec(helper.match(pattern, done)); client.multi().client(['list']).exec(helper.match(pattern, done))
}); })
it('lists connected clients when invoked with array syntax on client', function (done) { it('lists connected clients when invoked with multi\'s array syntax', function (done) {
client.multi().client(['list']).exec(helper.match(pattern, done)); client.multi([
}); ['client', 'list']
]).exec(helper.match(pattern, done))
})
})
it("lists connected clients when invoked with multi's array syntax", function (done) { describe('reply', function () {
client.multi([ describe('as normal command', function () {
['client', 'list'] it('on', function (done) {
]).exec(helper.match(pattern, done)); helper.serverVersionAtLeast.call(this, client, [3, 2, 0])
}); assert.strictEqual(client.reply, 'ON')
}); client.client('reply', 'on', helper.isString('OK'))
assert.strictEqual(client.reply, 'ON')
client.set('foo', 'bar', done)
})
describe('reply', function () { it('off', function (done) {
describe('as normal command', function () { helper.serverVersionAtLeast.call(this, client, [3, 2, 0])
it('on', function (done) { assert.strictEqual(client.reply, 'ON')
helper.serverVersionAtLeast.call(this, client, [3, 2, 0]); client.client(Buffer.from('REPLY'), 'OFF', helper.isUndefined())
assert.strictEqual(client.reply, 'ON'); assert.strictEqual(client.reply, 'OFF')
client.client('reply', 'on', helper.isString('OK')); client.set('foo', 'bar', helper.isUndefined(done))
assert.strictEqual(client.reply, 'ON'); })
client.set('foo', 'bar', done);
});
it('off', function (done) { it('skip', function (done) {
helper.serverVersionAtLeast.call(this, client, [3, 2, 0]); helper.serverVersionAtLeast.call(this, client, [3, 2, 0])
assert.strictEqual(client.reply, 'ON'); assert.strictEqual(client.reply, 'ON')
client.client(new Buffer('REPLY'), 'OFF', helper.isUndefined()); client.client('REPLY', Buffer.from('SKIP'), helper.isUndefined())
assert.strictEqual(client.reply, 'OFF'); assert.strictEqual(client.reply, 'SKIP_ONE_MORE')
client.set('foo', 'bar', helper.isUndefined(done)); client.set('foo', 'bar', helper.isUndefined())
}); client.get('foo', helper.isString('bar', done))
})
})
it('skip', function (done) { describe('in a batch context', function () {
helper.serverVersionAtLeast.call(this, client, [3, 2, 0]); it('on', function (done) {
assert.strictEqual(client.reply, 'ON'); helper.serverVersionAtLeast.call(this, client, [3, 2, 0])
client.client('REPLY', new Buffer('SKIP'), helper.isUndefined()); var batch = client.batch()
assert.strictEqual(client.reply, 'SKIP_ONE_MORE'); assert.strictEqual(client.reply, 'ON')
client.set('foo', 'bar', helper.isUndefined()); batch.client('reply', 'on', helper.isString('OK'))
client.get('foo', helper.isString('bar', done)); assert.strictEqual(client.reply, 'ON')
}); batch.set('foo', 'bar')
}); batch.exec(function (err, res) {
assert.deepEqual(res, ['OK', 'OK'])
done(err)
})
})
describe('in a batch context', function () { it('off', function (done) {
it('on', function (done) { helper.serverVersionAtLeast.call(this, client, [3, 2, 0])
helper.serverVersionAtLeast.call(this, client, [3, 2, 0]); var batch = client.batch()
var batch = client.batch(); assert.strictEqual(client.reply, 'ON')
assert.strictEqual(client.reply, 'ON'); batch.set('hello', 'world')
batch.client('reply', 'on', helper.isString('OK')); batch.client(Buffer.from('REPLY'), Buffer.from('OFF'), helper.isUndefined())
assert.strictEqual(client.reply, 'ON'); batch.set('foo', 'bar', helper.isUndefined())
batch.set('foo', 'bar'); batch.exec(function (err, res) {
batch.exec(function (err, res) { assert.strictEqual(client.reply, 'OFF')
assert.deepEqual(res, ['OK', 'OK']); assert.deepEqual(res, ['OK', undefined, undefined])
done(err); done(err)
}); })
}); })
it('off', function (done) { it('skip', function (done) {
helper.serverVersionAtLeast.call(this, client, [3, 2, 0]); helper.serverVersionAtLeast.call(this, client, [3, 2, 0])
var batch = client.batch(); assert.strictEqual(client.reply, 'ON')
assert.strictEqual(client.reply, 'ON'); client.batch()
batch.set('hello', 'world'); .set('hello', 'world')
batch.client(new Buffer('REPLY'), new Buffer('OFF'), helper.isUndefined()); .client('REPLY', 'SKIP', helper.isUndefined())
batch.set('foo', 'bar', helper.isUndefined()); .set('foo', 'bar', helper.isUndefined())
batch.exec(function (err, res) { .get('foo')
assert.strictEqual(client.reply, 'OFF'); .exec(function (err, res) {
assert.deepEqual(res, ['OK', undefined, undefined]); assert.strictEqual(client.reply, 'ON')
done(err); assert.deepEqual(res, ['OK', undefined, undefined, 'bar'])
}); done(err)
}); })
})
})
})
it('skip', function (done) { describe('setname / getname', function () {
helper.serverVersionAtLeast.call(this, client, [3, 2, 0]); var client2
assert.strictEqual(client.reply, 'ON');
client.batch()
.set('hello', 'world')
.client('REPLY', 'SKIP', helper.isUndefined())
.set('foo', 'bar', helper.isUndefined())
.get('foo')
.exec(function (err, res) {
assert.strictEqual(client.reply, 'ON');
assert.deepEqual(res, ['OK', undefined, undefined, 'bar']);
done(err);
});
});
});
});
describe('setname / getname', function () { beforeEach(function (done) {
var client2; client2 = redis.createClient.apply(null, args)
client2.once('ready', function () {
done()
})
})
beforeEach(function (done) { afterEach(function () {
client2 = redis.createClient.apply(null, args); client2.end(true)
client2.once('ready', function () { })
done();
});
});
afterEach(function () { it('sets the name', function (done) {
client2.end(true); // The querys are auto pipelined and the response is a response to all querys of one client
}); // per chunk. So the execution order is only guaranteed on each client
var end = helper.callFuncAfter(done, 2)
it('sets the name', function (done) { client.client('setname', 'RUTH')
// The querys are auto pipelined and the response is a response to all querys of one client client2.client('setname', ['RENEE'], helper.isString('OK'))
// per chunk. So the execution order is only garanteed on each client client2.client(['setname', 'MARTIN'], helper.isString('OK'))
var end = helper.callFuncAfter(done, 2); client2.client('getname', helper.isString('MARTIN', end))
client.client('getname', helper.isString('RUTH', end))
client.client('setname', 'RUTH'); })
client2.client('setname', ['RENEE'], helper.isString('OK')); })
client2.client(['setname', 'MARTIN'], helper.isString('OK')); })
client2.client('getname', function (err, res) { })
assert.equal(res, 'MARTIN'); })
end();
});
client.client('getname', function (err, res) {
assert.equal(res, 'RUTH');
end();
});
});
});
});
});
});

View File

@@ -1,95 +1,93 @@
'use strict'; 'use strict'
var assert = require('assert'); var assert = require('assert')
var config = require('../lib/config'); var config = require('../lib/config')
var helper = require('../helper'); var helper = require('../helper')
var redis = config.redis; var redis = config.redis
var uuid = require('uuid'); var uuid = require('uuid')
describe("The 'dbsize' method", function () { describe('The \'dbsize\' method', function () {
helper.allTests(function (ip, args) {
describe('using ' + ip, function () {
var key, value
helper.allTests(function (ip, args) { beforeEach(function () {
key = uuid.v4()
value = uuid.v4()
})
describe('using ' + ip, function () { describe('when not connected', function () {
var key, value; var client
beforeEach(function () { beforeEach(function (done) {
key = uuid.v4(); client = redis.createClient.apply(null, args)
value = uuid.v4(); client.once('ready', function () {
}); client.quit()
})
client.on('end', done)
})
describe('when not connected', function () { it('reports an error', function (done) {
var client; client.dbsize([], function (err, res) {
assert(err.message.match(/The connection is already closed/))
done()
})
})
})
beforeEach(function (done) { describe('when connected', function () {
client = redis.createClient.apply(null, args); var client
client.once('ready', function () {
client.quit();
});
client.on('end', done);
});
it('reports an error', function (done) { beforeEach(function (done) {
client.dbsize([], function (err, res) { client = redis.createClient.apply(null, args)
assert(err.message.match(/The connection is already closed/)); client.once('ready', function () {
done(); client.flushdb(function (err, res) {
}); helper.isString('OK')(err, res)
}); done()
}); })
})
})
describe('when connected', function () { afterEach(function () {
var client; client.end(true)
})
beforeEach(function (done) { it('returns a zero db size', function (done) {
client = redis.createClient.apply(null, args); client.dbsize([], function (err, res) {
client.once('ready', function () { helper.isNotError()(err, res)
client.flushdb(function (err, res) { helper.isType.number()(err, res)
helper.isString('OK')(err, res); assert.strictEqual(res, 0, 'Initial db size should be 0')
done(); done()
}); })
}); })
});
afterEach(function () { describe('when more data is added to Redis', function () {
client.end(true); var oldSize
});
it('returns a zero db size', function (done) { beforeEach(function (done) {
client.dbsize([], function (err, res) { client.dbsize(function (err, res) {
helper.isNotError()(err, res); helper.isType.number()(err, res)
helper.isType.number()(err, res); assert.strictEqual(res, 0, 'Initial db size should be 0')
assert.strictEqual(res, 0, 'Initial db size should be 0');
done();
});
});
describe('when more data is added to Redis', function () { oldSize = res
var oldSize;
beforeEach(function (done) { client.set(key, value, function (err, res) {
client.dbsize(function (err, res) { helper.isNotError()(err, res)
helper.isType.number()(err, res); done()
assert.strictEqual(res, 0, 'Initial db size should be 0'); })
})
})
oldSize = res; it('returns a larger db size', function (done) {
client.dbsize([], function (err, res) {
client.set(key, value, function (err, res) { helper.isNotError()(err, res)
helper.isNotError()(err, res); helper.isType.positiveNumber()(err, res)
done(); assert.strictEqual(true, (oldSize < res), 'Adding data should increase db size.')
}); done()
}); })
}); })
})
it('returns a larger db size', function (done) { })
client.dbsize([], function (err, res) { })
helper.isNotError()(err, res); })
helper.isType.positiveNumber()(err, res); })
assert.strictEqual(true, (oldSize < res), 'Adding data should increase db size.');
done();
});
});
});
});
});
});
});

View File

@@ -1,57 +1,55 @@
'use strict'; 'use strict'
var config = require('../lib/config'); var config = require('../lib/config')
var helper = require('../helper'); var helper = require('../helper')
var redis = config.redis; var redis = config.redis
describe("The 'del' method", function () { describe('The \'del\' method', function () {
helper.allTests(function (ip, args) {
describe('using ' + ip, function () {
var client
helper.allTests(function (ip, args) { beforeEach(function (done) {
client = redis.createClient.apply(null, args)
client.once('ready', function () {
client.flushdb(done)
})
})
describe('using ' + ip, function () { it('allows a single key to be deleted', function (done) {
var client; client.set('foo', 'bar')
client.del('foo', helper.isNumber(1))
client.get('foo', helper.isNull(done))
})
beforeEach(function (done) { it('allows del to be called on a key that does not exist', function (done) {
client = redis.createClient.apply(null, args); client.del('foo', helper.isNumber(0, done))
client.once('ready', function () { })
client.flushdb(done);
});
});
it('allows a single key to be deleted', function (done) { it('allows multiple keys to be deleted', function (done) {
client.set('foo', 'bar'); client.mset('foo', 'bar', 'apple', 'banana')
client.del('foo', helper.isNumber(1)); client.del('foo', 'apple', helper.isNumber(2))
client.get('foo', helper.isNull(done)); client.get('foo', helper.isNull())
}); client.get('apple', helper.isNull(done))
})
it('allows del to be called on a key that does not exist', function (done) { it('allows multiple keys to be deleted with the array syntax', function (done) {
client.del('foo', helper.isNumber(0, done)); client.mset('foo', 'bar', 'apple', 'banana')
}); client.del(['foo', 'apple'], helper.isNumber(2))
client.get('foo', helper.isNull())
client.get('apple', helper.isNull(done))
})
it('allows multiple keys to be deleted', function (done) { it('allows multiple keys to be deleted with the array syntax and no callback', function (done) {
client.mset('foo', 'bar', 'apple', 'banana'); client.mset('foo', 'bar', 'apple', 'banana')
client.del('foo', 'apple', helper.isNumber(2)); client.del(['foo', 'apple'])
client.get('foo', helper.isNull()); client.get('foo', helper.isNull())
client.get('apple', helper.isNull(done)); client.get('apple', helper.isNull(done))
}); })
it('allows multiple keys to be deleted with the array syntax', function (done) { afterEach(function () {
client.mset('foo', 'bar', 'apple', 'banana'); client.end(true)
client.del(['foo', 'apple'], helper.isNumber(2)); })
client.get('foo', helper.isNull()); })
client.get('apple', helper.isNull(done)); })
}); })
it('allows multiple keys to be deleted with the array syntax and no callback', function (done) {
client.mset('foo', 'bar', 'apple', 'banana');
client.del(['foo', 'apple']);
client.get('foo', helper.isNull());
client.get('apple', helper.isNull(done));
});
afterEach(function () {
client.end(true);
});
});
});
});

View File

@@ -1,210 +1,196 @@
'use strict'; 'use strict'
var assert = require('assert'); var assert = require('assert')
var config = require('../lib/config'); var config = require('../lib/config')
var crypto = require('crypto'); var crypto = require('crypto')
var helper = require('../helper'); var helper = require('../helper')
var redis = config.redis; var redis = config.redis
describe("The 'eval' method", function () { describe('The \'eval\' method', function () {
helper.allTests(function (ip, args) {
describe('using ' + ip, function () {
var client
var source = 'return redis.call(\'set\', \'sha\', \'test\')'
helper.allTests(function (ip, args) { beforeEach(function (done) {
client = redis.createClient.apply(null, args)
client.once('ready', function () {
client.flushdb(done)
})
})
describe('using ' + ip, function () { afterEach(function () {
var client; client.end(true)
var source = "return redis.call('set', 'sha', 'test')"; })
beforeEach(function (done) { it('converts a float to an integer when evaluated', function (done) {
client = redis.createClient.apply(null, args); client.eval('return 100.5', 0, helper.isNumber(100, done))
client.once('ready', function () { })
client.flushdb(done);
});
});
afterEach(function () { it('returns a string', function (done) {
client.end(true); client.eval('return \'hello world\'', 0, helper.isString('hello world', done))
}); })
it('converts a float to an integer when evaluated', function (done) { it('converts boolean true to integer 1', function (done) {
client.eval('return 100.5', 0, helper.isNumber(100, done)); client.eval('return true', 0, helper.isNumber(1, done))
}); })
it('returns a string', function (done) { it('converts boolean false to null', function (done) {
client.eval("return 'hello world'", 0, helper.isString('hello world', done)); client.eval('return false', 0, helper.isNull(done))
}); })
it('converts boolean true to integer 1', function (done) { it('converts lua status code to string representation', function (done) {
client.eval('return true', 0, helper.isNumber(1, done)); client.eval('return {ok=\'fine\'}', 0, helper.isString('fine', done))
}); })
it('converts boolean false to null', function (done) { it('converts lua error to an error response', function (done) {
client.eval('return false', 0, helper.isNull(done)); client.eval('return {err=\'this is an error\'}', 0, function (err) {
}); assert(err.code === undefined)
helper.isError()(err)
done()
})
})
it('converts lua status code to string representation', function (done) { it('represents a lua table appropritely', function (done) {
client.eval("return {ok='fine'}", 0, helper.isString('fine', done)); client.eval('return {1,2,3,\'ciao\',{1,2}}', 0, function (err, res) {
}); assert.strictEqual(err, null)
assert.strictEqual(5, res.length)
assert.strictEqual(1, res[0])
assert.strictEqual(2, res[1])
assert.strictEqual(3, res[2])
assert.strictEqual('ciao', res[3])
assert.strictEqual(2, res[4].length)
assert.strictEqual(1, res[4][0])
assert.strictEqual(2, res[4][1])
return done()
})
})
it('converts lua error to an error response', function (done) { it('populates keys and argv correctly', function (done) {
client.eval("return {err='this is an error'}", 0, function (err) { client.eval('return {KEYS[1],KEYS[2],ARGV[1],ARGV[2]}', 2, 'a', 'b', 'c', 'd', helper.isDeepEqual(['a', 'b', 'c', 'd'], done))
assert(err.code === undefined); })
helper.isError()(err);
done();
});
});
it('represents a lua table appropritely', function (done) { it('allows arguments to be provided in array rather than as multiple parameters', function (done) {
client.eval("return {1,2,3,'ciao',{1,2}}", 0, function (err, res) { client.eval(['return {KEYS[1],KEYS[2],ARGV[1],ARGV[2]}', 2, 'a', 'b', 'c', 'd'], helper.isDeepEqual(['a', 'b', 'c', 'd'], done))
assert.strictEqual(5, res.length); })
assert.strictEqual(1, res[0]);
assert.strictEqual(2, res[1]);
assert.strictEqual(3, res[2]);
assert.strictEqual('ciao', res[3]);
assert.strictEqual(2, res[4].length);
assert.strictEqual(1, res[4][0]);
assert.strictEqual(2, res[4][1]);
return done();
});
});
it('populates keys and argv correctly', function (done) { it('allows a script to be executed that accesses the redis API without callback', function (done) {
client.eval('return {KEYS[1],KEYS[2],ARGV[1],ARGV[2]}', 2, 'a', 'b', 'c', 'd', function (err, res) { client.eval(source, 0)
assert.strictEqual(4, res.length); client.get('sha', helper.isString('test', done))
assert.strictEqual('a', res[0]); })
assert.strictEqual('b', res[1]);
assert.strictEqual('c', res[2]);
assert.strictEqual('d', res[3]);
return done();
});
});
it('allows arguments to be provided in array rather than as multiple parameters', function (done) { describe('evalsha', function () {
client.eval(['return {KEYS[1],KEYS[2],ARGV[1],ARGV[2]}', 2, 'a', 'b', 'c', 'd'], function (err, res) { var sha = crypto.createHash('sha1').update(source).digest('hex')
assert.strictEqual(4, res.length);
assert.strictEqual('a', res[0]);
assert.strictEqual('b', res[1]);
assert.strictEqual('c', res[2]);
assert.strictEqual('d', res[3]);
return done();
});
});
it('allows a script to be executed that accesses the redis API without callback', function (done) { it('allows a script to be executed that accesses the redis API', function (done) {
client.eval(source, 0); client.eval(source, 0, helper.isString('OK'))
client.get('sha', helper.isString('test', done)); client.get('sha', helper.isString('test', done))
}); })
describe('evalsha', function () { it('can execute a script if the SHA exists', function (done) {
var sha = crypto.createHash('sha1').update(source).digest('hex'); client.evalsha(sha, 0, helper.isString('OK'))
client.get('sha', helper.isString('test', done))
})
it('allows a script to be executed that accesses the redis API', function (done) { it('returns an error if SHA does not exist', function (done) {
client.eval(source, 0, helper.isString('OK')); client.evalsha('ffffffffffffffffffffffffffffffffffffffff', 0, helper.isError(done))
client.get('sha', helper.isString('test', done)); })
});
it('can execute a script if the SHA exists', function (done) { it('emit an error if SHA does not exist without any callback', function (done) {
client.evalsha(sha, 0, helper.isString('OK')); client.evalsha('ffffffffffffffffffffffffffffffffffffffff', 0)
client.get('sha', helper.isString('test', done)); client.on('error', function (err) {
}); assert.strictEqual(err.code, 'NOSCRIPT')
assert(/NOSCRIPT No matching script. Please use EVAL./.test(err.message))
done()
})
})
it('returns an error if SHA does not exist', function (done) { it('emits an error if SHA does not exist and no callback has been provided', function (done) {
client.evalsha('ffffffffffffffffffffffffffffffffffffffff', 0, helper.isError(done)); client.on('error', function (err) {
}); assert.strictEqual(err.message, 'NOSCRIPT No matching script. Please use EVAL.')
done()
})
client.evalsha('ffffffffffffffffffffffffffffffffffffffff', 0)
})
})
it('emit an error if SHA does not exist without any callback', function (done) { it('allows a key to be incremented, and performs appropriate conversion from LUA type', function (done) {
client.evalsha('ffffffffffffffffffffffffffffffffffffffff', 0); client.set('incr key', 0, function (err, reply) {
client.on('error', function (err) { if (err) return done(err)
assert.equal(err.code, 'NOSCRIPT'); client.eval('local foo = redis.call(\'incr\',\'incr key\')\nreturn {type(foo),foo}', 0, function (err, res) {
assert(/NOSCRIPT No matching script. Please use EVAL./.test(err.message)); assert.strictEqual(2, res.length)
done(); assert.strictEqual('number', res[0])
}); assert.strictEqual(1, res[1])
}); return done(err)
})
})
})
it('emits an error if SHA does not exist and no callback has been provided', function (done) { it('allows a bulk operation to be performed, and performs appropriate conversion from LUA type', function (done) {
client.on('error', function (err) { client.set('bulk reply key', 'bulk reply value', function (err, res) {
assert.equal(err.message, 'NOSCRIPT No matching script. Please use EVAL.'); assert.strictEqual(err, null)
done(); client.eval('local foo = redis.call(\'get\',\'bulk reply key\'); return {type(foo),foo}', 0, function (err, res) {
}); assert.strictEqual(2, res.length)
client.evalsha('ffffffffffffffffffffffffffffffffffffffff', 0); assert.strictEqual('string', res[0])
}); assert.strictEqual('bulk reply value', res[1])
}); return done(err)
})
})
})
it('allows a key to be incremented, and performs appropriate conversion from LUA type', function (done) { it('allows a multi mulk operation to be performed, with the appropriate type conversion', function (done) {
client.set('incr key', 0, function (err, reply) { client.multi()
if (err) return done(err); .del('mylist')
client.eval("local foo = redis.call('incr','incr key')\nreturn {type(foo),foo}", 0, function (err, res) { .rpush('mylist', 'a')
assert.strictEqual(2, res.length); .rpush('mylist', 'b')
assert.strictEqual('number', res[0]); .rpush('mylist', 'c')
assert.strictEqual(1, res[1]); .exec(function (err, replies) {
return done(err); if (err) return done(err)
}); client.eval('local foo = redis.call(\'lrange\',\'mylist\',0,-1); return {type(foo),foo[1],foo[2],foo[3],# foo}', 0, function (err, res) {
}); assert.strictEqual(5, res.length)
}); assert.strictEqual('table', res[0])
assert.strictEqual('a', res[1])
assert.strictEqual('b', res[2])
assert.strictEqual('c', res[3])
assert.strictEqual(3, res[4])
return done(err)
})
})
})
it('allows a bulk operation to be performed, and performs appropriate conversion from LUA type', function (done) { it('returns an appropriate representation of Lua status reply', function (done) {
client.set('bulk reply key', 'bulk reply value', function (err, res) { client.eval('local foo = redis.call(\'set\',\'mykey\',\'myval\'); return {type(foo),foo[\'ok\']}', 0, function (err, res) {
client.eval("local foo = redis.call('get','bulk reply key'); return {type(foo),foo}", 0, function (err, res) { assert.strictEqual(2, res.length)
assert.strictEqual(2, res.length); assert.strictEqual('table', res[0])
assert.strictEqual('string', res[0]); assert.strictEqual('OK', res[1])
assert.strictEqual('bulk reply value', res[1]); return done(err)
return done(err); })
}); })
});
});
it('allows a multi mulk operation to be performed, with the appropriate type conversion', function (done) { it('returns an appropriate representation of a Lua error reply', function (done) {
client.multi() client.set('error reply key', 'error reply value', function (err, res) {
.del('mylist') if (err) return done(err)
.rpush('mylist', 'a') client.eval('local foo = redis.pcall(\'incr\',\'error reply key\'); return {type(foo),foo[\'err\']}', 0, function (err, res) {
.rpush('mylist', 'b') assert.strictEqual(2, res.length)
.rpush('mylist', 'c') assert.strictEqual('table', res[0])
.exec(function (err, replies) { assert.strictEqual('ERR value is not an integer or out of range', res[1])
if (err) return done(err); return done(err)
client.eval("local foo = redis.call('lrange','mylist',0,-1); return {type(foo),foo[1],foo[2],foo[3],# foo}", 0, function (err, res) { })
assert.strictEqual(5, res.length); })
assert.strictEqual('table', res[0]); })
assert.strictEqual('a', res[1]);
assert.strictEqual('b', res[2]);
assert.strictEqual('c', res[3]);
assert.strictEqual(3, res[4]);
return done(err);
});
});
});
it('returns an appropriate representation of Lua status reply', function (done) { it('returns an appropriate representation of a Lua nil reply', function (done) {
client.eval("local foo = redis.call('set','mykey','myval'); return {type(foo),foo['ok']}", 0, function (err, res) { client.del('nil reply key', function (err, res) {
assert.strictEqual(2, res.length); if (err) return done(err)
assert.strictEqual('table', res[0]); client.eval('local foo = redis.call(\'get\',\'nil reply key\'); return {type(foo),foo == false}', 0, function (err, res) {
assert.strictEqual('OK', res[1]); if (err) throw err
return done(err); assert.strictEqual(2, res.length)
}); assert.strictEqual('boolean', res[0])
}); assert.strictEqual(1, res[1])
return done(err)
it('returns an appropriate representation of a Lua error reply', function (done) { })
client.set('error reply key', 'error reply value', function (err, res) { })
if (err) return done(err); })
client.eval("local foo = redis.pcall('incr','error reply key'); return {type(foo),foo['err']}", 0, function (err, res) { })
assert.strictEqual(2, res.length); })
assert.strictEqual('table', res[0]); })
assert.strictEqual('ERR value is not an integer or out of range', res[1]);
return done(err);
});
});
});
it('returns an appropriate representation of a Lua nil reply', function (done) {
client.del('nil reply key', function (err, res) {
if (err) return done(err);
client.eval("local foo = redis.call('get','nil reply key'); return {type(foo),foo == false}", 0, function (err, res) {
if (err) throw err;
assert.strictEqual(2, res.length);
assert.strictEqual('boolean', res[0]);
assert.strictEqual(1, res[1]);
return done(err);
});
});
});
});
});
});

View File

@@ -1,40 +1,38 @@
'use strict'; 'use strict'
var config = require('../lib/config'); var config = require('../lib/config')
var helper = require('../helper'); var helper = require('../helper')
var redis = config.redis; var redis = config.redis
describe("The 'exists' method", function () { describe('The \'exists\' method', function () {
helper.allTests(function (ip, args) {
describe('using ' + ip, function () {
var client
helper.allTests(function (ip, args) { beforeEach(function (done) {
client = redis.createClient.apply(null, args)
client.once('ready', function () {
client.flushdb(done)
})
})
describe('using ' + ip, function () { it('returns 1 if the key exists', function (done) {
var client; client.set('foo', 'bar')
client.exists('foo', helper.isNumber(1, done))
})
beforeEach(function (done) { it('returns 1 if the key exists with array syntax', function (done) {
client = redis.createClient.apply(null, args); client.set('foo', 'bar')
client.once('ready', function () { client.exists(['foo'], helper.isNumber(1, done))
client.flushdb(done); })
});
});
it('returns 1 if the key exists', function (done) { it('returns 0 if the key does not exist', function (done) {
client.set('foo', 'bar'); client.exists('bar', helper.isNumber(0, done))
client.exists('foo', helper.isNumber(1, done)); })
});
it('returns 1 if the key exists with array syntax', function (done) { afterEach(function () {
client.set('foo', 'bar'); client.end(true)
client.exists(['foo'], helper.isNumber(1, done)); })
}); })
})
it('returns 0 if the key does not exist', function (done) { })
client.exists('bar', helper.isNumber(0, done));
});
afterEach(function () {
client.end(true);
});
});
});
});

View File

@@ -1,42 +1,40 @@
'use strict'; 'use strict'
var config = require('../lib/config'); var config = require('../lib/config')
var helper = require('../helper'); var helper = require('../helper')
var redis = config.redis; var redis = config.redis
describe("The 'expire' method", function () { describe('The \'expire\' method', function () {
helper.allTests(function (ip, args) {
describe('using ' + ip, function () {
var client
helper.allTests(function (ip, args) { beforeEach(function (done) {
client = redis.createClient.apply(null, args)
client.once('ready', function () {
client.flushdb(done)
})
})
describe('using ' + ip, function () { it('expires key after timeout', function (done) {
var client; client.set(['expiry key', 'bar'], helper.isString('OK'))
client.expire('expiry key', '1', helper.isNumber(1))
setTimeout(function () {
client.exists(['expiry key'], helper.isNumber(0, done))
}, 1050)
})
beforeEach(function (done) { it('expires key after timeout with array syntax', function (done) {
client = redis.createClient.apply(null, args); client.set(['expiry key', 'bar'], helper.isString('OK'))
client.once('ready', function () { client.expire(['expiry key', '1'], helper.isNumber(1))
client.flushdb(done); setTimeout(function () {
}); client.exists(['expiry key'], helper.isNumber(0, done))
}); }, 1050)
})
it('expires key after timeout', function (done) { afterEach(function () {
client.set(['expiry key', 'bar'], helper.isString('OK')); client.end(true)
client.expire('expiry key', '1', helper.isNumber(1)); })
setTimeout(function () { })
client.exists(['expiry key'], helper.isNumber(0, done)); })
}, 1050); })
});
it('expires key after timeout with array syntax', function (done) {
client.set(['expiry key', 'bar'], helper.isString('OK'));
client.expire(['expiry key', '1'], helper.isNumber(1));
setTimeout(function () {
client.exists(['expiry key'], helper.isNumber(0, done));
}, 1050);
});
afterEach(function () {
client.end(true);
});
});
});
});

View File

@@ -1,105 +1,94 @@
'use strict'; 'use strict'
var assert = require('assert'); var assert = require('assert')
var config = require('../lib/config'); var config = require('../lib/config')
var helper = require('../helper'); var helper = require('../helper')
var redis = config.redis; var redis = config.redis
var uuid = require('uuid'); var uuid = require('uuid')
describe("The 'flushdb' method", function () { describe('The \'flushdb\' method', function () {
helper.allTests(function (ip, args) {
describe('using ' + ip, function () {
var key, key2
helper.allTests(function (ip, args) { beforeEach(function () {
key = uuid.v4()
key2 = uuid.v4()
})
describe('using ' + ip, function () { describe('when not connected', function () {
var key, key2; var client
beforeEach(function () { beforeEach(function (done) {
key = uuid.v4(); client = redis.createClient.apply(null, args)
key2 = uuid.v4(); client.once('ready', function () {
}); client.quit()
})
client.on('end', done)
})
describe('when not connected', function () { it('reports an error', function (done) {
var client; client.flushdb(function (err, res) {
assert(err.message.match(/The connection is already closed/))
done()
})
})
})
beforeEach(function (done) { describe('when connected', function () {
client = redis.createClient.apply(null, args); var client
client.once('ready', function () {
client.quit();
});
client.on('end', done);
});
it('reports an error', function (done) { beforeEach(function (done) {
client.flushdb(function (err, res) { client = redis.createClient.apply(null, args)
assert(err.message.match(/The connection is already closed/)); client.once('ready', function () {
done(); done()
}); })
}); })
});
describe('when connected', function () { afterEach(function () {
var client; client.end(true)
})
beforeEach(function (done) { describe('when there is data in Redis', function () {
client = redis.createClient.apply(null, args); beforeEach(function (done) {
client.once('ready', function () { client.mset(key, uuid.v4(), key2, uuid.v4(), helper.isNotError())
done(); client.dbsize([], function (err, res) {
}); helper.isType.positiveNumber()(err, res)
}); assert.strictEqual(res, 2, 'Two keys should have been inserted')
done()
})
})
afterEach(function () { it('deletes all the keys', function (done) {
client.end(true); client.flushdb(function (err, res) {
}); assert.strictEqual(err, null)
assert.strictEqual(res, 'OK')
client.mget(key, key2, function (err, res) {
assert.strictEqual(null, err, 'Unexpected error returned')
assert.strictEqual(true, Array.isArray(res), 'Results object should be an array.')
assert.strictEqual(2, res.length, 'Results array should have length 2.')
assert.strictEqual(null, res[0], 'Redis key should have been flushed.')
assert.strictEqual(null, res[1], 'Redis key should have been flushed.')
done(err)
})
})
})
describe('when there is data in Redis', function () { it('results in a db size of zero', function (done) {
client.flushdb(function (err, res) {
assert.strictEqual(err, null)
client.dbsize([], helper.isNumber(0, done))
})
})
beforeEach(function (done) { it('results in a db size of zero without a callback', function (done) {
client.mset(key, uuid.v4(), key2, uuid.v4(), helper.isNotError()); client.flushdb()
client.dbsize([], function (err, res) { setTimeout(function () {
helper.isType.positiveNumber()(err, res); client.dbsize(helper.isNumber(0, done))
assert.equal(res, 2, 'Two keys should have been inserted'); }, 25)
done(); })
}); })
}); })
})
it('deletes all the keys', function (done) { })
client.flushdb(function (err, res) { })
assert.equal(res, 'OK');
client.mget(key, key2, function (err, res) {
assert.strictEqual(null, err, 'Unexpected error returned');
assert.strictEqual(true, Array.isArray(res), 'Results object should be an array.');
assert.strictEqual(2, res.length, 'Results array should have length 2.');
assert.strictEqual(null, res[0], 'Redis key should have been flushed.');
assert.strictEqual(null, res[1], 'Redis key should have been flushed.');
done(err);
});
});
});
it('results in a db size of zero', function (done) {
client.flushdb(function (err, res) {
client.dbsize([], function (err, res) {
helper.isNotError()(err, res);
helper.isType.number()(err, res);
assert.strictEqual(0, res, 'Flushing db should result in db size 0');
done();
});
});
});
it('results in a db size of zero without a callback', function (done) {
client.flushdb();
setTimeout(function (err, res) {
client.dbsize(function (err, res) {
helper.isNotError()(err, res);
helper.isType.number()(err, res);
assert.strictEqual(0, res, 'Flushing db should result in db size 0');
done();
});
}, 25);
});
});
});
});
});
});

View File

@@ -1,35 +1,33 @@
'use strict'; 'use strict'
var config = require('../lib/config'); var config = require('../lib/config')
var helper = require('../helper'); var helper = require('../helper')
var redis = config.redis; var redis = config.redis
describe("The 'geoadd' method", function () { describe('The \'geoadd\' method', function () {
helper.allTests(function (ip, args) {
describe('using ' + ip, function () {
var client
helper.allTests(function (ip, args) { beforeEach(function (done) {
client = redis.createClient.apply(null, args)
client.once('ready', function () {
client.flushdb(done)
})
})
describe('using ' + ip, function () { it('returns 1 if the key exists', function (done) {
var client; helper.serverVersionAtLeast.call(this, client, [3, 2, 0])
client.geoadd('mycity:21:0:location', '13.361389', '38.115556', 'COR', function (err, res) {
console.log(err, res)
// geoadd is still in the unstable branch. As soon as it reaches the stable one, activate this test
done()
})
})
beforeEach(function (done) { afterEach(function () {
client = redis.createClient.apply(null, args); client.end(true)
client.once('ready', function () { })
client.flushdb(done); })
}); })
}); })
it('returns 1 if the key exists', function (done) {
helper.serverVersionAtLeast.call(this, client, [3, 2, 0]);
client.geoadd('mycity:21:0:location', '13.361389', '38.115556', 'COR', function (err, res) {
console.log(err, res);
// geoadd is still in the unstable branch. As soon as it reaches the stable one, activate this test
done();
});
});
afterEach(function () {
client.end(true);
});
});
});
});

View File

@@ -1,95 +1,93 @@
'use strict'; 'use strict'
var assert = require('assert'); var assert = require('assert')
var config = require('../lib/config'); var config = require('../lib/config')
var helper = require('../helper'); var helper = require('../helper')
var redis = config.redis; var redis = config.redis
var uuid = require('uuid'); var uuid = require('uuid')
describe("The 'get' method", function () { describe('The \'get\' method', function () {
helper.allTests(function (ip, args) {
describe('using ' + ip, function () {
var key, value
helper.allTests(function (ip, args) { beforeEach(function () {
key = uuid.v4()
value = uuid.v4()
})
describe('using ' + ip, function () { describe('when not connected', function () {
var key, value; var client
beforeEach(function () { beforeEach(function (done) {
key = uuid.v4(); client = redis.createClient.apply(null, args)
value = uuid.v4(); client.once('ready', function () {
}); client.quit()
})
client.on('end', done)
})
describe('when not connected', function () { it('reports an error', function (done) {
var client; client.get(key, function (err, res) {
assert(err.message.match(/The connection is already closed/))
done()
})
})
beforeEach(function (done) { it('reports an error promisified', function () {
client = redis.createClient.apply(null, args); return client.getAsync(key).then(assert, function (err) {
client.once('ready', function () { assert(err.message.match(/The connection is already closed/))
client.quit(); })
}); })
client.on('end', done); })
});
it('reports an error', function (done) { describe('when connected', function () {
client.get(key, function (err, res) { var client
assert(err.message.match(/The connection is already closed/));
done();
});
});
it('reports an error promisified', function () { beforeEach(function (done) {
return client.getAsync(key).then(assert, function (err) { client = redis.createClient.apply(null, args)
assert(err.message.match(/The connection is already closed/)); client.once('ready', function () {
}); done()
}); })
}); })
describe('when connected', function () { afterEach(function () {
var client; client.end(true)
})
beforeEach(function (done) { describe('when the key exists in Redis', function () {
client = redis.createClient.apply(null, args); beforeEach(function (done) {
client.once('ready', function () { client.set(key, value, function (err, res) {
done(); helper.isNotError()(err, res)
}); done()
}); })
})
afterEach(function () { it('gets the value correctly', function (done) {
client.end(true); client.get(key, function (err, res) {
}); helper.isString(value)(err, res)
done(err)
})
})
describe('when the key exists in Redis', function () { it('should not throw on a get without callback (even if it\'s not useful)', function (done) {
beforeEach(function (done) { client.get(key)
client.set(key, value, function (err, res) { client.on('error', function (err) {
helper.isNotError()(err, res); throw err
done(); })
}); setTimeout(done, 25)
}); })
})
it('gets the value correctly', function (done) { describe('when the key does not exist in Redis', function () {
client.get(key, function (err, res) { it('gets a null value', function (done) {
helper.isString(value)(err, res); client.get(key, function (err, res) {
done(err); helper.isNull()(err, res)
}); done(err)
}); })
})
it("should not throw on a get without callback (even if it's not useful)", function (done) { })
client.get(key); })
client.on('error', function (err) { })
throw err; })
}); })
setTimeout(done, 25);
});
});
describe('when the key does not exist in Redis', function () {
it('gets a null value', function (done) {
client.get(key, function (err, res) {
helper.isNull()(err, res);
done(err);
});
});
});
});
});
});
});

View File

@@ -1,105 +1,103 @@
'use strict'; 'use strict'
var assert = require('assert'); var assert = require('assert')
var config = require('../lib/config'); var config = require('../lib/config')
var helper = require('../helper'); var helper = require('../helper')
var redis = config.redis; var redis = config.redis
var uuid = require('uuid'); var uuid = require('uuid')
describe("The 'getset' method", function () { describe('The \'getset\' method', function () {
helper.allTests(function (ip, args) {
describe('using ' + ip, function () {
var key, value, value2
helper.allTests(function (ip, args) { beforeEach(function () {
key = uuid.v4()
value = uuid.v4()
value2 = uuid.v4()
})
describe('using ' + ip, function () { describe('when not connected', function () {
var key, value, value2; var client
beforeEach(function () { beforeEach(function (done) {
key = uuid.v4(); client = redis.createClient.apply(null, args)
value = uuid.v4(); client.once('ready', function () {
value2 = uuid.v4(); client.quit()
}); })
client.on('end', done)
})
describe('when not connected', function () { it('reports an error', function (done) {
var client; client.get(key, function (err, res) {
assert(err.message.match(/The connection is already closed/))
done()
})
})
})
beforeEach(function (done) { describe('when connected', function () {
client = redis.createClient.apply(null, args); var client
client.once('ready', function () {
client.quit();
});
client.on('end', done);
});
it('reports an error', function (done) { beforeEach(function (done) {
client.get(key, function (err, res) { client = redis.createClient.apply(null, args)
assert(err.message.match(/The connection is already closed/)); client.once('ready', function () {
done(); done()
}); })
}); })
});
describe('when connected', function () { afterEach(function () {
var client; client.end(true)
})
beforeEach(function (done) { describe('when the key exists in Redis', function () {
client = redis.createClient.apply(null, args); beforeEach(function (done) {
client.once('ready', function () { client.set(key, value, function (err, res) {
done(); helper.isNotError()(err, res)
}); done()
}); })
})
afterEach(function () { it('gets the value correctly', function (done) {
client.end(true); client.getset(key, value2, function (err, res) {
}); helper.isString(value)(err, res)
client.get(key, function (err, res) {
helper.isString(value2)(err, res)
done(err)
})
})
})
describe('when the key exists in Redis', function () { it('gets the value correctly with array syntax', function (done) {
beforeEach(function (done) { client.getset([key, value2], function (err, res) {
client.set(key, value, function (err, res) { helper.isString(value)(err, res)
helper.isNotError()(err, res); client.get(key, function (err, res) {
done(); helper.isString(value2)(err, res)
}); done(err)
}); })
})
})
it('gets the value correctly', function (done) { it('gets the value correctly with array syntax style 2', function (done) {
client.getset(key, value2, function (err, res) { client.getset(key, [value2], function (err, res) {
helper.isString(value)(err, res); helper.isString(value)(err, res)
client.get(key, function (err, res) { client.get(key, function (err, res) {
helper.isString(value2)(err, res); helper.isString(value2)(err, res)
done(err); done(err)
}); })
}); })
}); })
})
it('gets the value correctly with array syntax', function (done) { describe('when the key does not exist in Redis', function () {
client.getset([key, value2], function (err, res) { it('gets a null value', function (done) {
helper.isString(value)(err, res); client.getset(key, value, function (err, res) {
client.get(key, function (err, res) { helper.isNull()(err, res)
helper.isString(value2)(err, res); done(err)
done(err); })
}); })
}); })
}); })
})
it('gets the value correctly with array syntax style 2', function (done) { })
client.getset(key, [value2], function (err, res) { })
helper.isString(value)(err, res);
client.get(key, function (err, res) {
helper.isString(value2)(err, res);
done(err);
});
});
});
});
describe('when the key does not exist in Redis', function () {
it('gets a null value', function (done) {
client.getset(key, value, function (err, res) {
helper.isNull()(err, res);
done(err);
});
});
});
});
});
});
});

View File

@@ -1,84 +1,82 @@
'use strict'; 'use strict'
var assert = require('assert'); var Buffer = require('safe-buffer').Buffer
var config = require('../lib/config'); var assert = require('assert')
var helper = require('../helper'); var config = require('../lib/config')
var redis = config.redis; var helper = require('../helper')
var redis = config.redis
describe("The 'hgetall' method", function () { describe('The \'hgetall\' method', function () {
helper.allTests(function (ip, args) {
describe('using ' + ip, function () {
var client
helper.allTests(function (ip, args) { describe('regular client', function () {
beforeEach(function (done) {
client = redis.createClient.apply(null, args)
client.once('ready', function () {
client.flushdb(done)
})
})
describe('using ' + ip, function () { it('handles simple keys and values', function (done) {
var client; client.hmset(['hosts', 'hasOwnProperty', '1', 'another', '23', 'home', '1234'], helper.isString('OK'))
client.hgetall(['hosts'], function (err, obj) {
assert.strictEqual(3, Object.keys(obj).length)
assert.strictEqual('1', obj.hasOwnProperty.toString())
assert.strictEqual('23', obj.another.toString())
assert.strictEqual('1234', obj.home.toString())
done(err)
})
})
describe('regular client', function () { it('handles fetching keys set using an object', function (done) {
client.batch().hmset('msgTest', { message: 'hello' }, undefined).exec()
client.hgetall('msgTest', function (err, obj) {
assert.strictEqual(1, Object.keys(obj).length)
assert.strictEqual(obj.message, 'hello')
done(err)
})
})
beforeEach(function (done) { it('handles fetching a messing key', function (done) {
client = redis.createClient.apply(null, args); client.hgetall('missing', function (err, obj) {
client.once('ready', function () { assert.strictEqual(null, obj)
client.flushdb(done); done(err)
}); })
}); })
})
it('handles simple keys and values', function (done) { describe('binary client', function () {
client.hmset(['hosts', 'hasOwnProperty', '1', 'another', '23', 'home', '1234'], helper.isString('OK')); var client
client.hgetall(['hosts'], function (err, obj) { var args = config.configureClient(ip, {
assert.strictEqual(3, Object.keys(obj).length); returnBuffers: true
assert.strictEqual('1', obj.hasOwnProperty.toString()); })
assert.strictEqual('23', obj.another.toString());
assert.strictEqual('1234', obj.home.toString());
done(err);
});
});
it('handles fetching keys set using an object', function (done) { beforeEach(function (done) {
client.batch().hmset('msgTest', { message: 'hello' }, undefined).exec(); client = redis.createClient.apply(null, args)
client.hgetall('msgTest', function (err, obj) { client.once('ready', function () {
assert.strictEqual(1, Object.keys(obj).length); client.flushdb(done)
assert.strictEqual(obj.message, 'hello'); })
done(err); })
});
});
it('handles fetching a messing key', function (done) { it('returns binary results', function (done) {
client.hgetall('missing', function (err, obj) { client.hmset(['bhosts', 'mjr', '1', 'another', '23', 'home', '1234', Buffer.from([0xAA, 0xBB, 0x00, 0xF0]), Buffer.from([0xCC, 0xDD, 0x00, 0xF0])], helper.isString('OK'))
assert.strictEqual(null, obj); client.hgetall('bhosts', function (err, obj) {
done(err); assert.strictEqual(4, Object.keys(obj).length)
}); assert.strictEqual('1', obj.mjr.toString())
}); assert.strictEqual('23', obj.another.toString())
}); assert.strictEqual('1234', obj.home.toString())
assert.strictEqual((Buffer.from([0xAA, 0xBB, 0x00, 0xF0])).toString('binary'), Object.keys(obj)[3])
assert.strictEqual((Buffer.from([0xCC, 0xDD, 0x00, 0xF0])).toString('binary'), obj[(Buffer.from([0xAA, 0xBB, 0x00, 0xF0])).toString('binary')].toString('binary'))
return done(err)
})
})
})
describe('binary client', function () { afterEach(function () {
var client; client.end(true)
var args = config.configureClient(ip, { })
returnBuffers: true })
}); })
})
beforeEach(function (done) {
client = redis.createClient.apply(null, args);
client.once('ready', function () {
client.flushdb(done);
});
});
it('returns binary results', function (done) {
client.hmset(['bhosts', 'mjr', '1', 'another', '23', 'home', '1234', new Buffer([0xAA, 0xBB, 0x00, 0xF0]), new Buffer([0xCC, 0xDD, 0x00, 0xF0])], helper.isString('OK'));
client.hgetall('bhosts', function (err, obj) {
assert.strictEqual(4, Object.keys(obj).length);
assert.strictEqual('1', obj.mjr.toString());
assert.strictEqual('23', obj.another.toString());
assert.strictEqual('1234', obj.home.toString());
assert.strictEqual((new Buffer([0xAA, 0xBB, 0x00, 0xF0])).toString('binary'), Object.keys(obj)[3]);
assert.strictEqual((new Buffer([0xCC, 0xDD, 0x00, 0xF0])).toString('binary'), obj[(new Buffer([0xAA, 0xBB, 0x00, 0xF0])).toString('binary')].toString('binary'));
return done(err);
});
});
});
afterEach(function () {
client.end(true);
});
});
});
});

View File

@@ -1,40 +1,38 @@
'use strict'; 'use strict'
var config = require('../lib/config'); var config = require('../lib/config')
var helper = require('../helper'); var helper = require('../helper')
var redis = config.redis; var redis = config.redis
describe("The 'hincrby' method", function () { describe('The \'hincrby\' method', function () {
helper.allTests(function (ip, args) {
describe('using ' + ip, function () {
var client
var hash = 'test hash'
helper.allTests(function (ip, args) { beforeEach(function (done) {
client = redis.createClient.apply(null, args)
client.once('ready', function () {
client.flushdb(done)
})
})
describe('using ' + ip, function () { it('increments a key that has already been set', function (done) {
var client; var field = 'field 1'
var hash = 'test hash';
beforeEach(function (done) { client.hset(hash, field, 33)
client = redis.createClient.apply(null, args); client.hincrby(hash, field, 10, helper.isNumber(43, done))
client.once('ready', function () { })
client.flushdb(done);
});
});
it('increments a key that has already been set', function (done) { it('increments a key that has not been set', function (done) {
var field = 'field 1'; var field = 'field 2'
client.hset(hash, field, 33); client.hincrby(hash, field, 10, helper.isNumber(10, done))
client.hincrby(hash, field, 10, helper.isNumber(43, done)); })
});
it('increments a key that has not been set', function (done) { afterEach(function () {
var field = 'field 2'; client.end(true)
})
client.hincrby(hash, field, 10, helper.isNumber(10, done)); })
}); })
})
afterEach(function () {
client.end(true);
});
});
});
});

View File

@@ -1,38 +1,37 @@
'use strict'; 'use strict'
var config = require('../lib/config'); var Buffer = require('safe-buffer').Buffer
var helper = require('../helper'); var config = require('../lib/config')
var redis = config.redis; var helper = require('../helper')
var redis = config.redis
describe("The 'hlen' method", function () { describe('The \'hlen\' method', function () {
helper.allTests(function (ip, args) {
describe('using ' + ip, function () {
var client
helper.allTests(function (ip, args) { beforeEach(function (done) {
client = redis.createClient.apply(null, args)
client.once('ready', function () {
client.flushdb(done)
})
})
describe('using ' + ip, function () { it('reports the count of keys', function (done) {
var client; var hash = 'test hash'
var field1 = Buffer.from('0123456789')
var value1 = Buffer.from('abcdefghij')
var field2 = Buffer.from('')
var value2 = Buffer.from('')
beforeEach(function (done) { client.hset(hash, field1, value1, helper.isNumber(1))
client = redis.createClient.apply(null, args); client.hset(hash, field2, value2, helper.isNumber(1))
client.once('ready', function () { client.hlen(hash, helper.isNumber(2, done))
client.flushdb(done); })
});
});
it('reports the count of keys', function (done) { afterEach(function () {
var hash = 'test hash'; client.end(true)
var field1 = new Buffer('0123456789'); })
var value1 = new Buffer('abcdefghij'); })
var field2 = new Buffer(0); })
var value2 = new Buffer(0); })
client.hset(hash, field1, value1, helper.isNumber(1));
client.hset(hash, field2, value2, helper.isNumber(1));
client.hlen(hash, helper.isNumber(2, done));
});
afterEach(function () {
client.end(true);
});
});
});
});

View File

@@ -1,71 +1,69 @@
'use strict'; 'use strict'
var assert = require('assert'); var assert = require('assert')
var config = require('../lib/config'); var config = require('../lib/config')
var helper = require('../helper'); var helper = require('../helper')
var redis = config.redis; var redis = config.redis
describe("The 'hmget' method", function () { describe('The \'hmget\' method', function () {
helper.allTests(function (ip, args) {
describe('using ' + ip, function () {
var client
var hash = 'test hash'
helper.allTests(function (ip, args) { beforeEach(function (done) {
client = redis.createClient.apply(null, args)
client.once('error', done)
client.once('ready', function () {
client.flushdb()
client.hmset(hash, {'0123456789': 'abcdefghij', 'some manner of key': 'a type of value'}, helper.isString('OK', done))
})
})
describe('using ' + ip, function () { it('allows keys to be specified using multiple arguments', function (done) {
var client; client.hmget(hash, '0123456789', 'some manner of key', function (err, reply) {
var hash = 'test hash'; assert.strictEqual('abcdefghij', reply[0].toString())
assert.strictEqual('a type of value', reply[1].toString())
return done(err)
})
})
beforeEach(function (done) { it('allows keys to be specified by passing an array without manipulating the array', function (done) {
client = redis.createClient.apply(null, args); var data = ['0123456789', 'some manner of key']
client.once('error', done); client.hmget(hash, data, function (err, reply) {
client.once('ready', function () { assert.strictEqual(data.length, 2)
client.flushdb(); assert.strictEqual('abcdefghij', reply[0].toString())
client.hmset(hash, {'0123456789': 'abcdefghij', 'some manner of key': 'a type of value'}, helper.isString('OK', done)); assert.strictEqual('a type of value', reply[1].toString())
}); return done(err)
}); })
})
it('allows keys to be specified using multiple arguments', function (done) { it('allows keys to be specified by passing an array as first argument', function (done) {
client.hmget(hash, '0123456789', 'some manner of key', function (err, reply) { client.hmget([hash, '0123456789', 'some manner of key'], function (err, reply) {
assert.strictEqual('abcdefghij', reply[0].toString()); assert.strictEqual('abcdefghij', reply[0].toString())
assert.strictEqual('a type of value', reply[1].toString()); assert.strictEqual('a type of value', reply[1].toString())
return done(err); return done(err)
}); })
}); })
it('allows keys to be specified by passing an array without manipulating the array', function (done) { it('allows a single key to be specified in an array', function (done) {
var data = ['0123456789', 'some manner of key']; client.hmget(hash, ['0123456789'], function (err, reply) {
client.hmget(hash, data, function (err, reply) { assert.strictEqual('abcdefghij', reply[0].toString())
assert.strictEqual(data.length, 2); return done(err)
assert.strictEqual('abcdefghij', reply[0].toString()); })
assert.strictEqual('a type of value', reply[1].toString()); })
return done(err);
});
});
it('allows keys to be specified by passing an array as first argument', function (done) { it('allows keys to be specified that have not yet been set', function (done) {
client.hmget([hash, '0123456789', 'some manner of key'], function (err, reply) { client.hmget(hash, 'missing thing', 'another missing thing', function (err, reply) {
assert.strictEqual('abcdefghij', reply[0].toString()); assert.strictEqual(null, reply[0])
assert.strictEqual('a type of value', reply[1].toString()); assert.strictEqual(null, reply[1])
return done(err); return done(err)
}); })
}); })
it('allows a single key to be specified in an array', function (done) { afterEach(function () {
client.hmget(hash, ['0123456789'], function (err, reply) { client.end(true)
assert.strictEqual('abcdefghij', reply[0].toString()); })
return done(err); })
}); })
}); })
it('allows keys to be specified that have not yet been set', function (done) {
client.hmget(hash, 'missing thing', 'another missing thing', function (err, reply) {
assert.strictEqual(null, reply[0]);
assert.strictEqual(null, reply[1]);
return done(err);
});
});
afterEach(function () {
client.end(true);
});
});
});
});

View File

@@ -1,117 +1,115 @@
'use strict'; 'use strict'
var assert = require('assert'); var assert = require('assert')
var config = require('../lib/config'); var config = require('../lib/config')
var helper = require('../helper'); var helper = require('../helper')
var redis = config.redis; var redis = config.redis
describe("The 'hmset' method", function () { describe('The \'hmset\' method', function () {
helper.allTests(function (ip, args) {
describe('using ' + ip, function () {
var client
var hash = 'test hash'
helper.allTests(function (ip, args) { beforeEach(function (done) {
client = redis.createClient.apply(null, args)
client.once('ready', function () {
client.flushdb(done)
})
})
describe('using ' + ip, function () { it('handles redis-style syntax', function (done) {
var client; client.hmset(hash, '0123456789', 'abcdefghij', 'some manner of key', 'a type of value', 'otherTypes', 555, helper.isString('OK'))
var hash = 'test hash'; client.hgetall(hash, function (err, obj) {
assert.strictEqual(obj['0123456789'], 'abcdefghij')
assert.strictEqual(obj['some manner of key'], 'a type of value')
return done(err)
})
})
beforeEach(function (done) { it('handles object-style syntax', function (done) {
client = redis.createClient.apply(null, args); client.hmset(hash, {'0123456789': 'abcdefghij', 'some manner of key': 'a type of value', 'otherTypes': 555}, helper.isString('OK'))
client.once('ready', function () { client.hgetall(hash, function (err, obj) {
client.flushdb(done); assert.strictEqual(obj['0123456789'], 'abcdefghij')
}); assert.strictEqual(obj['some manner of key'], 'a type of value')
}); return done(err)
})
})
it('handles redis-style syntax', function (done) { it('handles object-style syntax and the key being a number', function (done) {
client.hmset(hash, '0123456789', 'abcdefghij', 'some manner of key', 'a type of value', 'otherTypes', 555, helper.isString('OK')); client.hmset(231232, {'0123456789': 'abcdefghij', 'some manner of key': 'a type of value', 'otherTypes': 555}, undefined)
client.hgetall(hash, function (err, obj) { client.hgetall(231232, function (err, obj) {
assert.equal(obj['0123456789'], 'abcdefghij'); assert.strictEqual(obj['0123456789'], 'abcdefghij')
assert.equal(obj['some manner of key'], 'a type of value'); assert.strictEqual(obj['some manner of key'], 'a type of value')
return done(err); return done(err)
}); })
}); })
it('handles object-style syntax', function (done) { it('allows a numeric key', function (done) {
client.hmset(hash, {'0123456789': 'abcdefghij', 'some manner of key': 'a type of value', 'otherTypes': 555}, helper.isString('OK')); client.hmset(hash, 99, 'banana', helper.isString('OK'))
client.hgetall(hash, function (err, obj) { client.hgetall(hash, function (err, obj) {
assert.equal(obj['0123456789'], 'abcdefghij'); assert.strictEqual(obj['99'], 'banana')
assert.equal(obj['some manner of key'], 'a type of value'); return done(err)
return done(err); })
}); })
});
it('handles object-style syntax and the key being a number', function (done) { it('allows a numeric key without callback', function (done) {
client.hmset(231232, {'0123456789': 'abcdefghij', 'some manner of key': 'a type of value', 'otherTypes': 555}, undefined); client.hmset(hash, 99, 'banana', 'test', 25)
client.hgetall(231232, function (err, obj) { client.hgetall(hash, function (err, obj) {
assert.equal(obj['0123456789'], 'abcdefghij'); assert.strictEqual(obj['99'], 'banana')
assert.equal(obj['some manner of key'], 'a type of value'); assert.strictEqual(obj.test, '25')
return done(err); return done(err)
}); })
}); })
it('allows a numeric key', function (done) { it('allows an array without callback', function (done) {
client.hmset(hash, 99, 'banana', helper.isString('OK')); client.hmset([hash, 99, 'banana', 'test', 25])
client.hgetall(hash, function (err, obj) { client.hgetall(hash, function (err, obj) {
assert.equal(obj['99'], 'banana'); assert.strictEqual(obj['99'], 'banana')
return done(err); assert.strictEqual(obj.test, '25')
}); return done(err)
}); })
})
it('allows a numeric key without callback', function (done) { it('allows an array and a callback', function (done) {
client.hmset(hash, 99, 'banana', 'test', 25); client.hmset([hash, 99, 'banana', 'test', 25], helper.isString('OK'))
client.hgetall(hash, function (err, obj) { client.hgetall(hash, function (err, obj) {
assert.equal(obj['99'], 'banana'); assert.strictEqual(obj['99'], 'banana')
assert.equal(obj.test, '25'); assert.strictEqual(obj.test, '25')
return done(err); return done(err)
}); })
}); })
it('allows an array without callback', function (done) { it('allows a key plus array without callback', function (done) {
client.hmset([hash, 99, 'banana', 'test', 25]); client.hmset(hash, [99, 'banana', 'test', 25])
client.hgetall(hash, function (err, obj) { client.hgetall(hash, function (err, obj) {
assert.equal(obj['99'], 'banana'); assert.strictEqual(obj['99'], 'banana')
assert.equal(obj.test, '25'); assert.strictEqual(obj.test, '25')
return done(err); return done(err)
}); })
}); })
it('allows an array and a callback', function (done) { it('allows a key plus array and a callback', function (done) {
client.hmset([hash, 99, 'banana', 'test', 25], helper.isString('OK')); client.hmset(hash, [99, 'banana', 'test', 25], helper.isString('OK'))
client.hgetall(hash, function (err, obj) { client.hgetall(hash, function (err, obj) {
assert.equal(obj['99'], 'banana'); assert.strictEqual(obj['99'], 'banana')
assert.equal(obj.test, '25'); assert.strictEqual(obj.test, '25')
return done(err); return done(err)
}); })
}); })
it('allows a key plus array without callback', function (done) { it('handles object-style syntax without callback', function (done) {
client.hmset(hash, [99, 'banana', 'test', 25]); client.hmset(hash, {'0123456789': 'abcdefghij', 'some manner of key': 'a type of value'})
client.hgetall(hash, function (err, obj) { client.hgetall(hash, function (err, obj) {
assert.equal(obj['99'], 'banana'); assert.strictEqual(obj['0123456789'], 'abcdefghij')
assert.equal(obj.test, '25'); assert.strictEqual(obj['some manner of key'], 'a type of value')
return done(err); return done(err)
}); })
}); })
it('allows a key plus array and a callback', function (done) { afterEach(function () {
client.hmset(hash, [99, 'banana', 'test', 25], helper.isString('OK')); client.end(true)
client.hgetall(hash, function (err, obj) { })
assert.equal(obj['99'], 'banana'); })
assert.equal(obj.test, '25'); })
return done(err); })
});
});
it('handles object-style syntax without callback', function (done) {
client.hmset(hash, {'0123456789': 'abcdefghij', 'some manner of key': 'a type of value'});
client.hgetall(hash, function (err, obj) {
assert.equal(obj['0123456789'], 'abcdefghij');
assert.equal(obj['some manner of key'], 'a type of value');
return done(err);
});
});
afterEach(function () {
client.end(true);
});
});
});
});

View File

@@ -1,91 +1,91 @@
'use strict'; 'use strict'
var assert = require('assert'); var Buffer = require('safe-buffer').Buffer
var config = require('../lib/config'); var assert = require('assert')
var helper = require('../helper'); var config = require('../lib/config')
var redis = config.redis; var helper = require('../helper')
var redis = config.redis
describe("The 'hset' method", function () { describe('The \'hset\' method', function () {
helper.allTests(function (ip, args) {
describe('using ' + ip, function () {
var client
var hash = 'test hash'
helper.allTests(function (ip, args) { beforeEach(function (done) {
client = redis.createClient.apply(null, args)
client.once('ready', function () {
client.flushdb(done)
})
})
describe('using ' + ip, function () { it('allows a value to be set in a hash', function (done) {
var client; var field = Buffer.from('0123456789')
var hash = 'test hash'; var value = Buffer.from('abcdefghij')
beforeEach(function (done) { client.hset(hash, field, value, helper.isNumber(1))
client = redis.createClient.apply(null, args); client.hget(hash, field, helper.isString(value.toString(), done))
client.once('ready', function () { })
client.flushdb(done);
});
});
it('allows a value to be set in a hash', function (done) { it('handles an empty value', function (done) {
var field = new Buffer('0123456789'); var field = Buffer.from('0123456789')
var value = new Buffer('abcdefghij'); var value = Buffer.from('')
client.hset(hash, field, value, helper.isNumber(1)); client.hset(hash, field, value, helper.isNumber(1))
client.hget(hash, field, helper.isString(value.toString(), done)); client.hget([hash, field], helper.isString('', done))
}); })
it('handles an empty value', function (done) { it('handles empty key and value', function (done) {
var field = new Buffer('0123456789'); var field = Buffer.from('')
var value = new Buffer(0); var value = Buffer.from('')
client.hset([hash, field, value], function (err, res) {
assert.strictEqual(err, null)
assert.strictEqual(res, 1)
client.hset(hash, field, value, helper.isNumber(0, done))
})
})
client.hset(hash, field, value, helper.isNumber(1)); it('warns if someone passed a array either as field or as value', function (done) {
client.hget([hash, field], helper.isString('', done)); var hash = 'test hash'
}); var field = 'array'
// This would be converted to "array contents" but if you use more than one entry,
// it'll result in e.g. "array contents,second content" and this is not supported and considered harmful
var value = ['array contents']
client.on('warning', function (msg) {
assert.strictEqual(
msg,
'Deprecated: The HMSET command contains a argument of type Array.\n' +
'This is converted to "array contents" by using .toString() now and will return an error from v.3.0 on.\n' +
'Please handle this in your code to make sure everything works as you intended it to.'
)
done()
})
client.hmset(hash, field, value)
})
it('handles empty key and value', function (done) { it('does not error when a buffer and date are set as values on the same hash', function (done) {
var field = new Buffer(0); var hash = 'test hash'
var value = new Buffer(0); var field1 = 'buffer'
client.hset([hash, field, value], function (err, res) { var value1 = Buffer.from('abcdefghij')
assert.strictEqual(res, 1); var field2 = 'date'
client.hset(hash, field, value, helper.isNumber(0, done)); var value2 = new Date()
});
});
it('warns if someone passed a array either as field or as value', function (done) { client.hmset(hash, field1, value1, field2, value2, helper.isString('OK', done))
var hash = 'test hash'; })
var field = 'array';
// This would be converted to "array contents" but if you use more than one entry,
// it'll result in e.g. "array contents,second content" and this is not supported and considered harmful
var value = ['array contents'];
client.on('warning', function (msg) {
assert.strictEqual(
msg,
'Deprecated: The HMSET command contains a argument of type Array.\n' +
'This is converted to "array contents" by using .toString() now and will return an error from v.3.0 on.\n' +
'Please handle this in your code to make sure everything works as you intended it to.'
);
done();
});
client.hmset(hash, field, value);
});
it('does not error when a buffer and date are set as values on the same hash', function (done) { it('does not error when a buffer and date are set as fields on the same hash', function (done) {
var hash = 'test hash'; var hash = 'test hash'
var field1 = 'buffer'; var value1 = 'buffer'
var value1 = new Buffer('abcdefghij'); var field1 = Buffer.from('abcdefghij')
var field2 = 'date'; var value2 = 'date'
var value2 = new Date(); var field2 = new Date()
client.hmset(hash, field1, value1, field2, value2, helper.isString('OK', done)); client.hmset(hash, field1, value1, field2, value2, helper.isString('OK', done))
}); })
it('does not error when a buffer and date are set as fields on the same hash', function (done) { afterEach(function () {
var hash = 'test hash'; client.end(true)
var value1 = 'buffer'; })
var field1 = new Buffer('abcdefghij'); })
var value2 = 'date'; })
var field2 = new Date(); })
client.hmset(hash, field1, value1, field2, value2, helper.isString('OK', done));
});
afterEach(function () {
client.end(true);
});
});
});
});

View File

@@ -1,26 +1,22 @@
'use strict'; 'use strict'
var assert = require('assert'); var assert = require('assert')
var config = require('../lib/config'); var config = require('../lib/config')
var helper = require('../helper'); var helper = require('../helper')
var redis = config.redis; var redis = config.redis
describe("The 'incr' method", function () { describe('The \'incr\' method', function () {
helper.allTests(function (ip, args) {
describe('using ' + ip, function () {
describe('when connected and a value in Redis', function () {
var client
var key = 'ABOVE_SAFE_JAVASCRIPT_INTEGER'
helper.allTests(function (ip, args) { afterEach(function () {
client.end(true)
})
describe('using ' + ip, function () { /*
describe('when connected and a value in Redis', function () {
var client;
var key = 'ABOVE_SAFE_JAVASCRIPT_INTEGER';
afterEach(function () {
client.end(true);
});
/*
Number.MAX_SAFE_INTEGER === Math.pow(2, 53) - 1 === 9007199254740991 Number.MAX_SAFE_INTEGER === Math.pow(2, 53) - 1 === 9007199254740991
9007199254740992 -> 9007199254740992 9007199254740992 -> 9007199254740992
@@ -31,45 +27,45 @@ describe("The 'incr' method", function () {
9007199254740997 -> 9007199254740996 9007199254740997 -> 9007199254740996
... ...
*/ */
it('count above the safe integers as numbers', function (done) { it('count above the safe integers as numbers', function (done) {
client = redis.createClient.apply(null, args); client = redis.createClient.apply(null, args)
// Set a value to the maximum safe allowed javascript number (2^53) - 1 // Set a value to the maximum safe allowed javascript number (2^53) - 1
client.set(key, Number.MAX_SAFE_INTEGER, helper.isNotError()); client.set(key, Number.MAX_SAFE_INTEGER, helper.isNotError())
client.incr(key, helper.isNumber(Number.MAX_SAFE_INTEGER + 1)); client.incr(key, helper.isNumber(Number.MAX_SAFE_INTEGER + 1))
client.incr(key, helper.isNumber(Number.MAX_SAFE_INTEGER + 2)); client.incr(key, helper.isNumber(Number.MAX_SAFE_INTEGER + 2))
client.incr(key, helper.isNumber(Number.MAX_SAFE_INTEGER + 3)); client.incr(key, helper.isNumber(Number.MAX_SAFE_INTEGER + 3))
client.incr(key, helper.isNumber(Number.MAX_SAFE_INTEGER + 4)); client.incr(key, helper.isNumber(Number.MAX_SAFE_INTEGER + 4))
client.incr(key, helper.isNumber(Number.MAX_SAFE_INTEGER + 5)); client.incr(key, helper.isNumber(Number.MAX_SAFE_INTEGER + 5))
client.incr(key, function (err, res) { client.incr(key, function (err, res) {
helper.isNumber(Number.MAX_SAFE_INTEGER + 6)(err, res); helper.isNumber(Number.MAX_SAFE_INTEGER + 6)(err, res)
assert.strictEqual(typeof res, 'number'); assert.strictEqual(typeof res, 'number')
}); })
client.incr(key, helper.isNumber(Number.MAX_SAFE_INTEGER + 7)); client.incr(key, helper.isNumber(Number.MAX_SAFE_INTEGER + 7))
client.incr(key, helper.isNumber(Number.MAX_SAFE_INTEGER + 8)); client.incr(key, helper.isNumber(Number.MAX_SAFE_INTEGER + 8))
client.incr(key, helper.isNumber(Number.MAX_SAFE_INTEGER + 9)); client.incr(key, helper.isNumber(Number.MAX_SAFE_INTEGER + 9))
client.incr(key, helper.isNumber(Number.MAX_SAFE_INTEGER + 10, done)); client.incr(key, helper.isNumber(Number.MAX_SAFE_INTEGER + 10, done))
}); })
it('count above the safe integers as strings', function (done) { it('count above the safe integers as strings', function (done) {
args[2].stringNumbers = true; args[2].stringNumbers = true
client = redis.createClient.apply(null, args); client = redis.createClient.apply(null, args)
// Set a value to the maximum safe allowed javascript number (2^53) // Set a value to the maximum safe allowed javascript number (2^53)
client.set(key, Number.MAX_SAFE_INTEGER, helper.isNotError()); client.set(key, Number.MAX_SAFE_INTEGER, helper.isNotError())
client.incr(key, helper.isString('9007199254740992')); client.incr(key, helper.isString('9007199254740992'))
client.incr(key, helper.isString('9007199254740993')); client.incr(key, helper.isString('9007199254740993'))
client.incr(key, helper.isString('9007199254740994')); client.incr(key, helper.isString('9007199254740994'))
client.incr(key, helper.isString('9007199254740995')); client.incr(key, helper.isString('9007199254740995'))
client.incr(key, helper.isString('9007199254740996')); client.incr(key, helper.isString('9007199254740996'))
client.incr(key, function (err, res) { client.incr(key, function (err, res) {
helper.isString('9007199254740997')(err, res); helper.isString('9007199254740997')(err, res)
assert.strictEqual(typeof res, 'string'); assert.strictEqual(typeof res, 'string')
}); })
client.incr(key, helper.isString('9007199254740998')); client.incr(key, helper.isString('9007199254740998'))
client.incr(key, helper.isString('9007199254740999')); client.incr(key, helper.isString('9007199254740999'))
client.incr(key, helper.isString('9007199254741000')); client.incr(key, helper.isString('9007199254741000'))
client.incr(key, helper.isString('9007199254741001', done)); client.incr(key, helper.isString('9007199254741001', done))
}); })
}); })
}); })
}); })
}); })

View File

@@ -1,79 +1,78 @@
'use strict'; 'use strict'
var assert = require('assert'); var assert = require('assert')
var config = require('../lib/config'); var config = require('../lib/config')
var helper = require('../helper'); var helper = require('../helper')
var redis = config.redis; var redis = config.redis
describe("The 'info' method", function () { describe('The \'info\' method', function () {
helper.allTests(function (ip, args) {
describe('using ' + ip, function () {
var client
helper.allTests(function (ip, args) { beforeEach(function (done) {
client = redis.createClient.apply(null, args)
client.once('ready', function () {
client.flushall(done)
})
})
describe('using ' + ip, function () { afterEach(function () {
var client; client.end(true)
})
beforeEach(function (done) { it('update serverInfo after a info command', function (done) {
client = redis.createClient.apply(null, args); client.set('foo', 'bar')
client.once('ready', function () { client.info()
client.flushall(done); client.select(2, function () {
}); assert.strictEqual(client.serverInfo.db2, undefined)
}); })
client.set('foo', 'bar')
client.info()
setTimeout(function () {
assert.strictEqual(typeof client.serverInfo.db2, 'object')
done()
}, 30)
})
afterEach(function () { it('works with optional section provided with and without callback', function (done) {
client.end(true); client.set('foo', 'bar')
}); client.info('keyspace')
client.select(2, function () {
assert.strictEqual(Object.keys(client.serverInfo).length, 2, 'Key length should be three')
assert.strictEqual(typeof client.serverInfo.db0, 'object', 'db0 keyspace should be an object')
})
client.info(['keyspace'])
client.set('foo', 'bar')
client.info('all', function (err, res) {
assert.strictEqual(err, null)
assert(Object.keys(client.serverInfo).length > 3, 'Key length should be way above three')
assert.strictEqual(typeof client.serverInfo.redis_version, 'string')
assert.strictEqual(typeof client.serverInfo.db2, 'object')
done()
})
})
it('update serverInfo after a info command', function (done) { it('check redis v.2.4 support', function (done) {
client.set('foo', 'bar'); var end = helper.callFuncAfter(done, 2)
client.info(); client.internalSendCommand = function (commandObj) {
client.select(2, function () { assert.strictEqual(commandObj.args.length, 0)
assert.strictEqual(client.serverInfo.db2, undefined); assert.strictEqual(commandObj.command, 'info')
}); end()
client.set('foo', 'bar'); }
client.info(); client.info()
setTimeout(function () { client.info(function () {})
assert.strictEqual(typeof client.serverInfo.db2, 'object'); })
done();
}, 30);
});
it('works with optional section provided with and without callback', function (done) { it('emit error after a failure', function (done) {
client.set('foo', 'bar'); client.info()
client.info('keyspace'); client.once('error', function (err) {
client.select(2, function () { assert.strictEqual(err.code, 'UNCERTAIN_STATE')
assert.strictEqual(Object.keys(client.serverInfo).length, 2, 'Key length should be three'); assert.strictEqual(err.command, 'INFO')
assert.strictEqual(typeof client.serverInfo.db0, 'object', 'db0 keyspace should be an object'); done()
}); })
client.info(['keyspace']); client.stream.destroy()
client.set('foo', 'bar'); })
client.info('all', function (err, res) { })
assert(Object.keys(client.serverInfo).length > 3, 'Key length should be way above three'); })
assert.strictEqual(typeof client.serverInfo.redis_version, 'string'); })
assert.strictEqual(typeof client.serverInfo.db2, 'object');
done();
});
});
it('check redis v.2.4 support', function (done) {
var end = helper.callFuncAfter(done, 2);
client.internalSendCommand = function (commandObj) {
assert.strictEqual(commandObj.args.length, 0);
assert.strictEqual(commandObj.command, 'info');
end();
};
client.info();
client.info(function () {});
});
it('emit error after a failure', function (done) {
client.info();
client.once('error', function (err) {
assert.strictEqual(err.code, 'UNCERTAIN_STATE');
assert.strictEqual(err.command, 'INFO');
done();
});
client.stream.destroy();
});
});
});
});

View File

@@ -1,69 +1,67 @@
'use strict'; 'use strict'
var assert = require('assert'); var assert = require('assert')
var config = require('../lib/config'); var config = require('../lib/config')
var crypto = require('crypto'); var crypto = require('crypto')
var helper = require('../helper'); var helper = require('../helper')
var redis = config.redis; var redis = config.redis
describe("The 'keys' method", function () { describe('The \'keys\' method', function () {
helper.allTests(function (ip, args) {
describe('using ' + ip, function () {
var client
helper.allTests(function (ip, args) { beforeEach(function (done) {
client = redis.createClient.apply(null, args)
client.once('ready', function () {
client.flushall(done)
})
})
describe('using ' + ip, function () { it('returns matching keys', function (done) {
var client; client.mset(['test keys 1', 'test val 1', 'test keys 2', 'test val 2'], helper.isString('OK'))
client.keys('test keys*', function (err, results) {
assert.strictEqual(2, results.length)
assert.ok(~results.indexOf('test keys 1'))
assert.ok(~results.indexOf('test keys 2'))
return done(err)
})
})
beforeEach(function (done) { it('handles a large packet size', function (done) {
client = redis.createClient.apply(null, args); var keysValues = []
client.once('ready', function () {
client.flushall(done);
});
});
it('returns matching keys', function (done) { for (var i = 0; i < 200; i++) {
client.mset(['test keys 1', 'test val 1', 'test keys 2', 'test val 2'], helper.isString('OK')); var keyValue = [
client.keys('test keys*', function (err, results) { 'multibulk:' + crypto.randomBytes(256).toString('hex'), // use long strings as keys to ensure generation of large packet
assert.strictEqual(2, results.length); 'test val ' + i
assert.ok(~results.indexOf('test keys 1')); ]
assert.ok(~results.indexOf('test keys 2')); keysValues.push(keyValue)
return done(err); }
});
});
it('handles a large packet size', function (done) { client.mset(keysValues.reduce(function (a, b) {
var keysValues = []; return a.concat(b)
}), helper.isString('OK'))
for (var i = 0; i < 200; i++) { client.keys('multibulk:*', function (err, results) {
var keyValue = [ assert.deepEqual(keysValues.map(function (val) {
'multibulk:' + crypto.randomBytes(256).toString('hex'), // use long strings as keys to ensure generation of large packet return val[0]
'test val ' + i }).sort(), results.sort())
]; return done(err)
keysValues.push(keyValue); })
} })
client.mset(keysValues.reduce(function (a, b) { it('handles an empty response', function (done) {
return a.concat(b); client.keys(['users:*'], function (err, results) {
}), helper.isString('OK')); assert.strictEqual(results.length, 0)
assert.ok(Array.isArray(results))
return done(err)
})
})
client.keys('multibulk:*', function (err, results) { afterEach(function () {
assert.deepEqual(keysValues.map(function (val) { client.end(true)
return val[0]; })
}).sort(), results.sort()); })
return done(err); })
}); })
});
it('handles an empty response', function (done) {
client.keys(['users:*'], function (err, results) {
assert.strictEqual(results.length, 0);
assert.ok(Array.isArray(results));
return done(err);
});
});
afterEach(function () {
client.end(true);
});
});
});
});

View File

@@ -1,70 +1,68 @@
'use strict'; 'use strict'
var assert = require('assert'); var assert = require('assert')
var config = require('../lib/config'); var config = require('../lib/config')
var helper = require('../helper'); var helper = require('../helper')
var redis = config.redis; var redis = config.redis
describe("The 'mget' method", function () { describe('The \'mget\' method', function () {
helper.allTests(function (ip, args) {
describe('using ' + ip, function () {
var client
helper.allTests(function (ip, args) { beforeEach(function (done) {
client = redis.createClient.apply(null, args)
client.once('error', done)
client.once('ready', function () {
client.flushdb()
client.mset(['mget keys 1', 'mget val 1', 'mget keys 2', 'mget val 2', 'mget keys 3', 'mget val 3'], done)
})
})
describe('using ' + ip, function () { it('handles fetching multiple keys in argument form', function (done) {
var client; client.mset(['mget keys 1', 'mget val 1', 'mget keys 2', 'mget val 2', 'mget keys 3', 'mget val 3'], helper.isString('OK'))
client.mget('mget keys 1', 'mget keys 2', 'mget keys 3', function (err, results) {
assert.strictEqual(3, results.length)
assert.strictEqual('mget val 1', results[0].toString())
assert.strictEqual('mget val 2', results[1].toString())
assert.strictEqual('mget val 3', results[2].toString())
return done(err)
})
})
beforeEach(function (done) { it('handles fetching multiple keys via an array', function (done) {
client = redis.createClient.apply(null, args); client.mget(['mget keys 1', 'mget keys 2', 'mget keys 3'], function (err, results) {
client.once('error', done); assert.strictEqual('mget val 1', results[0].toString())
client.once('ready', function () { assert.strictEqual('mget val 2', results[1].toString())
client.flushdb(); assert.strictEqual('mget val 3', results[2].toString())
client.mset(['mget keys 1', 'mget val 1', 'mget keys 2', 'mget val 2', 'mget keys 3', 'mget val 3'], done); return done(err)
}); })
}); })
it('handles fetching multiple keys in argument form', function (done) { it('handles fetching multiple keys, when some keys do not exist', function (done) {
client.mset(['mget keys 1', 'mget val 1', 'mget keys 2', 'mget val 2', 'mget keys 3', 'mget val 3'], helper.isString('OK')); client.mget('mget keys 1', ['some random shit', 'mget keys 2', 'mget keys 3'], function (err, results) {
client.mget('mget keys 1', 'mget keys 2', 'mget keys 3', function (err, results) { assert.strictEqual(4, results.length)
assert.strictEqual(3, results.length); assert.strictEqual('mget val 1', results[0].toString())
assert.strictEqual('mget val 1', results[0].toString()); assert.strictEqual(null, results[1])
assert.strictEqual('mget val 2', results[1].toString()); assert.strictEqual('mget val 2', results[2].toString())
assert.strictEqual('mget val 3', results[2].toString()); assert.strictEqual('mget val 3', results[3].toString())
return done(err); return done(err)
}); })
}); })
it('handles fetching multiple keys via an array', function (done) { it('handles fetching multiple keys, when some keys do not exist promisified', function () {
client.mget(['mget keys 1', 'mget keys 2', 'mget keys 3'], function (err, results) { return client.mgetAsync('mget keys 1', ['some random shit', 'mget keys 2', 'mget keys 3']).then(function (results) {
assert.strictEqual('mget val 1', results[0].toString()); assert.strictEqual(4, results.length)
assert.strictEqual('mget val 2', results[1].toString()); assert.strictEqual('mget val 1', results[0].toString())
assert.strictEqual('mget val 3', results[2].toString()); assert.strictEqual(null, results[1])
return done(err); assert.strictEqual('mget val 2', results[2].toString())
}); assert.strictEqual('mget val 3', results[3].toString())
}); })
})
it('handles fetching multiple keys, when some keys do not exist', function (done) { afterEach(function () {
client.mget('mget keys 1', ['some random shit', 'mget keys 2', 'mget keys 3'], function (err, results) { client.end(true)
assert.strictEqual(4, results.length); })
assert.strictEqual('mget val 1', results[0].toString()); })
assert.strictEqual(null, results[1]); })
assert.strictEqual('mget val 2', results[2].toString()); })
assert.strictEqual('mget val 3', results[3].toString());
return done(err);
});
});
it('handles fetching multiple keys, when some keys do not exist promisified', function () {
return client.mgetAsync('mget keys 1', ['some random shit', 'mget keys 2', 'mget keys 3']).then(function (results) {
assert.strictEqual(4, results.length);
assert.strictEqual('mget val 1', results[0].toString());
assert.strictEqual(null, results[1]);
assert.strictEqual('mget val 2', results[2].toString());
assert.strictEqual('mget val 3', results[3].toString());
});
});
afterEach(function () {
client.end(true);
});
});
});
});

View File

@@ -1,215 +1,215 @@
'use strict'; 'use strict'
var assert = require('assert'); var Buffer = require('safe-buffer').Buffer
var config = require('../lib/config'); var assert = require('assert')
var helper = require('../helper'); var config = require('../lib/config')
var utils = require('../../lib/utils'); var helper = require('../helper')
var redis = config.redis; var utils = require('../../lib/utils')
var redis = config.redis
describe("The 'monitor' method", function () { describe('The \'monitor\' method', function () {
helper.allTests(function (parser, ip, args) {
var client
helper.allTests(function (parser, ip, args) { afterEach(function () {
client.end(true)
})
var client; beforeEach(function (done) {
client = redis.createClient.apply(null, args)
client.once('connect', function () {
client.flushdb(done)
})
})
afterEach(function () { it('monitors commands on all redis clients and works in the correct order', function (done) {
client.end(true); var monitorClient = redis.createClient.apply(null, args)
}); var responses = [
['mget', 'some', 'keys', 'foo', 'bar'],
['set', 'json', '{"foo":"123","bar":"sdflkdfsjk","another":false}'],
['eval', 'return redis.call(\'set\', \'sha\', \'test\')', '0'],
['set', 'sha', 'test'],
['get', 'baz'],
['set', 'foo', 'bar" "s are " " good!"'],
['mget', 'foo', 'baz'],
['subscribe', 'foo', 'baz']
]
var end = helper.callFuncAfter(done, 5)
beforeEach(function (done) { monitorClient.set('foo', 'bar')
client = redis.createClient.apply(null, args); monitorClient.flushdb()
client.once('connect', function () { monitorClient.monitor(function (err, res) {
client.flushdb(done); assert.strictEqual(err, null)
}); assert.strictEqual(res, 'OK')
}); client.mget('some', 'keys', 'foo', 'bar')
client.set('json', JSON.stringify({
foo: '123',
bar: 'sdflkdfsjk',
another: false
}))
client.eval('return redis.call(\'set\', \'sha\', \'test\')', 0)
monitorClient.get('baz', function (err, res) {
assert.strictEqual(res, null)
end(err)
})
monitorClient.set('foo', 'bar" "s are " " good!"', function (err, res) {
assert.strictEqual(res, 'OK')
end(err)
})
monitorClient.mget('foo', 'baz', function (err, res) {
assert.strictEqual(res[0], 'bar" "s are " " good!"')
assert.strictEqual(res[1], null)
end(err)
})
monitorClient.subscribe('foo', 'baz', function (err, res) {
// The return value might change in v.3
// assert.strictEqual(res, 'baz');
// TODO: Fix the return value of subscribe calls
end(err)
})
})
it('monitors commands on all redis clients and works in the correct order', function (done) { monitorClient.on('monitor', function (time, args, rawOutput) {
var monitorClient = redis.createClient.apply(null, args); assert.strictEqual(monitorClient.monitoring, true)
var responses = [ assert.deepEqual(args, responses.shift())
['mget', 'some', 'keys', 'foo', 'bar'], assert(utils.monitorRegex.test(rawOutput), rawOutput)
['set', 'json', '{"foo":"123","bar":"sdflkdfsjk","another":false}'], if (responses.length === 0) {
['eval', "return redis.call('set', 'sha', 'test')", '0'], monitorClient.quit(end)
['set', 'sha', 'test'], }
['get', 'baz'], })
['set', 'foo', 'bar" "s are " " good!"'], })
['mget', 'foo', 'baz'],
['subscribe', 'foo', 'baz']
];
var end = helper.callFuncAfter(done, 5);
monitorClient.set('foo', 'bar'); it('monitors returns strings in the rawOutput even with returnBuffers activated', function (done) {
monitorClient.flushdb(); if (process.platform === 'win32') {
monitorClient.monitor(function (err, res) { this.skip()
assert.strictEqual(res, 'OK'); }
client.mget('some', 'keys', 'foo', 'bar'); var monitorClient = redis.createClient({
client.set('json', JSON.stringify({ returnBuffers: true,
foo: '123', path: '/tmp/redis.sock'
bar: 'sdflkdfsjk', })
another: false
}));
client.eval("return redis.call('set', 'sha', 'test')", 0);
monitorClient.get('baz', function (err, res) {
assert.strictEqual(res, null);
end(err);
});
monitorClient.set('foo', 'bar" "s are " " good!"', function (err, res) {
assert.strictEqual(res, 'OK');
end(err);
});
monitorClient.mget('foo', 'baz', function (err, res) {
assert.strictEqual(res[0], 'bar" "s are " " good!"');
assert.strictEqual(res[1], null);
end(err);
});
monitorClient.subscribe('foo', 'baz', function (err, res) {
// The return value might change in v.3
// assert.strictEqual(res, 'baz');
// TODO: Fix the return value of subscribe calls
end(err);
});
});
monitorClient.on('monitor', function (time, args, rawOutput) { monitorClient.monitor(function (err, res) {
assert.strictEqual(monitorClient.monitoring, true); assert.strictEqual(err, null)
assert.deepEqual(args, responses.shift()); assert.strictEqual(monitorClient.monitoring, true)
assert(utils.monitorRegex.test(rawOutput), rawOutput); assert.strictEqual(res.inspect(), Buffer.from('OK').inspect())
if (responses.length === 0) { monitorClient.mget('hello', Buffer.from('world'))
monitorClient.quit(end); })
}
});
});
it('monitors returns strings in the rawOutput even with returnBuffers activated', function (done) { monitorClient.on('monitor', function (time, args, rawOutput) {
if (process.platform === 'win32') { assert.strictEqual(typeof rawOutput, 'string')
this.skip(); assert(utils.monitorRegex.test(rawOutput), rawOutput)
} assert.deepEqual(args, ['mget', 'hello', 'world'])
var monitorClient = redis.createClient({ // Quit immediately ends monitoring mode and therefore does not stream back the quit command
returnBuffers: true, monitorClient.quit(done)
path: '/tmp/redis.sock' })
}); })
monitorClient.monitor(function (err, res) { it('monitors reconnects properly and works with the offline queue', function (done) {
assert.strictEqual(monitorClient.monitoring, true); var called = false
assert.strictEqual(res.inspect(), new Buffer('OK').inspect()); client.monitor(helper.isString('OK'))
monitorClient.mget('hello', new Buffer('world')); client.mget('hello', 'world')
}); client.on('monitor', function (time, args, rawOutput) {
assert.strictEqual(client.monitoring, true)
assert(utils.monitorRegex.test(rawOutput), rawOutput)
assert.deepEqual(args, ['mget', 'hello', 'world'])
if (called) {
// End after a reconnect
return done()
}
client.stream.destroy()
client.mget('hello', 'world')
called = true
})
})
monitorClient.on('monitor', function (time, args, rawOutput) { it('monitors reconnects properly and works with the offline queue in a batch statement', function (done) {
assert.strictEqual(typeof rawOutput, 'string'); var called = false
assert(utils.monitorRegex.test(rawOutput), rawOutput); var multi = client.batch()
assert.deepEqual(args, ['mget', 'hello', 'world']); multi.monitor(helper.isString('OK'))
// Quit immediatly ends monitoring mode and therefore does not stream back the quit command multi.mget('hello', 'world')
monitorClient.quit(done); multi.exec(helper.isDeepEqual(['OK', [null, null]]))
}); client.on('monitor', function (time, args, rawOutput) {
}); assert.strictEqual(client.monitoring, true)
assert(utils.monitorRegex.test(rawOutput), rawOutput)
assert.deepEqual(args, ['mget', 'hello', 'world'])
if (called) {
// End after a reconnect
return done()
}
client.stream.destroy()
client.mget('hello', 'world')
called = true
})
})
it('monitors reconnects properly and works with the offline queue', function (done) { it('monitor activates even if the command could not be processed properly after a reconnect', function (done) {
var called = false; client.monitor(function (err, res) {
client.monitor(helper.isString('OK')); assert.strictEqual(err.code, 'UNCERTAIN_STATE')
client.mget('hello', 'world'); })
client.on('monitor', function (time, args, rawOutput) { client.on('error', function () {}) // Ignore error here
assert.strictEqual(client.monitoring, true); client.stream.destroy()
assert(utils.monitorRegex.test(rawOutput), rawOutput); var end = helper.callFuncAfter(done, 2)
assert.deepEqual(args, ['mget', 'hello', 'world']); client.on('monitor', function (time, args, rawOutput) {
if (called) { assert.strictEqual(client.monitoring, true)
// End after a reconnect end()
return done(); })
} client.on('reconnecting', function () {
client.stream.destroy(); client.get('foo', function (err, res) {
client.mget('hello', 'world'); assert(!err)
called = true; assert.strictEqual(client.monitoring, true)
}); end()
}); })
})
})
it('monitors reconnects properly and works with the offline queue in a batch statement', function (done) { it('monitors works in combination with the pub sub mode and the offline queue', function (done) {
var called = false; var responses = [
var multi = client.batch(); ['subscribe', '/foo', '/bar'],
multi.monitor(helper.isString('OK')); ['unsubscribe', '/bar'],
multi.mget('hello', 'world'); ['get', 'foo'],
multi.exec(function (err, res) { ['subscribe', '/foo'],
assert.deepEqual(res, ['OK', [null, null]]); ['subscribe', 'baz'],
}); ['unsubscribe', 'baz'],
client.on('monitor', function (time, args, rawOutput) { ['publish', '/foo', 'hello world']
assert.strictEqual(client.monitoring, true); ]
assert(utils.monitorRegex.test(rawOutput), rawOutput); var pub = redis.createClient()
assert.deepEqual(args, ['mget', 'hello', 'world']); pub.on('ready', function () {
if (called) { client.monitor(function (err, res) {
// End after a reconnect assert.strictEqual(err, null)
return done(); assert.strictEqual(res, 'OK')
} pub.get('foo', helper.isNull())
client.stream.destroy(); })
client.mget('hello', 'world'); client.subscribe('/foo', '/bar')
called = true; client.unsubscribe('/bar')
}); setTimeout(function () {
}); client.stream.destroy()
client.once('ready', function () {
it('monitor activates even if the command could not be processed properly after a reconnect', function (done) { pub.publish('/foo', 'hello world')
client.monitor(function (err, res) { })
assert.strictEqual(err.code, 'UNCERTAIN_STATE'); client.set('foo', 'bar', helper.isError())
}); client.subscribe('baz')
client.on('error', function (err) {}); // Ignore error here client.unsubscribe('baz')
client.stream.destroy(); }, 150)
var end = helper.callFuncAfter(done, 2); var called = false
client.on('monitor', function (time, args, rawOutput) { client.on('monitor', function (time, args, rawOutput) {
assert.strictEqual(client.monitoring, true); assert.deepEqual(args, responses.shift())
end(); assert(utils.monitorRegex.test(rawOutput), rawOutput)
}); if (responses.length === 0) {
client.on('reconnecting', function () { // The publish is called right after the reconnect and the monitor is called before the message is emitted.
client.get('foo', function (err, res) { // Therefore we have to wait till the next tick
assert(!err); process.nextTick(function () {
assert.strictEqual(client.monitoring, true); assert(called)
end(); client.quit(done)
}); pub.end(false)
}); })
}); }
})
it('monitors works in combination with the pub sub mode and the offline queue', function (done) { client.on('message', function (channel, msg) {
var responses = [ assert.strictEqual(channel, '/foo')
['subscribe', '/foo', '/bar'], assert.strictEqual(msg, 'hello world')
['unsubscribe', '/bar'], called = true
['get', 'foo'], })
['subscribe', '/foo'], })
['subscribe', 'baz'], })
['unsubscribe', 'baz'], })
['publish', '/foo', 'hello world'] })
];
var pub = redis.createClient();
pub.on('ready', function () {
client.monitor(function (err, res) {
assert.strictEqual(res, 'OK');
pub.get('foo', helper.isNull());
});
client.subscribe('/foo', '/bar');
client.unsubscribe('/bar');
setTimeout(function () {
client.stream.destroy();
client.once('ready', function () {
pub.publish('/foo', 'hello world');
});
client.set('foo', 'bar', helper.isError());
client.subscribe('baz');
client.unsubscribe('baz');
}, 150);
var called = false;
client.on('monitor', function (time, args, rawOutput) {
assert.deepEqual(args, responses.shift());
assert(utils.monitorRegex.test(rawOutput), rawOutput);
if (responses.length === 0) {
// The publish is called right after the reconnect and the monitor is called before the message is emitted.
// Therefore we have to wait till the next tick
process.nextTick(function () {
assert(called);
client.quit(done);
pub.end(false);
});
}
});
client.on('message', function (channel, msg) {
assert.strictEqual(channel, '/foo');
assert.strictEqual(msg, 'hello world');
called = true;
});
});
});
});
});

View File

@@ -1,111 +1,108 @@
'use strict'; 'use strict'
var assert = require('assert'); var assert = require('assert')
var config = require('../lib/config'); var config = require('../lib/config')
var helper = require('../helper'); var helper = require('../helper')
var redis = config.redis; var redis = config.redis
var uuid = require('uuid'); var uuid = require('uuid')
describe("The 'mset' method", function () { describe('The \'mset\' method', function () {
helper.allTests(function (ip, args) {
describe('using ' + ip, function () {
var key, value, key2, value2
helper.allTests(function (ip, args) { beforeEach(function () {
key = uuid.v4()
value = uuid.v4()
key2 = uuid.v4()
value2 = uuid.v4()
})
describe('using ' + ip, function () { describe('when not connected', function () {
var key, value, key2, value2; var client
beforeEach(function () { beforeEach(function (done) {
key = uuid.v4(); client = redis.createClient.apply(null, args)
value = uuid.v4(); client.once('ready', function () {
key2 = uuid.v4(); client.quit()
value2 = uuid.v4(); })
}); client.on('end', done)
})
describe('when not connected', function () { it('reports an error', function (done) {
var client; client.mset(key, value, key2, value2, function (err, res) {
assert(err.message.match(/The connection is already closed/))
done()
})
})
})
beforeEach(function (done) { describe('when connected', function () {
client = redis.createClient.apply(null, args); var client
client.once('ready', function () {
client.quit();
});
client.on('end', done);
});
it('reports an error', function (done) { beforeEach(function (done) {
client.mset(key, value, key2, value2, function (err, res) { client = redis.createClient.apply(null, args)
assert(err.message.match(/The connection is already closed/)); client.once('ready', function () {
done(); done()
}); })
}); })
});
describe('when connected', function () { afterEach(function () {
var client; client.end(true)
})
beforeEach(function (done) { describe('and a callback is specified', function () {
client = redis.createClient.apply(null, args); describe('with valid parameters', function () {
client.once('ready', function () { it('sets the value correctly', function (done) {
done(); client.mset(key, value, key2, value2, function (err) {
}); if (err) {
}); return done(err)
}
client.get(key, helper.isString(value))
client.get(key2, helper.isString(value2, done))
})
})
})
afterEach(function () { describe('with undefined \'key\' parameter and missing \'value\' parameter', function () {
client.end(true); it('reports an error', function (done) {
}); client.mset(undefined, function (err, res) {
helper.isError()(err, null)
done()
})
})
})
})
describe('and a callback is specified', function () { describe('and no callback is specified', function () {
describe('with valid parameters', function () { describe('with valid parameters', function () {
it('sets the value correctly', function (done) { it('sets the value correctly', function (done) {
client.mset(key, value, key2, value2, function (err) { client.mset(key, value2, key2, value)
if (err) { client.get(key, helper.isString(value2))
return done(err); client.get(key2, helper.isString(value, done))
} })
client.get(key, helper.isString(value));
client.get(key2, helper.isString(value2, done));
});
});
});
describe("with undefined 'key' parameter and missing 'value' parameter", function () { it('sets the value correctly with array syntax', function (done) {
it('reports an error', function (done) { client.mset([key, value2, key2, value])
client.mset(undefined, function (err, res) { client.get(key, helper.isString(value2))
helper.isError()(err, null); client.get(key2, helper.isString(value, done))
done(); })
}); })
});
});
}); describe('with undefined \'key\' and missing \'value\' parameter', function () {
// this behavior is different from the 'set' behavior.
it('emits an error', function (done) {
client.on('error', function (err) {
assert.strictEqual(err.message, 'ERR wrong number of arguments for \'mset\' command')
assert.strictEqual(err.name, 'ReplyError')
done()
})
describe('and no callback is specified', function () { client.mset()
describe('with valid parameters', function () { })
it('sets the value correctly', function (done) { })
client.mset(key, value2, key2, value); })
client.get(key, helper.isString(value2)); })
client.get(key2, helper.isString(value, done)); })
}); })
})
it('sets the value correctly with array syntax', function (done) {
client.mset([key, value2, key2, value]);
client.get(key, helper.isString(value2));
client.get(key2, helper.isString(value, done));
});
});
describe("with undefined 'key' and missing 'value' parameter", function () {
// this behavior is different from the 'set' behavior.
it('emits an error', function (done) {
client.on('error', function (err) {
assert.strictEqual(err.message, "ERR wrong number of arguments for 'mset' command");
assert.strictEqual(err.name, 'ReplyError');
done();
});
client.mset();
});
});
});
});
});
});
});

View File

@@ -1,38 +1,36 @@
'use strict'; 'use strict'
var config = require('../lib/config'); var config = require('../lib/config')
var helper = require('../helper'); var helper = require('../helper')
var redis = config.redis; var redis = config.redis
describe("The 'msetnx' method", function () { describe('The \'msetnx\' method', function () {
helper.allTests(function (ip, args) {
describe('using ' + ip, function () {
var client
helper.allTests(function (ip, args) { beforeEach(function (done) {
client = redis.createClient.apply(null, args)
client.once('ready', function () {
client.flushdb(done)
})
})
describe('using ' + ip, function () { it('if any keys exist entire operation fails', function (done) {
var client; client.mset(['mset1', 'val1', 'mset2', 'val2', 'mset3', 'val3'], helper.isString('OK'))
client.msetnx(['mset3', 'val3', 'mset4', 'val4'], helper.isNumber(0))
client.exists(['mset4'], helper.isNumber(0, done))
})
beforeEach(function (done) { it('sets multiple keys if all keys are not set', function (done) {
client = redis.createClient.apply(null, args); client.msetnx(['mset3', 'val3', 'mset4', 'val4'], helper.isNumber(1))
client.once('ready', function () { client.exists(['mset3'], helper.isNumber(1))
client.flushdb(done); client.exists(['mset3'], helper.isNumber(1, done))
}); })
});
it('if any keys exist entire operation fails', function (done) { afterEach(function () {
client.mset(['mset1', 'val1', 'mset2', 'val2', 'mset3', 'val3'], helper.isString('OK')); client.end(true)
client.msetnx(['mset3', 'val3', 'mset4', 'val4'], helper.isNumber(0)); })
client.exists(['mset4'], helper.isNumber(0, done)); })
}); })
})
it('sets multiple keys if all keys are not set', function (done) {
client.msetnx(['mset3', 'val3', 'mset4', 'val4'], helper.isNumber(1));
client.exists(['mset3'], helper.isNumber(1));
client.exists(['mset3'], helper.isNumber(1, done));
});
afterEach(function () {
client.end(true);
});
});
});
});

View File

@@ -1,35 +1,33 @@
'use strict'; 'use strict'
var assert = require('assert'); var assert = require('assert')
var config = require('../lib/config'); var config = require('../lib/config')
var helper = require('../helper'); var helper = require('../helper')
var redis = config.redis; var redis = config.redis
describe("The 'randomkey' method", function () { describe('The \'randomkey\' method', function () {
helper.allTests(function (ip, args) {
describe('using ' + ip, function () {
var client
helper.allTests(function (ip, args) { beforeEach(function (done) {
client = redis.createClient.apply(null, args)
client.once('ready', function () {
client.flushdb(done)
})
})
describe('using ' + ip, function () { it('returns a random key', function (done) {
var client; client.mset(['test keys 1', 'test val 1', 'test keys 2', 'test val 2'], helper.isString('OK'))
client.randomkey([], function (err, results) {
assert.strictEqual(true, /test keys.+/.test(results))
return done(err)
})
})
beforeEach(function (done) { afterEach(function () {
client = redis.createClient.apply(null, args); client.end(true)
client.once('ready', function () { })
client.flushdb(done); })
}); })
}); })
it('returns a random key', function (done) {
client.mset(['test keys 1', 'test val 1', 'test keys 2', 'test val 2'], helper.isString('OK'));
client.randomkey([], function (err, results) {
assert.strictEqual(true, /test keys.+/.test(results));
return done(err);
});
});
afterEach(function () {
client.end(true);
});
});
});
});

View File

@@ -1,38 +1,36 @@
'use strict'; 'use strict'
var config = require('../lib/config'); var config = require('../lib/config')
var helper = require('../helper'); var helper = require('../helper')
var redis = config.redis; var redis = config.redis
describe("The 'rename' method", function () { describe('The \'rename\' method', function () {
helper.allTests(function (ip, args) {
describe('using ' + ip, function () {
var client
helper.allTests(function (ip, args) { beforeEach(function (done) {
client = redis.createClient.apply(null, args)
client.once('ready', function () {
client.flushdb(done)
})
})
describe('using ' + ip, function () { it('populates the new key', function (done) {
var client; client.set(['foo', 'bar'], helper.isString('OK'))
client.rename(['foo', 'new foo'], helper.isString('OK'))
client.exists(['new foo'], helper.isNumber(1, done))
})
beforeEach(function (done) { it('removes the old key', function (done) {
client = redis.createClient.apply(null, args); client.set(['foo', 'bar'], helper.isString('OK'))
client.once('ready', function () { client.rename(['foo', 'new foo'], helper.isString('OK'))
client.flushdb(done); client.exists(['foo'], helper.isNumber(0, done))
}); })
});
it('populates the new key', function (done) { afterEach(function () {
client.set(['foo', 'bar'], helper.isString('OK')); client.end(true)
client.rename(['foo', 'new foo'], helper.isString('OK')); })
client.exists(['new foo'], helper.isNumber(1, done)); })
}); })
})
it('removes the old key', function (done) {
client.set(['foo', 'bar'], helper.isString('OK'));
client.rename(['foo', 'new foo'], helper.isString('OK'));
client.exists(['foo'], helper.isNumber(0, done));
});
afterEach(function () {
client.end(true);
});
});
});
});

View File

@@ -1,41 +1,39 @@
'use strict'; 'use strict'
var config = require('../lib/config'); var config = require('../lib/config')
var helper = require('../helper'); var helper = require('../helper')
var redis = config.redis; var redis = config.redis
describe("The 'renamenx' method", function () { describe('The \'renamenx\' method', function () {
helper.allTests(function (ip, args) {
describe('using ' + ip, function () {
var client
helper.allTests(function (ip, args) { beforeEach(function (done) {
client = redis.createClient.apply(null, args)
client.once('ready', function () {
client.flushdb(done)
})
})
describe('using ' + ip, function () { it('renames the key if target does not yet exist', function (done) {
var client; client.set('foo', 'bar', helper.isString('OK'))
client.renamenx('foo', 'foo2', helper.isNumber(1))
client.exists('foo', helper.isNumber(0))
client.exists(['foo2'], helper.isNumber(1, done))
})
beforeEach(function (done) { it('does not rename the key if the target exists', function (done) {
client = redis.createClient.apply(null, args); client.set('foo', 'bar', helper.isString('OK'))
client.once('ready', function () { client.set('foo2', 'apple', helper.isString('OK'))
client.flushdb(done); client.renamenx('foo', 'foo2', helper.isNumber(0))
}); client.exists('foo', helper.isNumber(1))
}); client.exists(['foo2'], helper.isNumber(1, done))
})
it('renames the key if target does not yet exist', function (done) { afterEach(function () {
client.set('foo', 'bar', helper.isString('OK')); client.end(true)
client.renamenx('foo', 'foo2', helper.isNumber(1)); })
client.exists('foo', helper.isNumber(0)); })
client.exists(['foo2'], helper.isNumber(1, done)); })
}); })
it('does not rename the key if the target exists', function (done) {
client.set('foo', 'bar', helper.isString('OK'));
client.set('foo2', 'apple', helper.isString('OK'));
client.renamenx('foo', 'foo2', helper.isNumber(0));
client.exists('foo', helper.isNumber(1));
client.exists(['foo2'], helper.isNumber(1, done));
});
afterEach(function () {
client.end(true);
});
});
});
});

View File

@@ -1,36 +1,34 @@
'use strict'; 'use strict'
var config = require('../lib/config'); var config = require('../lib/config')
var helper = require('../helper'); var helper = require('../helper')
var redis = config.redis; var redis = config.redis
var assert = require('assert'); var assert = require('assert')
describe("The 'rpush' command", function () { describe('The \'rpush\' command', function () {
helper.allTests(function (ip, args) {
describe('using ' + ip, function () {
var client
helper.allTests(function (ip, args) { beforeEach(function (done) {
client = redis.createClient.apply(null, args)
client.once('ready', function () {
client.flushdb(done)
})
})
describe('using ' + ip, function () { it('inserts multiple values at a time into a list', function (done) {
var client; client.rpush('test', ['list key', 'should be a list'])
client.lrange('test', 0, -1, function (err, res) {
assert.strictEqual(res[0], 'list key')
assert.strictEqual(res[1], 'should be a list')
done(err)
})
})
beforeEach(function (done) { afterEach(function () {
client = redis.createClient.apply(null, args); client.end(true)
client.once('ready', function () { })
client.flushdb(done); })
}); })
}); })
it('inserts multiple values at a time into a list', function (done) {
client.rpush('test', ['list key', 'should be a list']);
client.lrange('test', 0, -1, function (err, res) {
assert.equal(res[0], 'list key');
assert.equal(res[1], 'should be a list');
done(err);
});
});
afterEach(function () {
client.end(true);
});
});
});
});

View File

@@ -1,62 +1,60 @@
'use strict'; 'use strict'
var assert = require('assert'); var assert = require('assert')
var config = require('../lib/config'); var config = require('../lib/config')
var helper = require('../helper'); var helper = require('../helper')
var redis = config.redis; var redis = config.redis
describe("The 'sadd' method", function () { describe('The \'sadd\' method', function () {
helper.allTests(function (ip, args) {
describe('using ' + ip, function () {
var client
helper.allTests(function (ip, args) { beforeEach(function (done) {
client = redis.createClient.apply(null, args)
client.once('ready', function () {
client.flushdb(done)
})
})
describe('using ' + ip, function () { it('allows a single value to be added to the set', function (done) {
var client; client.sadd('set0', 'member0', helper.isNumber(1))
client.smembers('set0', function (err, res) {
assert.ok(~res.indexOf('member0'))
return done(err)
})
})
beforeEach(function (done) { it('does not add the same value to the set twice', function (done) {
client = redis.createClient.apply(null, args); client.sadd('set0', 'member0', helper.isNumber(1))
client.once('ready', function () { client.sadd('set0', 'member0', helper.isNumber(0, done))
client.flushdb(done); })
});
});
it('allows a single value to be added to the set', function (done) { it('allows multiple values to be added to the set', function (done) {
client.sadd('set0', 'member0', helper.isNumber(1)); client.sadd('set0', ['member0', 'member1', 'member2'], helper.isNumber(3))
client.smembers('set0', function (err, res) { client.smembers('set0', function (err, res) {
assert.ok(~res.indexOf('member0')); assert.strictEqual(res.length, 3)
return done(err); assert.ok(~res.indexOf('member0'))
}); assert.ok(~res.indexOf('member1'))
}); assert.ok(~res.indexOf('member2'))
return done(err)
})
})
it('does not add the same value to the set twice', function (done) { it('allows multiple values to be added to the set with a different syntax', function (done) {
client.sadd('set0', 'member0', helper.isNumber(1)); client.sadd(['set0', 'member0', 'member1', 'member2'], helper.isNumber(3))
client.sadd('set0', 'member0', helper.isNumber(0, done)); client.smembers('set0', function (err, res) {
}); assert.strictEqual(res.length, 3)
assert.ok(~res.indexOf('member0'))
assert.ok(~res.indexOf('member1'))
assert.ok(~res.indexOf('member2'))
return done(err)
})
})
it('allows multiple values to be added to the set', function (done) { afterEach(function () {
client.sadd('set0', ['member0', 'member1', 'member2'], helper.isNumber(3)); client.end(true)
client.smembers('set0', function (err, res) { })
assert.strictEqual(res.length, 3); })
assert.ok(~res.indexOf('member0')); })
assert.ok(~res.indexOf('member1')); })
assert.ok(~res.indexOf('member2'));
return done(err);
});
});
it('allows multiple values to be added to the set with a different syntax', function (done) {
client.sadd(['set0', 'member0', 'member1', 'member2'], helper.isNumber(3));
client.smembers('set0', function (err, res) {
assert.strictEqual(res.length, 3);
assert.ok(~res.indexOf('member0'));
assert.ok(~res.indexOf('member1'));
assert.ok(~res.indexOf('member2'));
return done(err);
});
});
afterEach(function () {
client.end(true);
});
});
});
});

View File

@@ -1,31 +1,29 @@
'use strict'; 'use strict'
var config = require('../lib/config'); var config = require('../lib/config')
var helper = require('../helper'); var helper = require('../helper')
var redis = config.redis; var redis = config.redis
describe("The 'scard' method", function () { describe('The \'scard\' method', function () {
helper.allTests(function (ip, args) {
describe('using ' + ip, function () {
var client
helper.allTests(function (ip, args) { beforeEach(function (done) {
client = redis.createClient.apply(null, args)
client.once('ready', function () {
client.flushdb(done)
})
})
describe('using ' + ip, function () { it('returns the number of values in a set', function (done) {
var client; client.sadd('foo', [1, 2, 3], helper.isNumber(3))
client.scard('foo', helper.isNumber(3, done))
})
beforeEach(function (done) { afterEach(function () {
client = redis.createClient.apply(null, args); client.end(true)
client.once('ready', function () { })
client.flushdb(done); })
}); })
}); })
it('returns the number of values in a set', function (done) {
client.sadd('foo', [1, 2, 3], helper.isNumber(3));
client.scard('foo', helper.isNumber(3, done));
});
afterEach(function () {
client.end(true);
});
});
});
});

View File

@@ -1,55 +1,44 @@
'use strict'; 'use strict'
var assert = require('assert'); var config = require('../lib/config')
var config = require('../lib/config'); var crypto = require('crypto')
var crypto = require('crypto'); var helper = require('../helper')
var helper = require('../helper'); var redis = config.redis
var redis = config.redis;
describe("The 'script' method", function () { describe('The \'script\' method', function () {
helper.allTests(function (ip, args) {
var command = 'return 99'
var commandSha = crypto.createHash('sha1').update(command).digest('hex')
helper.allTests(function (ip, args) { describe('using ' + ip, function () {
var command = 'return 99'; var client
var commandSha = crypto.createHash('sha1').update(command).digest('hex');
describe('using ' + ip, function () { beforeEach(function (done) {
var client; client = redis.createClient.apply(null, args)
client.once('ready', function () {
client.flushdb(done)
})
})
beforeEach(function (done) { afterEach(function () {
client = redis.createClient.apply(null, args); client.end(true)
client.once('ready', function () { })
client.flushdb(done);
});
});
afterEach(function () { it('loads script with client.script(\'load\')', function (done) {
client.end(true); client.script('load', command, helper.isString(commandSha, done))
}); })
it("loads script with client.script('load')", function (done) { it('allows a loaded script to be evaluated', function (done) {
client.script('load', command, function (err, result) { client.evalsha(commandSha, 0, helper.isNumber(99, done))
assert.strictEqual(result, commandSha); })
return done();
});
});
it('allows a loaded script to be evaluated', function (done) { it('allows a script to be loaded as part of a chained transaction', function (done) {
client.evalsha(commandSha, 0, helper.isNumber(99, done)); client.multi().script('load', command).exec(helper.isDeepEqual([commandSha], done))
}); })
it('allows a script to be loaded as part of a chained transaction', function (done) { it('allows a script to be loaded using a transaction\'s array syntax', function (done) {
client.multi().script('load', command).exec(function (err, result) { client.multi([['script', 'load', command]]).exec(helper.isDeepEqual([commandSha], done))
assert.strictEqual(result[0], commandSha); })
return done(); })
}); })
}); })
it("allows a script to be loaded using a transaction's array syntax", function (done) {
client.multi([['script', 'load', command]]).exec(function (err, result) {
assert.strictEqual(result[0], commandSha);
return done();
});
});
});
});
});

View File

@@ -1,47 +1,45 @@
'use strict'; 'use strict'
var assert = require('assert'); var assert = require('assert')
var config = require('../lib/config'); var config = require('../lib/config')
var helper = require('../helper'); var helper = require('../helper')
var redis = config.redis; var redis = config.redis
describe("The 'sdiff' method", function () { describe('The \'sdiff\' method', function () {
helper.allTests(function (ip, args) {
describe('using ' + ip, function () {
var client
helper.allTests(function (ip, args) { beforeEach(function (done) {
client = redis.createClient.apply(null, args)
client.once('ready', function () {
client.flushdb(done)
})
})
describe('using ' + ip, function () { it('returns set difference', function (done) {
var client; client.sadd('foo', 'x', helper.isNumber(1))
client.sadd('foo', ['a'], helper.isNumber(1))
client.sadd('foo', 'b', helper.isNumber(1))
client.sadd(['foo', 'c'], helper.isNumber(1))
beforeEach(function (done) { client.sadd(['bar', 'c', helper.isNumber(1)])
client = redis.createClient.apply(null, args);
client.once('ready', function () {
client.flushdb(done);
});
});
it('returns set difference', function (done) { client.sadd('baz', 'a', helper.isNumber(1))
client.sadd('foo', 'x', helper.isNumber(1)); client.sadd('baz', 'd', helper.isNumber(1))
client.sadd('foo', ['a'], helper.isNumber(1));
client.sadd('foo', 'b', helper.isNumber(1));
client.sadd(['foo', 'c'], helper.isNumber(1));
client.sadd(['bar', 'c', helper.isNumber(1)]); client.sdiff('foo', 'bar', 'baz', function (err, values) {
values.sort()
assert.strictEqual(values.length, 2)
assert.strictEqual(values[0], 'b')
assert.strictEqual(values[1], 'x')
return done(err)
})
})
client.sadd('baz', 'a', helper.isNumber(1)); afterEach(function () {
client.sadd('baz', 'd', helper.isNumber(1)); client.end(true)
})
client.sdiff('foo', 'bar', 'baz', function (err, values) { })
values.sort(); })
assert.equal(values.length, 2); })
assert.equal(values[0], 'b');
assert.equal(values[1], 'x');
return done(err);
});
});
afterEach(function () {
client.end(true);
});
});
});
});

View File

@@ -1,47 +1,45 @@
'use strict'; 'use strict'
var assert = require('assert'); var assert = require('assert')
var config = require('../lib/config'); var config = require('../lib/config')
var helper = require('../helper'); var helper = require('../helper')
var redis = config.redis; var redis = config.redis
describe("The 'sdiffstore' method", function () { describe('The \'sdiffstore\' method', function () {
helper.allTests(function (ip, args) {
describe('using ' + ip, function () {
var client
helper.allTests(function (ip, args) { beforeEach(function (done) {
client = redis.createClient.apply(null, args)
client.once('ready', function () {
client.flushdb(done)
})
})
describe('using ' + ip, function () { it('calculates set difference ands stores it in a key', function (done) {
var client; client.sadd('foo', 'x', helper.isNumber(1))
client.sadd('foo', 'a', helper.isNumber(1))
client.sadd('foo', 'b', helper.isNumber(1))
client.sadd('foo', 'c', helper.isNumber(1))
beforeEach(function (done) { client.sadd('bar', 'c', helper.isNumber(1))
client = redis.createClient.apply(null, args);
client.once('ready', function () {
client.flushdb(done);
});
});
it('calculates set difference ands stores it in a key', function (done) { client.sadd('baz', 'a', helper.isNumber(1))
client.sadd('foo', 'x', helper.isNumber(1)); client.sadd('baz', 'd', helper.isNumber(1))
client.sadd('foo', 'a', helper.isNumber(1));
client.sadd('foo', 'b', helper.isNumber(1));
client.sadd('foo', 'c', helper.isNumber(1));
client.sadd('bar', 'c', helper.isNumber(1)); client.sdiffstore('quux', 'foo', 'bar', 'baz', helper.isNumber(2))
client.sadd('baz', 'a', helper.isNumber(1)); client.smembers('quux', function (err, values) {
client.sadd('baz', 'd', helper.isNumber(1)); var members = values.sort()
assert.deepEqual(members, [ 'b', 'x' ])
return done(err)
})
})
client.sdiffstore('quux', 'foo', 'bar', 'baz', helper.isNumber(2)); afterEach(function () {
client.end(true)
client.smembers('quux', function (err, values) { })
var members = values.sort(); })
assert.deepEqual(members, [ 'b', 'x' ]); })
return done(err); })
});
});
afterEach(function () {
client.end(true);
});
});
});
});

View File

@@ -1,126 +1,124 @@
'use strict'; 'use strict'
var assert = require('assert'); var assert = require('assert')
var config = require('../lib/config'); var config = require('../lib/config')
var helper = require('../helper'); var helper = require('../helper')
var redis = config.redis; var redis = config.redis
describe("The 'select' method", function () { describe('The \'select\' method', function () {
helper.allTests(function (ip, args) {
describe('using ' + ip, function () {
describe('when not connected', function () {
var client
helper.allTests(function (ip, args) { beforeEach(function (done) {
client = redis.createClient.apply(null, args)
client.once('ready', function () {
client.quit()
})
client.on('end', done)
})
describe('using ' + ip, function () { it('returns an error if redis is not connected', function (done) {
describe('when not connected', function () { var buffering = client.select(1, function (err, res) {
var client; assert(err.message.match(/The connection is already closed/))
done()
})
assert(typeof buffering === 'boolean')
})
})
beforeEach(function (done) { describe('when connected', function () {
client = redis.createClient.apply(null, args); var client
client.once('ready', function () {
client.quit();
});
client.on('end', done);
});
it('returns an error if redis is not connected', function (done) { beforeEach(function (done) {
var buffering = client.select(1, function (err, res) { client = redis.createClient.apply(null, args)
assert(err.message.match(/The connection is already closed/)); client.once('ready', function () {
done(); client.flushdb(done)
}); })
assert(typeof buffering === 'boolean'); })
});
});
describe('when connected', function () { afterEach(function () {
var client; client.end(true)
})
beforeEach(function (done) { it('changes the database and calls the callback', function (done) {
client = redis.createClient.apply(null, args); // default value of null means database 0 will be used.
client.once('ready', function () { assert.strictEqual(client.selectedDb, undefined, 'default db should be undefined')
client.flushdb(done); var buffering = client.select(1, function (err, res) {
}); helper.isNotError()(err, res)
}); assert.strictEqual(client.selectedDb, 1, 'db should be 1 after select')
done()
})
assert(typeof buffering === 'boolean')
})
afterEach(function () { describe('and a callback is specified', function () {
client.end(true); describe('with a valid db index', function () {
}); it('selects the appropriate database', function (done) {
assert.strictEqual(client.selectedDb, undefined, 'default db should be undefined')
client.select(1, function (err) {
assert.strictEqual(err, null)
assert.strictEqual(client.selectedDb, 1, 'we should have selected the new valid DB')
done()
})
})
})
it('changes the database and calls the callback', function (done) { describe('with an invalid db index', function () {
// default value of null means database 0 will be used. it('returns an error', function (done) {
assert.strictEqual(client.selectedDb, undefined, 'default db should be undefined'); assert.strictEqual(client.selectedDb, undefined, 'default db should be undefined')
var buffering = client.select(1, function (err, res) { client.select(9999, function (err) {
helper.isNotError()(err, res); assert.strictEqual(err.code, 'ERR')
assert.strictEqual(client.selectedDb, 1, 'db should be 1 after select'); assert.strictEqual(err.message, 'ERR invalid DB index')
done(); done()
}); })
assert(typeof buffering === 'boolean'); })
}); })
})
describe('and a callback is specified', function () { describe('and no callback is specified', function () {
describe('with a valid db index', function () { describe('with a valid db index', function () {
it('selects the appropriate database', function (done) { it('selects the appropriate database', function (done) {
assert.strictEqual(client.selectedDb, undefined, 'default db should be undefined'); assert.strictEqual(client.selectedDb, undefined, 'default db should be undefined')
client.select(1, function (err) { client.select(1)
assert.equal(err, null); setTimeout(function () {
assert.equal(client.selectedDb, 1, 'we should have selected the new valid DB'); assert.strictEqual(client.selectedDb, 1, 'we should have selected the new valid DB')
done(); done()
}); }, 25)
}); })
}); })
describe('with an invalid db index', function () { describe('with an invalid db index', function () {
it('returns an error', function (done) { it('emits an error when callback not provided', function (done) {
assert.strictEqual(client.selectedDb, undefined, 'default db should be undefined'); assert.strictEqual(client.selectedDb, undefined, 'default db should be undefined')
client.select(9999, function (err) {
assert.equal(err.code, 'ERR');
assert.equal(err.message, 'ERR invalid DB index');
done();
});
});
});
});
describe('and no callback is specified', function () { client.on('error', function (err) {
describe('with a valid db index', function () { assert.strictEqual(err.command, 'SELECT')
it('selects the appropriate database', function (done) { assert.strictEqual(err.message, 'ERR invalid DB index')
assert.strictEqual(client.selectedDb, undefined, 'default db should be undefined'); done()
client.select(1); })
setTimeout(function () {
assert.equal(client.selectedDb, 1, 'we should have selected the new valid DB');
done();
}, 25);
});
});
describe('with an invalid db index', function () { client.select(9999)
it('emits an error when callback not provided', function (done) { })
assert.strictEqual(client.selectedDb, undefined, 'default db should be undefined'); })
})
client.on('error', function (err) { describe('reconnection occurs', function () {
assert.strictEqual(err.command, 'SELECT'); it('selects the appropriate database after a reconnect', function (done) {
assert.equal(err.message, 'ERR invalid DB index'); assert.strictEqual(client.selectedDb, undefined, 'default db should be undefined')
done(); client.select(3)
}); client.set('foo', 'bar', function () {
client.stream.destroy()
client.select(9999); })
}); client.once('ready', function () {
}); assert.strictEqual(client.selectedDb, 3)
}); assert(typeof client.serverInfo.db3 === 'object')
done()
describe('reconnection occurs', function () { })
it('selects the appropriate database after a reconnect', function (done) { })
assert.strictEqual(client.selectedDb, undefined, 'default db should be undefined'); })
client.select(3); })
client.set('foo', 'bar', function () { })
client.stream.destroy(); })
}); })
client.once('ready', function () {
assert.strictEqual(client.selectedDb, 3);
assert(typeof client.serverInfo.db3 === 'object');
done();
});
});
});
});
});
});
});

View File

@@ -1,170 +1,168 @@
'use strict'; 'use strict'
var assert = require('assert'); var assert = require('assert')
var config = require('../lib/config'); var config = require('../lib/config')
var helper = require('../helper'); var helper = require('../helper')
var redis = config.redis; var redis = config.redis
var uuid = require('uuid'); var uuid = require('uuid')
describe("The 'set' method", function () { describe('The \'set\' method', function () {
helper.allTests(function (ip, args) {
describe('using ' + ip, function () {
var key, value
helper.allTests(function (ip, args) { beforeEach(function () {
key = uuid.v4()
value = uuid.v4()
})
describe('using ' + ip, function () { describe('when not connected', function () {
var key, value; var client
beforeEach(function () { beforeEach(function (done) {
key = uuid.v4(); client = redis.createClient.apply(null, args)
value = uuid.v4(); client.once('ready', function () {
}); client.quit()
})
client.on('end', done)
})
describe('when not connected', function () { it('reports an error', function (done) {
var client; client.set(key, value, function (err, res) {
assert(err.message.match(/The connection is already closed/))
done()
})
})
})
beforeEach(function (done) { describe('when connected', function () {
client = redis.createClient.apply(null, args); var client
client.once('ready', function () {
client.quit();
});
client.on('end', done);
});
it('reports an error', function (done) { beforeEach(function (done) {
client.set(key, value, function (err, res) { client = redis.createClient.apply(null, args)
assert(err.message.match(/The connection is already closed/)); client.once('ready', function () {
done(); client.flushdb(done)
}); })
}); })
});
describe('when connected', function () { afterEach(function () {
var client; client.end(true)
})
beforeEach(function (done) { describe('and a callback is specified', function () {
client = redis.createClient.apply(null, args); describe('with valid parameters', function () {
client.once('ready', function () { it('sets the value correctly', function (done) {
client.flushdb(done); client.set(key, value, function (err, res) {
}); helper.isNotError()(err, res)
}); client.get(key, function (err, res) {
helper.isString(value)(err, res)
done()
})
})
})
afterEach(function () { it('set expire date in seconds', function (done) {
client.end(true); client.set('foo', 'bar', 'ex', 10, helper.isString('OK'))
}); client.pttl('foo', function (err, res) {
assert(res >= 10000 - 50) // Max 50 ms should have passed
assert(res <= 10000) // Max possible should be 10.000
done(err)
})
})
describe('and a callback is specified', function () { it('set expire date in milliseconds', function (done) {
describe('with valid parameters', function () { client.set('foo', 'bar', 'px', 100, helper.isString('OK'))
it('sets the value correctly', function (done) { client.pttl('foo', function (err, res) {
client.set(key, value, function (err, res) { assert(res >= 50) // Max 50 ms should have passed
helper.isNotError()(err, res); assert(res <= 100) // Max possible should be 100
client.get(key, function (err, res) { done(err)
helper.isString(value)(err, res); })
done(); })
});
});
});
it('set expire date in seconds', function (done) { it('only set the key if (not) already set', function (done) {
client.set('foo', 'bar', 'ex', 10, helper.isString('OK')); client.set('foo', 'bar', 'NX', helper.isString('OK'))
client.pttl('foo', function (err, res) { client.set('foo', 'bar', 'nx', helper.isNull())
assert(res >= 10000 - 50); // Max 50 ms should have passed client.set('foo', 'bar', 'EX', '10', 'XX', helper.isString('OK'))
assert(res <= 10000); // Max possible should be 10.000 client.ttl('foo', function (err, res) {
done(err); assert(res >= 9) // Min 9s should be left
}); assert(res <= 10) // Max 10s should be left
}); done(err)
})
})
})
it('set expire date in milliseconds', function (done) { describe('reports an error with invalid parameters', function () {
client.set('foo', 'bar', 'px', 100, helper.isString('OK')); it('undefined \'key\' and missing \'value\' parameter', function (done) {
client.pttl('foo', function (err, res) { client.set(undefined, function (err, res) {
assert(res >= 50); // Max 50 ms should have passed helper.isError()(err, null)
assert(res <= 100); // Max possible should be 100 assert.strictEqual(err.command, 'SET')
done(err); done()
}); })
}); })
it('only set the key if (not) already set', function (done) { it('empty array as second parameter', function (done) {
client.set('foo', 'bar', 'NX', helper.isString('OK')); client.set('foo', [], function (err, res) {
client.set('foo', 'bar', 'nx', helper.isNull()); assert.strictEqual(err.message, 'ERR wrong number of arguments for \'set\' command')
client.set('foo', 'bar', 'EX', '10', 'XX', helper.isString('OK')); done()
client.ttl('foo', function (err, res) { })
assert(res >= 9); // Min 9s should be left })
assert(res <= 10); // Max 10s should be left })
done(err); })
});
});
});
describe('reports an error with invalid parameters', function () { describe('and no callback is specified', function () {
it("undefined 'key' and missing 'value' parameter", function (done) { describe('with valid parameters', function () {
client.set(undefined, function (err, res) { it('sets the value correctly', function (done) {
helper.isError()(err, null); client.set(key, value)
assert.equal(err.command, 'SET'); client.get(key, helper.isString(value, done))
done(); })
});
});
it('empty array as second parameter', function (done) { it('sets the value correctly even if the callback is explicitly set to undefined', function (done) {
client.set('foo', [], function (err, res) { client.set(key, value, undefined)
assert.strictEqual(err.message, "ERR wrong number of arguments for 'set' command"); client.get(key, helper.isString(value, done))
done(); })
});
});
});
});
describe('and no callback is specified', function () { it('sets the value correctly with the array syntax', function (done) {
describe('with valid parameters', function () { client.set([key, value])
it('sets the value correctly', function (done) { client.get(key, helper.isString(value, done))
client.set(key, value); })
client.get(key, helper.isString(value, done)); })
});
it('sets the value correctly even if the callback is explicitly set to undefined', function (done) { describe('with undefined \'key\' and missing \'value\' parameter', function () {
client.set(key, value, undefined); it('emits an error without callback', function (done) {
client.get(key, helper.isString(value, done)); client.on('error', function (err) {
}); assert.strictEqual(err.message, 'ERR wrong number of arguments for \'set\' command')
assert.strictEqual(err.command, 'SET')
done()
})
client.set(undefined)
})
})
it('sets the value correctly with the array syntax', function (done) { // TODO: This test has to be refactored from v.3.0 on to expect an error instead
client.set([key, value]); it('converts null to \'null\'', function (done) {
client.get(key, helper.isString(value, done)); client.set('foo', null)
}); client.get('foo', helper.isString('null', done))
}); })
describe("with undefined 'key' and missing 'value' parameter", function () { it('emit an error with only the key set', function (done) {
it('emits an error without callback', function (done) { client.on('error', function (err) {
client.on('error', function (err) { assert.strictEqual(err.message, 'ERR wrong number of arguments for \'set\' command')
assert.equal(err.message, "ERR wrong number of arguments for 'set' command"); done()
assert.equal(err.command, 'SET'); })
done();
});
client.set(undefined);
});
});
// TODO: This test has to be refactored from v.3.0 on to expect an error instead client.set('foo')
it("converts null to 'null'", function (done) { })
client.set('foo', null);
client.get('foo', helper.isString('null', done));
});
it('emit an error with only the key set', function (done) { it('emit an error without any parameters', function (done) {
client.on('error', function (err) { client.once('error', function (err) {
assert.equal(err.message, "ERR wrong number of arguments for 'set' command"); assert.strictEqual(err.message, 'ERR wrong number of arguments for \'set\' command')
done(); assert.strictEqual(err.command, 'SET')
}); done()
})
client.set('foo'); client.set()
}); })
})
it('emit an error without any parameters', function (done) { })
client.once('error', function (err) { })
assert.equal(err.message, "ERR wrong number of arguments for 'set' command"); })
assert.equal(err.command, 'SET'); })
done();
});
client.set();
});
});
});
});
});
});

View File

@@ -1,37 +1,36 @@
'use strict'; 'use strict'
var assert = require('assert'); var assert = require('assert')
var config = require('../lib/config'); var config = require('../lib/config')
var helper = require('../helper'); var helper = require('../helper')
var redis = config.redis; var redis = config.redis
describe("The 'setex' method", function () { describe('The \'setex\' method', function () {
helper.allTests(function (ip, args) {
describe('using ' + ip, function () {
var client
helper.allTests(function (ip, args) { beforeEach(function (done) {
client = redis.createClient.apply(null, args)
client.once('ready', function () {
client.flushdb(done)
})
})
describe('using ' + ip, function () { it('sets a key with an expiry', function (done) {
var client; client.setex(['setex key', '100', 'setex val'], helper.isString('OK'))
var buffering = client.exists(['setex key'], helper.isNumber(1))
assert(typeof buffering === 'boolean')
client.ttl(['setex key'], function (err, ttl) {
assert.strictEqual(err, null)
assert(ttl > 0)
return done()
})
})
beforeEach(function (done) { afterEach(function () {
client = redis.createClient.apply(null, args); client.end(true)
client.once('ready', function () { })
client.flushdb(done); })
}); })
}); })
it('sets a key with an expiry', function (done) {
client.setex(['setex key', '100', 'setex val'], helper.isString('OK'));
var buffering = client.exists(['setex key'], helper.isNumber(1));
assert(typeof buffering === 'boolean');
client.ttl(['setex key'], function (err, ttl) {
assert(ttl > 0);
return done();
});
});
afterEach(function () {
client.end(true);
});
});
});
});

View File

@@ -1,37 +1,35 @@
'use strict'; 'use strict'
var config = require('../lib/config'); var config = require('../lib/config')
var helper = require('../helper'); var helper = require('../helper')
var redis = config.redis; var redis = config.redis
describe("The 'setnx' method", function () { describe('The \'setnx\' method', function () {
helper.allTests(function (ip, args) {
describe('using ' + ip, function () {
var client
helper.allTests(function (ip, args) { beforeEach(function (done) {
client = redis.createClient.apply(null, args)
client.once('ready', function () {
client.flushdb(done)
})
})
describe('using ' + ip, function () { it('sets key if it does not have a value', function (done) {
var client; client.setnx('foo', 'banana', helper.isNumber(1))
client.get('foo', helper.isString('banana', done))
})
beforeEach(function (done) { it('does not set key if it already has a value', function (done) {
client = redis.createClient.apply(null, args); client.set('foo', 'bar', helper.isString('OK'))
client.once('ready', function () { client.setnx('foo', 'banana', helper.isNumber(0))
client.flushdb(done); client.get('foo', helper.isString('bar', done))
}); })
});
it('sets key if it does not have a value', function (done) { afterEach(function () {
client.setnx('foo', 'banana', helper.isNumber(1)); client.end(true)
client.get('foo', helper.isString('banana', done)); })
}); })
})
it('does not set key if it already has a value', function (done) { })
client.set('foo', 'bar', helper.isString('OK'));
client.setnx('foo', 'banana', helper.isNumber(0));
client.get('foo', helper.isString('bar', done));
});
afterEach(function () {
client.end(true);
});
});
});
});

View File

@@ -1,63 +1,61 @@
'use strict'; 'use strict'
var assert = require('assert'); var assert = require('assert')
var config = require('../lib/config'); var config = require('../lib/config')
var helper = require('../helper'); var helper = require('../helper')
var redis = config.redis; var redis = config.redis
describe("The 'sinter' method", function () { describe('The \'sinter\' method', function () {
helper.allTests(function (ip, args) {
describe('using ' + ip, function () {
var client
helper.allTests(function (ip, args) { beforeEach(function (done) {
client = redis.createClient.apply(null, args)
client.once('ready', function () {
client.flushdb(done)
})
})
describe('using ' + ip, function () { it('handles two sets being intersected', function (done) {
var client; client.sadd('sa', 'a', helper.isNumber(1))
client.sadd('sa', 'b', helper.isNumber(1))
client.sadd('sa', 'c', helper.isNumber(1))
beforeEach(function (done) { client.sadd('sb', 'b', helper.isNumber(1))
client = redis.createClient.apply(null, args); client.sadd('sb', 'c', helper.isNumber(1))
client.once('ready', function () { client.sadd('sb', 'd', helper.isNumber(1))
client.flushdb(done);
});
});
it('handles two sets being intersected', function (done) { client.sinter('sa', 'sb', function (err, intersection) {
client.sadd('sa', 'a', helper.isNumber(1)); assert.strictEqual(intersection.length, 2)
client.sadd('sa', 'b', helper.isNumber(1)); assert.deepEqual(intersection.sort(), [ 'b', 'c' ])
client.sadd('sa', 'c', helper.isNumber(1)); return done(err)
})
})
client.sadd('sb', 'b', helper.isNumber(1)); it('handles three sets being intersected', function (done) {
client.sadd('sb', 'c', helper.isNumber(1)); client.sadd('sa', 'a', helper.isNumber(1))
client.sadd('sb', 'd', helper.isNumber(1)); client.sadd('sa', 'b', helper.isNumber(1))
client.sadd('sa', 'c', helper.isNumber(1))
client.sinter('sa', 'sb', function (err, intersection) { client.sadd('sb', 'b', helper.isNumber(1))
assert.equal(intersection.length, 2); client.sadd('sb', 'c', helper.isNumber(1))
assert.deepEqual(intersection.sort(), [ 'b', 'c' ]); client.sadd('sb', 'd', helper.isNumber(1))
return done(err);
});
});
it('handles three sets being intersected', function (done) { client.sadd('sc', 'c', helper.isNumber(1))
client.sadd('sa', 'a', helper.isNumber(1)); client.sadd('sc', 'd', helper.isNumber(1))
client.sadd('sa', 'b', helper.isNumber(1)); client.sadd('sc', 'e', helper.isNumber(1))
client.sadd('sa', 'c', helper.isNumber(1));
client.sadd('sb', 'b', helper.isNumber(1)); client.sinter('sa', 'sb', 'sc', function (err, intersection) {
client.sadd('sb', 'c', helper.isNumber(1)); assert.strictEqual(intersection.length, 1)
client.sadd('sb', 'd', helper.isNumber(1)); assert.strictEqual(intersection[0], 'c')
return done(err)
})
})
client.sadd('sc', 'c', helper.isNumber(1)); afterEach(function () {
client.sadd('sc', 'd', helper.isNumber(1)); client.end(true)
client.sadd('sc', 'e', helper.isNumber(1)); })
})
client.sinter('sa', 'sb', 'sc', function (err, intersection) { })
assert.equal(intersection.length, 1); })
assert.equal(intersection[0], 'c');
return done(err);
});
});
afterEach(function () {
client.end(true);
});
});
});
});

View File

@@ -1,48 +1,46 @@
'use strict'; 'use strict'
var assert = require('assert'); var assert = require('assert')
var config = require('../lib/config'); var config = require('../lib/config')
var helper = require('../helper'); var helper = require('../helper')
var redis = config.redis; var redis = config.redis
describe("The 'sinterstore' method", function () { describe('The \'sinterstore\' method', function () {
helper.allTests(function (ip, args) {
describe('using ' + ip, function () {
var client
helper.allTests(function (ip, args) { beforeEach(function (done) {
client = redis.createClient.apply(null, args)
client.once('ready', function () {
client.flushdb(done)
})
})
describe('using ' + ip, function () { it('calculates set intersection and stores it in a key', function (done) {
var client; client.sadd('sa', 'a', helper.isNumber(1))
client.sadd('sa', 'b', helper.isNumber(1))
client.sadd('sa', 'c', helper.isNumber(1))
beforeEach(function (done) { client.sadd('sb', 'b', helper.isNumber(1))
client = redis.createClient.apply(null, args); client.sadd('sb', 'c', helper.isNumber(1))
client.once('ready', function () { client.sadd('sb', 'd', helper.isNumber(1))
client.flushdb(done);
});
});
it('calculates set intersection and stores it in a key', function (done) { client.sadd('sc', 'c', helper.isNumber(1))
client.sadd('sa', 'a', helper.isNumber(1)); client.sadd('sc', 'd', helper.isNumber(1))
client.sadd('sa', 'b', helper.isNumber(1)); client.sadd('sc', 'e', helper.isNumber(1))
client.sadd('sa', 'c', helper.isNumber(1));
client.sadd('sb', 'b', helper.isNumber(1)); client.sinterstore('foo', 'sa', 'sb', 'sc', helper.isNumber(1))
client.sadd('sb', 'c', helper.isNumber(1));
client.sadd('sb', 'd', helper.isNumber(1));
client.sadd('sc', 'c', helper.isNumber(1)); client.smembers('foo', function (err, members) {
client.sadd('sc', 'd', helper.isNumber(1)); assert.deepEqual(members, [ 'c' ])
client.sadd('sc', 'e', helper.isNumber(1)); return done(err)
})
})
client.sinterstore('foo', 'sa', 'sb', 'sc', helper.isNumber(1)); afterEach(function () {
client.end(true)
client.smembers('foo', function (err, members) { })
assert.deepEqual(members, [ 'c' ]); })
return done(err); })
}); })
});
afterEach(function () {
client.end(true);
});
});
});
});

View File

@@ -1,35 +1,33 @@
'use strict'; 'use strict'
var config = require('../lib/config'); var config = require('../lib/config')
var helper = require('../helper'); var helper = require('../helper')
var redis = config.redis; var redis = config.redis
describe("The 'sismember' method", function () { describe('The \'sismember\' method', function () {
helper.allTests(function (ip, args) {
describe('using ' + ip, function () {
var client
helper.allTests(function (ip, args) { beforeEach(function (done) {
client = redis.createClient.apply(null, args)
client.once('ready', function () {
client.flushdb(done)
})
})
describe('using ' + ip, function () { it('returns 0 if the value is not in the set', function (done) {
var client; client.sismember('foo', 'banana', helper.isNumber(0, done))
})
beforeEach(function (done) { it('returns 1 if the value is in the set', function (done) {
client = redis.createClient.apply(null, args); client.sadd('foo', 'banana', helper.isNumber(1))
client.once('ready', function () { client.sismember('foo', 'banana', helper.isNumber(1, done))
client.flushdb(done); })
});
});
it('returns 0 if the value is not in the set', function (done) { afterEach(function () {
client.sismember('foo', 'banana', helper.isNumber(0, done)); client.end(true)
}); })
})
it('returns 1 if the value is in the set', function (done) { })
client.sadd('foo', 'banana', helper.isNumber(1)); })
client.sismember('foo', 'banana', helper.isNumber(1, done));
});
afterEach(function () {
client.end(true);
});
});
});
});

View File

@@ -1,41 +1,39 @@
'use strict'; 'use strict'
var assert = require('assert'); var assert = require('assert')
var config = require('../lib/config'); var config = require('../lib/config')
var helper = require('../helper'); var helper = require('../helper')
var redis = config.redis; var redis = config.redis
describe("The 'slowlog' method", function () { describe('The \'slowlog\' method', function () {
helper.allTests(function (ip, args) {
describe('using ' + ip, function () {
var client
helper.allTests(function (ip, args) { beforeEach(function (done) {
client = redis.createClient.apply(null, args)
client.once('ready', function () {
client.flushdb(done)
})
})
describe('using ' + ip, function () { it('logs operations in slowlog', function (done) {
var client; client.config('set', 'slowlog-log-slower-than', 0, helper.isString('OK'))
client.slowlog('reset', helper.isString('OK'))
client.set('foo', 'bar', helper.isString('OK'))
client.get('foo', helper.isString('bar'))
client.slowlog('get', function (err, res) {
assert.strictEqual(res.length, 3)
assert.strictEqual(res[0][3].length, 2)
assert.deepEqual(res[1][3], ['set', 'foo', 'bar'])
assert.deepEqual(res[2][3], ['slowlog', 'reset'])
return done(err)
})
})
beforeEach(function (done) { afterEach(function () {
client = redis.createClient.apply(null, args); client.end(true)
client.once('ready', function () { })
client.flushdb(done); })
}); })
}); })
it('logs operations in slowlog', function (done) {
client.config('set', 'slowlog-log-slower-than', 0, helper.isString('OK'));
client.slowlog('reset', helper.isString('OK'));
client.set('foo', 'bar', helper.isString('OK'));
client.get('foo', helper.isString('bar'));
client.slowlog('get', function (err, res) {
assert.equal(res.length, 3);
assert.equal(res[0][3].length, 2);
assert.deepEqual(res[1][3], ['set', 'foo', 'bar']);
assert.deepEqual(res[2][3], ['slowlog', 'reset']);
return done(err);
});
});
afterEach(function () {
client.end(true);
});
});
});
});

View File

@@ -1,38 +1,36 @@
'use strict'; 'use strict'
var assert = require('assert'); var assert = require('assert')
var config = require('../lib/config'); var config = require('../lib/config')
var helper = require('../helper'); var helper = require('../helper')
var redis = config.redis; var redis = config.redis
describe("The 'smembers' method", function () { describe('The \'smembers\' method', function () {
helper.allTests(function (ip, args) {
describe('using ' + ip, function () {
var client
helper.allTests(function (ip, args) { beforeEach(function (done) {
client = redis.createClient.apply(null, args)
client.once('ready', function () {
client.flushdb(done)
})
})
describe('using ' + ip, function () { it('returns all values in a set', function (done) {
var client; client.sadd('foo', 'x', helper.isNumber(1))
client.sadd('foo', 'y', helper.isNumber(1))
client.smembers('foo', function (err, values) {
assert.strictEqual(values.length, 2)
var members = values.sort()
assert.deepEqual(members, [ 'x', 'y' ])
return done(err)
})
})
beforeEach(function (done) { afterEach(function () {
client = redis.createClient.apply(null, args); client.end(true)
client.once('ready', function () { })
client.flushdb(done); })
}); })
}); })
it('returns all values in a set', function (done) {
client.sadd('foo', 'x', helper.isNumber(1));
client.sadd('foo', 'y', helper.isNumber(1));
client.smembers('foo', function (err, values) {
assert.equal(values.length, 2);
var members = values.sort();
assert.deepEqual(members, [ 'x', 'y' ]);
return done(err);
});
});
afterEach(function () {
client.end(true);
});
});
});
});

View File

@@ -1,40 +1,38 @@
'use strict'; 'use strict'
var config = require('../lib/config'); var config = require('../lib/config')
var helper = require('../helper'); var helper = require('../helper')
var redis = config.redis; var redis = config.redis
describe("The 'smove' method", function () { describe('The \'smove\' method', function () {
helper.allTests(function (ip, args) {
describe('using ' + ip, function () {
var client
helper.allTests(function (ip, args) { beforeEach(function (done) {
client = redis.createClient.apply(null, args)
client.once('ready', function () {
client.flushdb(done)
})
})
describe('using ' + ip, function () { it('moves a value to a set that does not yet exist', function (done) {
var client; client.sadd('foo', 'x', helper.isNumber(1))
client.smove('foo', 'bar', 'x', helper.isNumber(1))
client.sismember('foo', 'x', helper.isNumber(0))
client.sismember('bar', 'x', helper.isNumber(1, done))
})
beforeEach(function (done) { it('does not move a value if it does not exist in the first set', function (done) {
client = redis.createClient.apply(null, args); client.sadd('foo', 'x', helper.isNumber(1))
client.once('ready', function () { client.smove('foo', 'bar', 'y', helper.isNumber(0))
client.flushdb(done); client.sismember('foo', 'y', helper.isNumber(0))
}); client.sismember('bar', 'y', helper.isNumber(0, done))
}); })
it('moves a value to a set that does not yet exist', function (done) { afterEach(function () {
client.sadd('foo', 'x', helper.isNumber(1)); client.end(true)
client.smove('foo', 'bar', 'x', helper.isNumber(1)); })
client.sismember('foo', 'x', helper.isNumber(0)); })
client.sismember('bar', 'x', helper.isNumber(1, done)); })
}); })
it('does not move a value if it does not exist in the first set', function (done) {
client.sadd('foo', 'x', helper.isNumber(1));
client.smove('foo', 'bar', 'y', helper.isNumber(0));
client.sismember('foo', 'y', helper.isNumber(0));
client.sismember('bar', 'y', helper.isNumber(0, done));
});
afterEach(function () {
client.end(true);
});
});
});
});

View File

@@ -1,130 +1,127 @@
'use strict'; 'use strict'
var assert = require('assert'); var assert = require('assert')
var config = require('../lib/config'); var config = require('../lib/config')
var helper = require('../helper'); var helper = require('../helper')
var redis = config.redis; var redis = config.redis
function setupData (client, done) { function setupData (client, done) {
client.rpush('y', 'd'); client.rpush('y', 'd')
client.rpush('y', 'b'); client.rpush('y', 'b')
client.rpush('y', 'a'); client.rpush('y', 'a')
client.rpush('y', 'c'); client.rpush('y', 'c')
client.rpush('x', '3'); client.rpush('x', '3')
client.rpush('x', '9'); client.rpush('x', '9')
client.rpush('x', '2'); client.rpush('x', '2')
client.rpush('x', '4'); client.rpush('x', '4')
client.set('w3', '4'); client.set('w3', '4')
client.set('w9', '5'); client.set('w9', '5')
client.set('w2', '12'); client.set('w2', '12')
client.set('w4', '6'); client.set('w4', '6')
client.set('o2', 'buz'); client.set('o2', 'buz')
client.set('o3', 'foo'); client.set('o3', 'foo')
client.set('o4', 'baz'); client.set('o4', 'baz')
client.set('o9', 'bar'); client.set('o9', 'bar')
client.set('p2', 'qux'); client.set('p2', 'qux')
client.set('p3', 'bux'); client.set('p3', 'bux')
client.set('p4', 'lux'); client.set('p4', 'lux')
client.set('p9', 'tux', done); client.set('p9', 'tux', done)
} }
describe("The 'sort' method", function () { describe('The \'sort\' method', function () {
helper.allTests(function (ip, args) {
describe('using ' + ip, function () {
var client
helper.allTests(function (ip, args) { beforeEach(function (done) {
client = redis.createClient.apply(null, args)
client.once('error', done)
client.once('connect', function () {
client.flushdb()
setupData(client, done)
})
})
describe('using ' + ip, function () { describe('alphabetical', function () {
var client; it('sorts in ascending alphabetical order', function (done) {
client.sort('y', 'asc', 'alpha', function (err, sorted) {
assert.deepEqual(sorted, ['a', 'b', 'c', 'd'])
return done(err)
})
})
beforeEach(function (done) { it('sorts in descending alphabetical order', function (done) {
client = redis.createClient.apply(null, args); client.sort('y', 'desc', 'alpha', function (err, sorted) {
client.once('error', done); assert.deepEqual(sorted, ['d', 'c', 'b', 'a'])
client.once('connect', function () { return done(err)
client.flushdb(); })
setupData(client, done); })
}); })
});
describe('alphabetical', function () { describe('numeric', function () {
it('sorts in ascending alphabetical order', function (done) { it('sorts in ascending numeric order', function (done) {
client.sort('y', 'asc', 'alpha', function (err, sorted) { client.sort('x', 'asc', function (err, sorted) {
assert.deepEqual(sorted, ['a', 'b', 'c', 'd']); assert.deepEqual(sorted, [2, 3, 4, 9])
return done(err); return done(err)
}); })
}); })
it('sorts in descending alphabetical order', function (done) { it('sorts in descending numeric order', function (done) {
client.sort('y', 'desc', 'alpha', function (err, sorted) { client.sort('x', 'desc', function (err, sorted) {
assert.deepEqual(sorted, ['d', 'c', 'b', 'a']); assert.deepEqual(sorted, [9, 4, 3, 2])
return done(err); return done(err)
}); })
}); })
}); })
describe('numeric', function () { describe('pattern', function () {
it('sorts in ascending numeric order', function (done) { it('handles sorting with a pattern', function (done) {
client.sort('x', 'asc', function (err, sorted) { client.sort('x', 'by', 'w*', 'asc', function (err, sorted) {
assert.deepEqual(sorted, [2, 3, 4, 9]); assert.deepEqual(sorted, [3, 9, 4, 2])
return done(err); return done(err)
}); })
}); })
it('sorts in descending numeric order', function (done) { it('handles sorting with a \'by\' pattern and 1 \'get\' pattern', function (done) {
client.sort('x', 'desc', function (err, sorted) { client.sort('x', 'by', 'w*', 'asc', 'get', 'o*', function (err, sorted) {
assert.deepEqual(sorted, [9, 4, 3, 2]); assert.deepEqual(sorted, ['foo', 'bar', 'baz', 'buz'])
return done(err); return done(err)
}); })
}); })
});
describe('pattern', function () { it('handles sorting with a \'by\' pattern and 2 \'get\' patterns', function (done) {
it('handles sorting with a pattern', function (done) { client.sort('x', 'by', 'w*', 'asc', 'get', 'o*', 'get', 'p*', function (err, sorted) {
client.sort('x', 'by', 'w*', 'asc', function (err, sorted) { assert.deepEqual(sorted, ['foo', 'bux', 'bar', 'tux', 'baz', 'lux', 'buz', 'qux'])
assert.deepEqual(sorted, [3, 9, 4, 2]); return done(err)
return done(err); })
}); })
});
it("handles sorting with a 'by' pattern and 1 'get' pattern", function (done) { it('handles sorting with a \'by\' pattern and 2 \'get\' patterns with the array syntax', function (done) {
client.sort('x', 'by', 'w*', 'asc', 'get', 'o*', function (err, sorted) { client.sort(['x', 'by', 'w*', 'asc', 'get', 'o*', 'get', 'p*'], function (err, sorted) {
assert.deepEqual(sorted, ['foo', 'bar', 'baz', 'buz']); assert.deepEqual(sorted, ['foo', 'bux', 'bar', 'tux', 'baz', 'lux', 'buz', 'qux'])
return done(err); return done(err)
}); })
}); })
it("handles sorting with a 'by' pattern and 2 'get' patterns", function (done) { it('sorting with a \'by\' pattern and 2 \'get\' patterns and stores results', function (done) {
client.sort('x', 'by', 'w*', 'asc', 'get', 'o*', 'get', 'p*', function (err, sorted) { client.sort('x', 'by', 'w*', 'asc', 'get', 'o*', 'get', 'p*', 'store', 'bacon', function (err) {
assert.deepEqual(sorted, ['foo', 'bux', 'bar', 'tux', 'baz', 'lux', 'buz', 'qux']); if (err) return done(err)
return done(err); })
});
});
it("handles sorting with a 'by' pattern and 2 'get' patterns with the array syntax", function (done) { client.lrange('bacon', 0, -1, function (err, values) {
client.sort(['x', 'by', 'w*', 'asc', 'get', 'o*', 'get', 'p*'], function (err, sorted) { assert.deepEqual(values, ['foo', 'bux', 'bar', 'tux', 'baz', 'lux', 'buz', 'qux'])
assert.deepEqual(sorted, ['foo', 'bux', 'bar', 'tux', 'baz', 'lux', 'buz', 'qux']); return done(err)
return done(err); })
}); })
}); })
it("sorting with a 'by' pattern and 2 'get' patterns and stores results", function (done) { afterEach(function () {
client.sort('x', 'by', 'w*', 'asc', 'get', 'o*', 'get', 'p*', 'store', 'bacon', function (err) { client.end(true)
if (err) return done(err); })
}); })
})
client.lrange('bacon', 0, -1, function (err, values) { })
assert.deepEqual(values, ['foo', 'bux', 'bar', 'tux', 'baz', 'lux', 'buz', 'qux']);
return done(err);
});
});
});
afterEach(function () {
client.end(true);
});
});
});
});

View File

@@ -1,38 +1,36 @@
'use strict'; 'use strict'
var assert = require('assert'); var assert = require('assert')
var config = require('../lib/config'); var config = require('../lib/config')
var helper = require('../helper'); var helper = require('../helper')
var redis = config.redis; var redis = config.redis
describe("The 'spop' method", function () { describe('The \'spop\' method', function () {
helper.allTests(function (ip, args) {
describe('using ' + ip, function () {
var client
helper.allTests(function (ip, args) { beforeEach(function (done) {
client = redis.createClient.apply(null, args)
client.once('ready', function () {
client.flushdb(done)
})
})
describe('using ' + ip, function () { it('returns a random element from the set', function (done) {
var client; client.sadd('zzz', 'member0', helper.isNumber(1))
client.scard('zzz', helper.isNumber(1))
beforeEach(function (done) { client.spop('zzz', function (err, value) {
client = redis.createClient.apply(null, args); if (err) return done(err)
client.once('ready', function () { assert.strictEqual(value, 'member0')
client.flushdb(done); client.scard('zzz', helper.isNumber(0, done))
}); })
}); })
it('returns a random element from the set', function (done) { afterEach(function () {
client.sadd('zzz', 'member0', helper.isNumber(1)); client.end(true)
client.scard('zzz', helper.isNumber(1)); })
})
client.spop('zzz', function (err, value) { })
if (err) return done(err); })
assert.equal(value, 'member0');
client.scard('zzz', helper.isNumber(0, done));
});
});
afterEach(function () {
client.end(true);
});
});
});
});

View File

@@ -1,69 +1,67 @@
'use strict'; 'use strict'
var assert = require('assert'); var assert = require('assert')
var config = require('../lib/config'); var config = require('../lib/config')
var helper = require('../helper'); var helper = require('../helper')
var redis = config.redis; var redis = config.redis
describe("The 'srem' method", function () { describe('The \'srem\' method', function () {
helper.allTests(function (ip, args) {
describe('using ' + ip, function () {
var client
helper.allTests(function (ip, args) { beforeEach(function (done) {
client = redis.createClient.apply(null, args)
client.once('ready', function () {
client.flushdb(done)
})
})
describe('using ' + ip, function () { it('removes a value', function (done) {
var client; client.sadd('set0', 'member0', helper.isNumber(1))
client.srem('set0', 'member0', helper.isNumber(1))
client.scard('set0', helper.isNumber(0, done))
})
beforeEach(function (done) { it('handles attempting to remove a missing value', function (done) {
client = redis.createClient.apply(null, args); client.srem('set0', 'member0', helper.isNumber(0, done))
client.once('ready', function () { })
client.flushdb(done);
});
});
it('removes a value', function (done) { it('allows multiple values to be removed', function (done) {
client.sadd('set0', 'member0', helper.isNumber(1)); client.sadd('set0', ['member0', 'member1', 'member2'], helper.isNumber(3))
client.srem('set0', 'member0', helper.isNumber(1)); client.srem('set0', ['member1', 'member2'], helper.isNumber(2))
client.scard('set0', helper.isNumber(0, done)); client.smembers('set0', function (err, res) {
}); assert.strictEqual(res.length, 1)
assert.ok(~res.indexOf('member0'))
return done(err)
})
})
it('handles attempting to remove a missing value', function (done) { it('allows multiple values to be removed with sendCommand', function (done) {
client.srem('set0', 'member0', helper.isNumber(0, done)); client.sendCommand('sadd', ['set0', 'member0', 'member1', 'member2'], helper.isNumber(3))
}); client.sendCommand('srem', ['set0', 'member1', 'member2'], helper.isNumber(2))
client.smembers('set0', function (err, res) {
assert.strictEqual(res.length, 1)
assert.ok(~res.indexOf('member0'))
return done(err)
})
})
it('allows multiple values to be removed', function (done) { it('handles a value missing from the set of values being removed', function (done) {
client.sadd('set0', ['member0', 'member1', 'member2'], helper.isNumber(3)); client.sadd(['set0', 'member0', 'member1', 'member2'], helper.isNumber(3))
client.srem('set0', ['member1', 'member2'], helper.isNumber(2)); client.srem(['set0', 'member3', 'member4'], helper.isNumber(0))
client.smembers('set0', function (err, res) { client.smembers('set0', function (err, res) {
assert.strictEqual(res.length, 1); assert.strictEqual(res.length, 3)
assert.ok(~res.indexOf('member0')); assert.ok(~res.indexOf('member0'))
return done(err); assert.ok(~res.indexOf('member1'))
}); assert.ok(~res.indexOf('member2'))
}); return done(err)
})
})
it('allows multiple values to be removed with sendCommand', function (done) { afterEach(function () {
client.sendCommand('sadd', ['set0', 'member0', 'member1', 'member2'], helper.isNumber(3)); client.end(true)
client.sendCommand('srem', ['set0', 'member1', 'member2'], helper.isNumber(2)); })
client.smembers('set0', function (err, res) { })
assert.strictEqual(res.length, 1); })
assert.ok(~res.indexOf('member0')); })
return done(err);
});
});
it('handles a value missing from the set of values being removed', function (done) {
client.sadd(['set0', 'member0', 'member1', 'member2'], helper.isNumber(3));
client.srem(['set0', 'member3', 'member4'], helper.isNumber(0));
client.smembers('set0', function (err, res) {
assert.strictEqual(res.length, 3);
assert.ok(~res.indexOf('member0'));
assert.ok(~res.indexOf('member1'));
assert.ok(~res.indexOf('member2'));
return done(err);
});
});
afterEach(function () {
client.end(true);
});
});
});
});

View File

@@ -1,46 +1,44 @@
'use strict'; 'use strict'
var assert = require('assert'); var assert = require('assert')
var config = require('../lib/config'); var config = require('../lib/config')
var helper = require('../helper'); var helper = require('../helper')
var redis = config.redis; var redis = config.redis
describe("The 'sunion' method", function () { describe('The \'sunion\' method', function () {
helper.allTests(function (ip, args) {
describe('using ' + ip, function () {
var client
helper.allTests(function (ip, args) { beforeEach(function (done) {
client = redis.createClient.apply(null, args)
client.once('ready', function () {
client.flushdb(done)
})
})
describe('using ' + ip, function () { it('returns the union of a group of sets', function (done) {
var client; client.sadd('sa', 'a', helper.isNumber(1))
client.sadd('sa', 'b', helper.isNumber(1))
client.sadd('sa', 'c', helper.isNumber(1))
beforeEach(function (done) { client.sadd('sb', 'b', helper.isNumber(1))
client = redis.createClient.apply(null, args); client.sadd('sb', 'c', helper.isNumber(1))
client.once('ready', function () { client.sadd('sb', 'd', helper.isNumber(1))
client.flushdb(done);
});
});
it('returns the union of a group of sets', function (done) { client.sadd('sc', 'c', helper.isNumber(1))
client.sadd('sa', 'a', helper.isNumber(1)); client.sadd('sc', 'd', helper.isNumber(1))
client.sadd('sa', 'b', helper.isNumber(1)); client.sadd('sc', 'e', helper.isNumber(1))
client.sadd('sa', 'c', helper.isNumber(1));
client.sadd('sb', 'b', helper.isNumber(1)); client.sunion('sa', 'sb', 'sc', function (err, union) {
client.sadd('sb', 'c', helper.isNumber(1)); assert.deepEqual(union.sort(), ['a', 'b', 'c', 'd', 'e'])
client.sadd('sb', 'd', helper.isNumber(1)); return done(err)
})
})
client.sadd('sc', 'c', helper.isNumber(1)); afterEach(function () {
client.sadd('sc', 'd', helper.isNumber(1)); client.end(true)
client.sadd('sc', 'e', helper.isNumber(1)); })
})
client.sunion('sa', 'sb', 'sc', function (err, union) { })
assert.deepEqual(union.sort(), ['a', 'b', 'c', 'd', 'e']); })
return done(err);
});
});
afterEach(function () {
client.end(true);
});
});
});
});

View File

@@ -1,49 +1,47 @@
'use strict'; 'use strict'
var assert = require('assert'); var assert = require('assert')
var config = require('../lib/config'); var config = require('../lib/config')
var helper = require('../helper'); var helper = require('../helper')
var redis = config.redis; var redis = config.redis
describe("The 'sunionstore' method", function () { describe('The \'sunionstore\' method', function () {
helper.allTests(function (ip, args) {
describe('using ' + ip, function () {
var client
helper.allTests(function (ip, args) { beforeEach(function (done) {
client = redis.createClient.apply(null, args)
client.once('ready', function () {
client.flushdb(done)
})
})
describe('using ' + ip, function () { it('stores the result of a union', function (done) {
var client; client.sadd('sa', 'a', helper.isNumber(1))
client.sadd('sa', 'b', helper.isNumber(1))
client.sadd('sa', 'c', helper.isNumber(1))
beforeEach(function (done) { client.sadd('sb', 'b', helper.isNumber(1))
client = redis.createClient.apply(null, args); client.sadd('sb', 'c', helper.isNumber(1))
client.once('ready', function () { client.sadd('sb', 'd', helper.isNumber(1))
client.flushdb(done);
});
});
it('stores the result of a union', function (done) { client.sadd('sc', 'c', helper.isNumber(1))
client.sadd('sa', 'a', helper.isNumber(1)); client.sadd('sc', 'd', helper.isNumber(1))
client.sadd('sa', 'b', helper.isNumber(1)); client.sadd('sc', 'e', helper.isNumber(1))
client.sadd('sa', 'c', helper.isNumber(1));
client.sadd('sb', 'b', helper.isNumber(1)); client.sunionstore('foo', 'sa', 'sb', 'sc', helper.isNumber(5))
client.sadd('sb', 'c', helper.isNumber(1));
client.sadd('sb', 'd', helper.isNumber(1));
client.sadd('sc', 'c', helper.isNumber(1)); client.smembers('foo', function (err, members) {
client.sadd('sc', 'd', helper.isNumber(1)); assert.strictEqual(members.length, 5)
client.sadd('sc', 'e', helper.isNumber(1)); assert.deepEqual(members.sort(), ['a', 'b', 'c', 'd', 'e'])
return done(err)
})
})
client.sunionstore('foo', 'sa', 'sb', 'sc', helper.isNumber(5)); afterEach(function () {
client.end(true)
client.smembers('foo', function (err, members) { })
assert.equal(members.length, 5); })
assert.deepEqual(members.sort(), ['a', 'b', 'c', 'd', 'e']); })
return done(err); })
});
});
afterEach(function () {
client.end(true);
});
});
});
});

View File

@@ -1,37 +1,35 @@
'use strict'; 'use strict'
var assert = require('assert'); var assert = require('assert')
var config = require('../lib/config'); var config = require('../lib/config')
var helper = require('../helper'); var helper = require('../helper')
var redis = config.redis; var redis = config.redis
describe("The 'ttl' method", function () { describe('The \'ttl\' method', function () {
helper.allTests(function (ip, args) {
describe('using ' + ip, function () {
var client
helper.allTests(function (ip, args) { beforeEach(function (done) {
client = redis.createClient.apply(null, args)
client.once('ready', function () {
client.flushdb(done)
})
})
describe('using ' + ip, function () { it('returns the current ttl on a key', function (done) {
var client; client.set(['ttl key', 'ttl val'], helper.isString('OK'))
client.expire(['ttl key', '100'], helper.isNumber(1))
client.ttl(['ttl key'], function (err, ttl) {
assert(ttl >= 99)
assert(ttl <= 100)
done(err)
})
})
beforeEach(function (done) { afterEach(function () {
client = redis.createClient.apply(null, args); client.end(true)
client.once('ready', function () { })
client.flushdb(done); })
}); })
}); })
it('returns the current ttl on a key', function (done) {
client.set(['ttl key', 'ttl val'], helper.isString('OK'));
client.expire(['ttl key', '100'], helper.isNumber(1));
client.ttl(['ttl key'], function (err, ttl) {
assert(ttl >= 99);
assert(ttl <= 100);
done(err);
});
});
afterEach(function () {
client.end(true);
});
});
});
});

View File

@@ -1,56 +1,53 @@
'use strict'; 'use strict'
var config = require('../lib/config'); var config = require('../lib/config')
var helper = require('../helper'); var helper = require('../helper')
var redis = config.redis; var redis = config.redis
describe("The 'type' method", function () { describe('The \'type\' method', function () {
helper.allTests(function (ip, args) {
describe('using ' + ip, function () {
var client
helper.allTests(function (ip, args) { beforeEach(function (done) {
client = redis.createClient.apply(null, args)
client.once('ready', function () {
client.flushdb(done)
})
})
describe('using ' + ip, function () { it('reports string type', function (done) {
var client; client.set(['string key', 'should be a string'], helper.isString('OK'))
client.type(['string key'], helper.isString('string', done))
})
beforeEach(function (done) { it('reports list type', function (done) {
client = redis.createClient.apply(null, args); client.rpush(['list key', 'should be a list'], helper.isNumber(1))
client.once('ready', function () { client.type(['list key'], helper.isString('list', done))
client.flushdb(done); })
});
});
it('reports string type', function (done) { it('reports set type', function (done) {
client.set(['string key', 'should be a string'], helper.isString('OK')); client.sadd(['set key', 'should be a set'], helper.isNumber(1))
client.type(['string key'], helper.isString('string', done)); client.type(['set key'], helper.isString('set', done))
}); })
it('reports list type', function (done) { it('reports zset type', function (done) {
client.rpush(['list key', 'should be a list'], helper.isNumber(1)); client.zadd('zset key', ['10.0', 'should be a zset'], helper.isNumber(1))
client.type(['list key'], helper.isString('list', done)); client.type(['zset key'], helper.isString('zset', done))
}); })
it('reports set type', function (done) { it('reports hash type', function (done) {
client.sadd(['set key', 'should be a set'], helper.isNumber(1)); client.hset('hash key', 'hashtest', 'should be a hash', helper.isNumber(1))
client.type(['set key'], helper.isString('set', done)); client.type(['hash key'], helper.isString('hash', done))
}); })
it('reports zset type', function (done) { it('reports none for null key', function (done) {
client.zadd('zset key', ['10.0', 'should be a zset'], helper.isNumber(1)); client.type('not here yet', helper.isString('none', done))
client.type(['zset key'], helper.isString('zset', done)); })
});
it('reports hash type', function (done) { afterEach(function () {
client.hset('hash key', 'hashtest', 'should be a hash', helper.isNumber(1)); client.end(true)
client.type(['hash key'], helper.isString('hash', done)); })
}); })
})
it('reports none for null key', function (done) { })
client.type('not here yet', helper.isString('none', done));
});
afterEach(function () {
client.end(true);
});
});
});
});

View File

@@ -1,54 +1,50 @@
'use strict'; 'use strict'
var assert = require('assert'); var assert = require('assert')
var config = require('../lib/config'); var config = require('../lib/config')
var helper = require('../helper'); var helper = require('../helper')
var redis = config.redis; var redis = config.redis
describe("The 'watch' method", function () { describe('The \'watch\' method', function () {
helper.allTests(function (ip, args) {
var watched = 'foobar'
helper.allTests(function (ip, args) { describe('using ' + ip, function () {
var client
var watched = 'foobar'; beforeEach(function (done) {
client = redis.createClient.apply(null, args)
client.once('ready', function () {
client.flushdb(done)
})
})
describe('using ' + ip, function () { afterEach(function () {
var client; client.end(true)
})
beforeEach(function (done) { it('does not execute transaction if watched key was modified prior to execution', function (done) {
client = redis.createClient.apply(null, args); client.watch(watched)
client.once('ready', function () { client.incr(watched)
client.flushdb(done); var multi = client.multi()
}); multi.incr(watched)
}); multi.exec(helper.isNull(done))
})
afterEach(function () { it('successfully modifies other keys independently of transaction', function (done) {
client.end(true); client.set('unwatched', 200)
});
it('does not execute transaction if watched key was modified prior to execution', function (done) { client.set(watched, 0)
client.watch(watched); client.watch(watched)
client.incr(watched); client.incr(watched)
var multi = client.multi();
multi.incr(watched);
multi.exec(helper.isNull(done));
});
it('successfully modifies other keys independently of transaction', function (done) { client.multi().incr(watched).exec(function (err, replies) {
client.set('unwatched', 200); assert.strictEqual(err, null)
assert.strictEqual(replies, null, 'Aborted transaction multi-bulk reply should be null.')
client.set(watched, 0); client.get('unwatched', helper.isString('200', done))
client.watch(watched); })
client.incr(watched); })
})
client.multi().incr(watched).exec(function (err, replies) { })
assert.strictEqual(replies, null, 'Aborted transaction multi-bulk reply should be null.'); })
client.get('unwatched', function (err, reply) {
assert.equal(reply, 200, 'Expected 200, got ' + reply);
return done(err);
});
});
});
});
});
});

View File

@@ -1,48 +1,46 @@
'use strict'; 'use strict'
var config = require('../lib/config'); var config = require('../lib/config')
var helper = require('../helper'); var helper = require('../helper')
var assert = require('assert'); var assert = require('assert')
var redis = config.redis; var redis = config.redis
describe("The 'zadd' method", function () { describe('The \'zadd\' method', function () {
helper.allTests(function (ip, args) {
describe('using ' + ip, function () {
var client
helper.allTests(function (ip, args) { beforeEach(function (done) {
client = redis.createClient.apply(null, args)
client.once('ready', function () {
client.flushdb(done)
})
})
describe('using ' + ip, function () { it('reports an error', function (done) {
var client; if (helper.redisProcess().spawnFailed()) this.skip()
client.zadd('infinity', [+'5t', 'should not be possible'], helper.isError(done))
})
beforeEach(function (done) { it('return inf / -inf', function (done) {
client = redis.createClient.apply(null, args); if (helper.redisProcess().spawnFailed()) this.skip()
client.once('ready', function () { helper.serverVersionAtLeast.call(this, client, [3, 0, 2])
client.flushdb(done); client.zadd('infinity', [+Infinity, 'should be inf'], helper.isNumber(1))
}); client.zadd('infinity', ['inf', 'should be also be inf'], helper.isNumber(1))
}); client.zadd('infinity', -Infinity, 'should be negative inf', helper.isNumber(1))
client.zadd('infinity', [99999999999999999999999, 'should not be inf'], helper.isNumber(1))
client.zrange('infinity', 0, -1, 'WITHSCORES', function (err, res) {
assert.strictEqual(err, null)
assert.strictEqual(res[5], 'inf')
assert.strictEqual(res[1], '-inf')
assert.strictEqual(res[3], '9.9999999999999992e+22')
done()
})
})
it('reports an error', function (done) { afterEach(function () {
if (helper.redisProcess().spawnFailed()) this.skip(); client.end(true)
client.zadd('infinity', [+'5t', 'should not be possible'], helper.isError(done)); })
}); })
})
it('return inf / -inf', function (done) { })
if (helper.redisProcess().spawnFailed()) this.skip();
helper.serverVersionAtLeast.call(this, client, [3, 0, 2]);
client.zadd('infinity', [+Infinity, 'should be inf'], helper.isNumber(1));
client.zadd('infinity', ['inf', 'should be also be inf'], helper.isNumber(1));
client.zadd('infinity', -Infinity, 'should be negative inf', helper.isNumber(1));
client.zadd('infinity', [99999999999999999999999, 'should not be inf'], helper.isNumber(1));
client.zrange('infinity', 0, -1, 'WITHSCORES', function (err, res) {
assert.equal(res[5], 'inf');
assert.equal(res[1], '-inf');
assert.equal(res[3], '9.9999999999999992e+22');
done();
});
});
afterEach(function () {
client.end(true);
});
});
});
});

View File

@@ -1,50 +1,47 @@
'use strict'; 'use strict'
var config = require('../lib/config'); var config = require('../lib/config')
var helper = require('../helper'); var helper = require('../helper')
var assert = require('assert'); var assert = require('assert')
var redis = config.redis; var redis = config.redis
describe("The 'zscan' method", function () { describe('The \'zscan\' method', function () {
helper.allTests(function (ip, args) {
describe('using ' + ip, function () {
var client
helper.allTests(function (ip, args) { beforeEach(function (done) {
client = redis.createClient.apply(null, args)
client.once('ready', function () {
client.flushdb(done)
})
})
describe('using ' + ip, function () { it('return values', function (done) {
var client; if (helper.redisProcess().spawnFailed()) this.skip()
helper.serverVersionAtLeast.call(this, client, [2, 8, 0])
var hash = {}
var set = []
var zset = ['zset:1']
for (var i = 0; i < 500; i++) {
hash['key_' + i] = 'value_' + i
set.push('member_' + i)
zset.push(i, 'zMember_' + i)
}
client.hmset('hash:1', hash)
client.sadd('set:1', set)
client.zadd(zset)
client.zscan('zset:1', 0, 'MATCH', '*', 'COUNT', 500, function (err, res) {
assert(!err)
assert.strictEqual(res.length, 2)
assert.strictEqual(res[1].length, 1000)
done()
})
})
beforeEach(function (done) { afterEach(function () {
client = redis.createClient.apply(null, args); client.end(true)
client.once('ready', function () { })
client.flushdb(done); })
}); })
}); })
it('return values', function (done) {
if (helper.redisProcess().spawnFailed()) this.skip();
helper.serverVersionAtLeast.call(this, client, [2, 8, 0]);
var hash = {};
var set = [];
var zset = ['zset:1'];
for (var i = 0; i < 500; i++) {
hash['key_' + i] = 'value_' + i;
set.push('member_' + i);
zset.push(i, 'zMember_' + i);
}
client.hmset('hash:1', hash);
client.sadd('set:1', set);
client.zadd(zset);
client.zscan('zset:1', 0, 'MATCH', '*', 'COUNT', 500, function (err, res) {
assert(!err);
assert.strictEqual(res.length, 2);
assert.strictEqual(res[1].length, 1000);
done();
});
});
afterEach(function () {
client.end(true);
});
});
});
});

View File

@@ -1,35 +1,29 @@
'use strict'; 'use strict'
var config = require('../lib/config'); var config = require('../lib/config')
var helper = require('../helper'); var helper = require('../helper')
var assert = require('assert'); var redis = config.redis
var redis = config.redis;
describe("The 'zscore' method", function () { describe('The \'zscore\' method', function () {
helper.allTests(function (ip, args) {
describe('using ' + ip, function () {
var client
helper.allTests(function (ip, args) { beforeEach(function (done) {
client = redis.createClient.apply(null, args)
client.once('ready', function () {
client.flushdb(done)
})
})
describe('using ' + ip, function () { it('should return the score of member in the sorted set at key', function (done) {
var client; client.zadd('myzset', 1, 'one')
client.zscore('myzset', 'one', helper.isString('1', done))
})
beforeEach(function (done) { afterEach(function () {
client = redis.createClient.apply(null, args); client.end(true)
client.once('ready', function () { })
client.flushdb(done); })
}); })
}); })
it('should return the score of member in the sorted set at key', function (done) {
client.zadd('myzset', 1, 'one');
client.zscore('myzset', 'one', function (err, res) {
assert.equal(res, 1);
done();
});
});
afterEach(function () {
client.end(true);
});
});
});
});

View File

@@ -1,99 +1,97 @@
'use strict'; 'use strict'
var assert = require('assert'); var assert = require('assert')
var config = require('./lib/config'); var config = require('./lib/config')
var helper = require('./helper'); var helper = require('./helper')
var RedisProcess = require('./lib/redis-process'); var RedisProcess = require('./lib/redis-process')
var rp; var rp
var path = require('path'); var path = require('path')
var redis = config.redis; var redis = config.redis
if (process.platform === 'win32') { // TODO: Fix redis process spawn on windows
// TODO: Fix redis process spawn on windows if (process.platform !== 'win32') {
return; describe('master slave sync', function () {
} var master = null
var slave = null
describe('master slave sync', function () {
var master = null;
var slave = null;
before(function (done) { before(function (done) {
helper.stopRedis(function () { helper.stopRedis(function () {
helper.startRedis('./conf/password.conf', done); helper.startRedis('./conf/password.conf', done)
}); })
}); })
before(function (done) { before(function (done) {
if (helper.redisProcess().spawnFailed()) return done(); if (helper.redisProcess().spawnFailed()) return done()
master = redis.createClient({ master = redis.createClient({
password: 'porkchopsandwiches' password: 'porkchopsandwiches'
}); })
var multi = master.multi(); var multi = master.multi()
var i = 0; var i = 0
while (i < 1000) { while (i < 1000) {
i++; i++
// Write some data in the redis instance, so there's something to sync // Write some data in the redis instance, so there's something to sync
multi.set('foo' + i, 'bar' + new Array(500).join(Math.random())); multi.set('foo' + i, 'bar' + new Array(500).join(Math.random()))
} }
multi.exec(done); multi.exec(done)
}); })
it('sync process and no master should delay ready being emitted for slaves', function (done) { it('sync process and no master should delay ready being emitted for slaves', function (done) {
if (helper.redisProcess().spawnFailed()) this.skip(); if (helper.redisProcess().spawnFailed()) this.skip()
var port = 6381; var port = 6381
var firstInfo; var firstInfo
slave = redis.createClient({ slave = redis.createClient({
port: port, port: port,
retryStrategy: function (options) { retryStrategy: function (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
} }
}); })
var tmp = slave.info.bind(slave); var tmp = slave.info.bind(slave)
var i = 0; var i = 0
slave.info = function (err, res) { slave.info = function (err, res) {
i++; i++
tmp(err, res); tmp(err, res)
if (!firstInfo || Object.keys(firstInfo).length === 0) { if (!firstInfo || Object.keys(firstInfo).length === 0) {
firstInfo = slave.serverInfo; firstInfo = slave.serverInfo
} }
}; }
slave.on('connect', function () { slave.on('connect', function () {
assert.strictEqual(i, 0); assert.strictEqual(i, 0)
}); })
var end = helper.callFuncAfter(done, 2); var end = helper.callFuncAfter(done, 2)
slave.on('ready', function () { slave.on('ready', function () {
assert.strictEqual(this.serverInfo.master_link_status, 'up'); assert.strictEqual(this.serverInfo.master_link_status, 'up')
assert.strictEqual(firstInfo.master_link_status, 'down'); assert.strictEqual(firstInfo.master_link_status, 'down')
assert(i > 1); assert(i > 1)
this.get('foo300', function (err, res) { this.get('foo300', function (err, res) {
assert.strictEqual(res.substr(0, 3), 'bar'); assert.strictEqual(res.substr(0, 3), 'bar')
end(err); end(err)
}); })
}); })
RedisProcess.start(function (err, _rp) { RedisProcess.start(function (err, _rp) {
rp = _rp; rp = _rp
end(err); end(err)
}, path.resolve(__dirname, './conf/slave.conf'), port); }, path.resolve(__dirname, './conf/slave.conf'), port)
}); })
after(function (done) { after(function (done) {
if (helper.redisProcess().spawnFailed()) return done(); if (helper.redisProcess().spawnFailed()) return done()
var end = helper.callFuncAfter(done, 3); var end = helper.callFuncAfter(done, 3)
rp.stop(end); rp.stop(end)
slave.end(true); slave.end(true)
master.flushdb(function (err) { master.flushdb(function (err) {
end(err); end(err)
master.end(true); master.end(true)
}); })
helper.stopRedis(function () { helper.stopRedis(function () {
helper.startRedis('./conf/redis.conf', end); helper.startRedis('./conf/redis.conf', end)
}); })
}); })
}); })
}

File diff suppressed because it is too large Load Diff

View File

@@ -1,89 +1,88 @@
'use strict'; 'use strict'
var assert = require('assert'); var assert = require('assert')
var errors = require('../lib/customErrors'); var errors = require('../lib/customErrors')
describe('errors', function () { describe('errors', function () {
describe('AbortError', function () {
it('should inherit from Error', function () {
var e = new errors.AbortError({})
assert.strictEqual(e.message, '')
assert.strictEqual(e.name, 'AbortError')
assert.strictEqual(Object.keys(e).length, 0)
assert(e instanceof Error)
assert(e instanceof errors.AbortError)
})
describe('AbortError', function () { it('should list options properties but not name and message', function () {
it('should inherit from Error', function () { var e = new errors.AbortError({
var e = new errors.AbortError({}); name: 'weird',
assert.strictEqual(e.message, ''); message: 'hello world',
assert.strictEqual(e.name, 'AbortError'); property: true
assert.strictEqual(Object.keys(e).length, 0); })
assert(e instanceof Error); assert.strictEqual(e.message, 'hello world')
assert(e instanceof errors.AbortError); assert.strictEqual(e.name, 'weird')
}); assert.strictEqual(e.property, true)
assert.strictEqual(Object.keys(e).length, 2)
assert(e instanceof Error)
assert(e instanceof errors.AbortError)
assert(delete e.name)
assert.strictEqual(e.name, 'AbortError')
})
it('should list options properties but not name and message', function () { it('should change name and message', function () {
var e = new errors.AbortError({ var e = new errors.AbortError({
name: 'weird', message: 'hello world',
message: 'hello world', property: true
property: true })
}); assert.strictEqual(e.name, 'AbortError')
assert.strictEqual(e.message, 'hello world'); assert.strictEqual(e.message, 'hello world')
assert.strictEqual(e.name, 'weird'); e.name = 'foo'
assert.strictEqual(e.property, true); e.message = 'foobar'
assert.strictEqual(Object.keys(e).length, 2); assert.strictEqual(e.name, 'foo')
assert(e instanceof Error); assert.strictEqual(e.message, 'foobar')
assert(e instanceof errors.AbortError); })
assert(delete e.name); })
assert.strictEqual(e.name, 'AbortError');
});
it('should change name and message', function () { describe('AggregateError', function () {
var e = new errors.AbortError({ it('should inherit from Error and AbortError', function () {
message: 'hello world', var e = new errors.AggregateError({})
property: true assert.strictEqual(e.message, '')
}); assert.strictEqual(e.name, 'AggregateError')
assert.strictEqual(e.name, 'AbortError'); assert.strictEqual(Object.keys(e).length, 0)
assert.strictEqual(e.message, 'hello world'); assert(e instanceof Error)
e.name = 'foo'; assert(e instanceof errors.AggregateError)
e.message = 'foobar'; assert(e instanceof errors.AbortError)
assert.strictEqual(e.name, 'foo'); })
assert.strictEqual(e.message, 'foobar');
});
});
describe('AggregateError', function () { it('should list options properties but not name and message', function () {
it('should inherit from Error and AbortError', function () { var e = new errors.AggregateError({
var e = new errors.AggregateError({}); name: 'weird',
assert.strictEqual(e.message, ''); message: 'hello world',
assert.strictEqual(e.name, 'AggregateError'); property: true
assert.strictEqual(Object.keys(e).length, 0); })
assert(e instanceof Error); assert.strictEqual(e.message, 'hello world')
assert(e instanceof errors.AggregateError); assert.strictEqual(e.name, 'weird')
assert(e instanceof errors.AbortError); assert.strictEqual(e.property, true)
}); assert.strictEqual(Object.keys(e).length, 2)
assert(e instanceof Error)
assert(e instanceof errors.AggregateError)
assert(e instanceof errors.AbortError)
assert(delete e.name)
assert.strictEqual(e.name, 'AggregateError')
})
it('should list options properties but not name and message', function () { it('should change name and message', function () {
var e = new errors.AggregateError({ var e = new errors.AggregateError({
name: 'weird', message: 'hello world',
message: 'hello world', property: true
property: true })
}); assert.strictEqual(e.name, 'AggregateError')
assert.strictEqual(e.message, 'hello world'); assert.strictEqual(e.message, 'hello world')
assert.strictEqual(e.name, 'weird'); e.name = 'foo'
assert.strictEqual(e.property, true); e.message = 'foobar'
assert.strictEqual(Object.keys(e).length, 2); assert.strictEqual(e.name, 'foo')
assert(e instanceof Error); assert.strictEqual(e.message, 'foobar')
assert(e instanceof errors.AggregateError); })
assert(e instanceof errors.AbortError); })
assert(delete e.name); })
assert.strictEqual(e.name, 'AggregateError');
});
it('should change name and message', function () {
var e = new errors.AggregateError({
message: 'hello world',
property: true
});
assert.strictEqual(e.name, 'AggregateError');
assert.strictEqual(e.message, 'hello world');
e.name = 'foo';
e.message = 'foobar';
assert.strictEqual(e.name, 'foo');
assert.strictEqual(e.message, 'foobar');
});
});
});

View File

@@ -1,268 +1,268 @@
'use strict'; 'use strict'
var assert = require('assert'); var Buffer = require('safe-buffer').Buffer
var config = require('./lib/config'); var assert = require('assert')
var helper = require('./helper'); var config = require('./lib/config')
var redis = config.redis; var helper = require('./helper')
var redis = config.redis
describe('detectBuffers', function () { describe('detectBuffers', function () {
var client
var args = config.configureClient('localhost', {
detectBuffers: true
})
var client; beforeEach(function (done) {
var args = config.configureClient('localhost', { client = redis.createClient.apply(null, args)
detectBuffers: true client.once('error', done)
}); client.once('connect', function () {
client.flushdb(function (err) {
client.hmset('hash key 2', 'key 1', 'val 1', 'key 2', 'val 2')
client.set('string key 1', 'string value')
return done(err)
})
})
})
beforeEach(function (done) { afterEach(function () {
client = redis.createClient.apply(null, args); client.end(true)
client.once('error', done); })
client.once('connect', function () {
client.flushdb(function (err) {
client.hmset('hash key 2', 'key 1', 'val 1', 'key 2', 'val 2');
client.set('string key 1', 'string value');
return done(err);
});
});
});
afterEach(function () { describe('get', function () {
client.end(true); describe('first argument is a string', function () {
}); it('returns a string', function (done) {
client.get('string key 1', helper.isString('string value', done))
})
describe('get', function () { it('returns a string when executed as part of transaction', function (done) {
describe('first argument is a string', function () { client.multi().get('string key 1').exec(function (err, res) {
it('returns a string', function (done) { helper.isString('string value', done)(err, res[0])
client.get('string key 1', helper.isString('string value', done)); })
}); })
})
it('returns a string when executed as part of transaction', function (done) { describe('first argument is a buffer', function () {
client.multi().get('string key 1').exec(function (err, res) { it('returns a buffer', function (done) {
helper.isString('string value', done)(err, res[0]); client.get(Buffer.from('string key 1'), function (err, reply) {
}); assert.strictEqual(true, Buffer.isBuffer(reply))
}); assert.strictEqual('<Buffer 73 74 72 69 6e 67 20 76 61 6c 75 65>', reply.inspect())
}); return done(err)
})
})
describe('first argument is a buffer', function () { it('returns a bufffer when executed as part of transaction', function (done) {
it('returns a buffer', function (done) { client.multi().get(Buffer.from('string key 1')).exec(function (err, reply) {
client.get(new Buffer('string key 1'), function (err, reply) { assert.strictEqual(1, reply.length)
assert.strictEqual(true, Buffer.isBuffer(reply)); assert.strictEqual(true, Buffer.isBuffer(reply[0]))
assert.strictEqual('<Buffer 73 74 72 69 6e 67 20 76 61 6c 75 65>', reply.inspect()); assert.strictEqual('<Buffer 73 74 72 69 6e 67 20 76 61 6c 75 65>', reply[0].inspect())
return done(err); return done(err)
}); })
}); })
})
})
it('returns a bufffer when executed as part of transaction', function (done) { describe('multi.hget', function () {
client.multi().get(new Buffer('string key 1')).exec(function (err, reply) { it('can interleave string and buffer results', function (done) {
assert.strictEqual(1, reply.length); client.multi()
assert.strictEqual(true, Buffer.isBuffer(reply[0])); .hget('hash key 2', 'key 1')
assert.strictEqual('<Buffer 73 74 72 69 6e 67 20 76 61 6c 75 65>', reply[0].inspect()); .hget(Buffer.from('hash key 2'), 'key 1')
return done(err); .hget('hash key 2', Buffer.from('key 2'))
}); .hget('hash key 2', 'key 2')
}); .exec(function (err, reply) {
}); assert.strictEqual(true, Array.isArray(reply))
}); assert.strictEqual(4, reply.length)
assert.strictEqual('val 1', reply[0])
assert.strictEqual(true, Buffer.isBuffer(reply[1]))
assert.strictEqual('<Buffer 76 61 6c 20 31>', reply[1].inspect())
assert.strictEqual(true, Buffer.isBuffer(reply[2]))
assert.strictEqual('<Buffer 76 61 6c 20 32>', reply[2].inspect())
assert.strictEqual('val 2', reply[3])
return done(err)
})
})
})
describe('multi.hget', function () { describe('batch.hget', function () {
it('can interleave string and buffer results', function (done) { it('can interleave string and buffer results', function (done) {
client.multi() client.batch()
.hget('hash key 2', 'key 1') .hget('hash key 2', 'key 1')
.hget(new Buffer('hash key 2'), 'key 1') .hget(Buffer.from('hash key 2'), 'key 1')
.hget('hash key 2', new Buffer('key 2')) .hget('hash key 2', Buffer.from('key 2'))
.hget('hash key 2', 'key 2') .hget('hash key 2', 'key 2')
.exec(function (err, reply) { .exec(function (err, 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])
assert.strictEqual(true, Buffer.isBuffer(reply[1])); assert.strictEqual(true, Buffer.isBuffer(reply[1]))
assert.strictEqual('<Buffer 76 61 6c 20 31>', reply[1].inspect()); assert.strictEqual('<Buffer 76 61 6c 20 31>', reply[1].inspect())
assert.strictEqual(true, Buffer.isBuffer(reply[2])); assert.strictEqual(true, Buffer.isBuffer(reply[2]))
assert.strictEqual('<Buffer 76 61 6c 20 32>', reply[2].inspect()); assert.strictEqual('<Buffer 76 61 6c 20 32>', reply[2].inspect())
assert.strictEqual('val 2', reply[3]); assert.strictEqual('val 2', reply[3])
return done(err); return done(err)
}); })
}); })
}); })
describe('batch.hget', function () { describe('hmget', function () {
it('can interleave string and buffer results', function (done) { describe('first argument is a string', function () {
client.batch() it('returns strings for keys requested', function (done) {
.hget('hash key 2', 'key 1') client.hmget('hash key 2', 'key 1', 'key 2', function (err, reply) {
.hget(new Buffer('hash key 2'), 'key 1') assert.strictEqual(true, Array.isArray(reply))
.hget('hash key 2', new Buffer('key 2')) assert.strictEqual(2, reply.length)
.hget('hash key 2', 'key 2') assert.strictEqual('val 1', reply[0])
.exec(function (err, reply) { assert.strictEqual('val 2', reply[1])
assert.strictEqual(true, Array.isArray(reply)); return done(err)
assert.strictEqual(4, reply.length); })
assert.strictEqual('val 1', reply[0]); })
assert.strictEqual(true, Buffer.isBuffer(reply[1]));
assert.strictEqual('<Buffer 76 61 6c 20 31>', reply[1].inspect());
assert.strictEqual(true, Buffer.isBuffer(reply[2]));
assert.strictEqual('<Buffer 76 61 6c 20 32>', reply[2].inspect());
assert.strictEqual('val 2', reply[3]);
return done(err);
});
});
});
describe('hmget', function () { it('returns strings for keys requested in transaction', function (done) {
describe('first argument is a string', function () { client.multi().hmget('hash key 2', 'key 1', 'key 2').exec(function (err, reply) {
it('returns strings for keys requested', function (done) { assert.strictEqual(true, Array.isArray(reply))
client.hmget('hash key 2', 'key 1', 'key 2', function (err, reply) { assert.strictEqual(1, reply.length)
assert.strictEqual(true, Array.isArray(reply)); assert.strictEqual(2, reply[0].length)
assert.strictEqual(2, reply.length); assert.strictEqual('val 1', reply[0][0])
assert.strictEqual('val 1', reply[0]); assert.strictEqual('val 2', reply[0][1])
assert.strictEqual('val 2', reply[1]); return done(err)
return done(err); })
}); })
});
it('returns strings for keys requested in transaction', function (done) { it('handles array of strings with undefined values (repro #344)', function (done) {
client.multi().hmget('hash key 2', 'key 1', 'key 2').exec(function (err, reply) { client.hmget('hash key 2', 'key 3', 'key 4', function (err, reply) {
assert.strictEqual(true, Array.isArray(reply)); assert.strictEqual(true, Array.isArray(reply))
assert.strictEqual(1, reply.length); assert.strictEqual(2, reply.length)
assert.strictEqual(2, reply[0].length); assert.strictEqual(null, reply[0])
assert.strictEqual('val 1', reply[0][0]); assert.strictEqual(null, reply[1])
assert.strictEqual('val 2', reply[0][1]); return done(err)
return done(err); })
}); })
});
it('handles array of strings with undefined values (repro #344)', function (done) { it('handles array of strings with undefined values in transaction (repro #344)', function (done) {
client.hmget('hash key 2', 'key 3', 'key 4', function (err, reply) { client.multi().hmget('hash key 2', 'key 3', 'key 4').exec(function (err, reply) {
assert.strictEqual(true, Array.isArray(reply)); assert.strictEqual(true, Array.isArray(reply))
assert.strictEqual(2, reply.length); assert.strictEqual(1, reply.length)
assert.equal(null, reply[0]); assert.strictEqual(2, reply[0].length)
assert.equal(null, reply[1]); assert.strictEqual(null, reply[0][0])
return done(err); assert.strictEqual(null, reply[0][1])
}); return done(err)
}); })
})
})
it('handles array of strings with undefined values in transaction (repro #344)', function (done) { describe('first argument is a buffer', function () {
client.multi().hmget('hash key 2', 'key 3', 'key 4').exec(function (err, reply) { it('returns buffers for keys requested', function (done) {
assert.strictEqual(true, Array.isArray(reply)); client.hmget(Buffer.from('hash key 2'), 'key 1', 'key 2', function (err, reply) {
assert.strictEqual(1, reply.length); assert.strictEqual(true, Array.isArray(reply))
assert.strictEqual(2, reply[0].length); assert.strictEqual(2, reply.length)
assert.equal(null, reply[0][0]); assert.strictEqual(true, Buffer.isBuffer(reply[0]))
assert.equal(null, reply[0][1]); assert.strictEqual(true, Buffer.isBuffer(reply[1]))
return done(err); assert.strictEqual('<Buffer 76 61 6c 20 31>', reply[0].inspect())
}); assert.strictEqual('<Buffer 76 61 6c 20 32>', reply[1].inspect())
}); return done(err)
}); })
})
describe('first argument is a buffer', function () { it('returns buffers for keys requested in transaction', function (done) {
it('returns buffers for keys requested', function (done) { client.multi().hmget(Buffer.from('hash key 2'), 'key 1', 'key 2').exec(function (err, reply) {
client.hmget(new Buffer('hash key 2'), 'key 1', 'key 2', function (err, reply) { assert.strictEqual(true, Array.isArray(reply))
assert.strictEqual(true, Array.isArray(reply)); assert.strictEqual(1, reply.length)
assert.strictEqual(2, reply.length); assert.strictEqual(2, reply[0].length)
assert.strictEqual(true, Buffer.isBuffer(reply[0])); assert.strictEqual(true, Buffer.isBuffer(reply[0][0]))
assert.strictEqual(true, Buffer.isBuffer(reply[1])); assert.strictEqual(true, Buffer.isBuffer(reply[0][1]))
assert.strictEqual('<Buffer 76 61 6c 20 31>', reply[0].inspect()); assert.strictEqual('<Buffer 76 61 6c 20 31>', reply[0][0].inspect())
assert.strictEqual('<Buffer 76 61 6c 20 32>', reply[1].inspect()); assert.strictEqual('<Buffer 76 61 6c 20 32>', reply[0][1].inspect())
return done(err); return done(err)
}); })
}); })
it('returns buffers for keys requested in transaction', function (done) { it('returns buffers for keys requested in .batch', function (done) {
client.multi().hmget(new Buffer('hash key 2'), 'key 1', 'key 2').exec(function (err, reply) { client.batch().hmget(Buffer.from('hash key 2'), 'key 1', 'key 2').exec(function (err, reply) {
assert.strictEqual(true, Array.isArray(reply)); assert.strictEqual(true, Array.isArray(reply))
assert.strictEqual(1, reply.length); assert.strictEqual(1, reply.length)
assert.strictEqual(2, reply[0].length); assert.strictEqual(2, reply[0].length)
assert.strictEqual(true, Buffer.isBuffer(reply[0][0])); assert.strictEqual(true, Buffer.isBuffer(reply[0][0]))
assert.strictEqual(true, Buffer.isBuffer(reply[0][1])); assert.strictEqual(true, Buffer.isBuffer(reply[0][1]))
assert.strictEqual('<Buffer 76 61 6c 20 31>', reply[0][0].inspect()); assert.strictEqual('<Buffer 76 61 6c 20 31>', reply[0][0].inspect())
assert.strictEqual('<Buffer 76 61 6c 20 32>', reply[0][1].inspect()); assert.strictEqual('<Buffer 76 61 6c 20 32>', reply[0][1].inspect())
return done(err); return done(err)
}); })
}); })
})
})
it('returns buffers for keys requested in .batch', function (done) { describe('hgetall', function (done) {
client.batch().hmget(new Buffer('hash key 2'), 'key 1', 'key 2').exec(function (err, reply) { describe('first argument is a string', function () {
assert.strictEqual(true, Array.isArray(reply)); it('returns string values', function (done) {
assert.strictEqual(1, reply.length); client.hgetall('hash key 2', function (err, reply) {
assert.strictEqual(2, reply[0].length); assert.strictEqual('object', typeof reply)
assert.strictEqual(true, Buffer.isBuffer(reply[0][0])); assert.strictEqual(2, Object.keys(reply).length)
assert.strictEqual(true, Buffer.isBuffer(reply[0][1])); assert.strictEqual('val 1', reply['key 1'])
assert.strictEqual('<Buffer 76 61 6c 20 31>', reply[0][0].inspect()); assert.strictEqual('val 2', reply['key 2'])
assert.strictEqual('<Buffer 76 61 6c 20 32>', reply[0][1].inspect()); return done(err)
return done(err); })
}); })
});
});
});
describe('hgetall', function (done) { it('returns string values when executed in transaction', function (done) {
describe('first argument is a string', function () { client.multi().hgetall('hash key 2').exec(function (err, reply) {
it('returns string values', function (done) { assert.strictEqual(1, reply.length)
client.hgetall('hash key 2', function (err, reply) { assert.strictEqual('object', typeof reply[0])
assert.strictEqual('object', typeof reply); assert.strictEqual(2, Object.keys(reply[0]).length)
assert.strictEqual(2, Object.keys(reply).length); assert.strictEqual('val 1', reply[0]['key 1'])
assert.strictEqual('val 1', reply['key 1']); assert.strictEqual('val 2', reply[0]['key 2'])
assert.strictEqual('val 2', reply['key 2']); return done(err)
return done(err); })
}); })
});
it('returns string values when executed in transaction', function (done) { it('returns string values when executed in .batch', function (done) {
client.multi().hgetall('hash key 2').exec(function (err, reply) { client.batch().hgetall('hash key 2').exec(function (err, reply) {
assert.strictEqual(1, reply.length); assert.strictEqual(1, reply.length)
assert.strictEqual('object', typeof reply[0]); assert.strictEqual('object', typeof reply[0])
assert.strictEqual(2, Object.keys(reply[0]).length); assert.strictEqual(2, Object.keys(reply[0]).length)
assert.strictEqual('val 1', reply[0]['key 1']); assert.strictEqual('val 1', reply[0]['key 1'])
assert.strictEqual('val 2', reply[0]['key 2']); assert.strictEqual('val 2', reply[0]['key 2'])
return done(err); return done(err)
}); })
}); })
})
it('returns string values when executed in .batch', function (done) { describe('first argument is a buffer', function () {
client.batch().hgetall('hash key 2').exec(function (err, reply) { it('returns buffer values', function (done) {
assert.strictEqual(1, reply.length); client.hgetall(Buffer.from('hash key 2'), function (err, reply) {
assert.strictEqual('object', typeof reply[0]); assert.strictEqual(null, err)
assert.strictEqual(2, Object.keys(reply[0]).length); assert.strictEqual('object', typeof reply)
assert.strictEqual('val 1', reply[0]['key 1']); assert.strictEqual(2, Object.keys(reply).length)
assert.strictEqual('val 2', reply[0]['key 2']); assert.strictEqual(true, Buffer.isBuffer(reply['key 1']))
return done(err); assert.strictEqual(true, Buffer.isBuffer(reply['key 2']))
}); assert.strictEqual('<Buffer 76 61 6c 20 31>', reply['key 1'].inspect())
}); assert.strictEqual('<Buffer 76 61 6c 20 32>', reply['key 2'].inspect())
}); return done(err)
})
})
describe('first argument is a buffer', function () { it('returns buffer values when executed in transaction', function (done) {
it('returns buffer values', function (done) { client.multi().hgetall(Buffer.from('hash key 2')).exec(function (err, reply) {
client.hgetall(new Buffer('hash key 2'), function (err, reply) { assert.strictEqual(1, reply.length)
assert.strictEqual(null, err); assert.strictEqual('object', typeof reply[0])
assert.strictEqual('object', typeof reply); assert.strictEqual(2, Object.keys(reply[0]).length)
assert.strictEqual(2, Object.keys(reply).length); assert.strictEqual(true, Buffer.isBuffer(reply[0]['key 1']))
assert.strictEqual(true, Buffer.isBuffer(reply['key 1'])); assert.strictEqual(true, Buffer.isBuffer(reply[0]['key 2']))
assert.strictEqual(true, Buffer.isBuffer(reply['key 2'])); assert.strictEqual('<Buffer 76 61 6c 20 31>', reply[0]['key 1'].inspect())
assert.strictEqual('<Buffer 76 61 6c 20 31>', reply['key 1'].inspect()); assert.strictEqual('<Buffer 76 61 6c 20 32>', reply[0]['key 2'].inspect())
assert.strictEqual('<Buffer 76 61 6c 20 32>', reply['key 2'].inspect()); return done(err)
return done(err); })
}); })
});
it('returns buffer values when executed in transaction', function (done) { it('returns buffer values when executed in .batch', function (done) {
client.multi().hgetall(new Buffer('hash key 2')).exec(function (err, reply) { client.batch().hgetall(Buffer.from('hash key 2')).exec(function (err, reply) {
assert.strictEqual(1, reply.length); assert.strictEqual(1, reply.length)
assert.strictEqual('object', typeof reply[0]); assert.strictEqual('object', typeof reply[0])
assert.strictEqual(2, Object.keys(reply[0]).length); assert.strictEqual(2, Object.keys(reply[0]).length)
assert.strictEqual(true, Buffer.isBuffer(reply[0]['key 1'])); assert.strictEqual(true, Buffer.isBuffer(reply[0]['key 1']))
assert.strictEqual(true, Buffer.isBuffer(reply[0]['key 2'])); assert.strictEqual(true, Buffer.isBuffer(reply[0]['key 2']))
assert.strictEqual('<Buffer 76 61 6c 20 31>', reply[0]['key 1'].inspect()); assert.strictEqual('<Buffer 76 61 6c 20 31>', reply[0]['key 1'].inspect())
assert.strictEqual('<Buffer 76 61 6c 20 32>', reply[0]['key 2'].inspect()); assert.strictEqual('<Buffer 76 61 6c 20 32>', reply[0]['key 2'].inspect())
return done(err); return done(err)
}); })
}); })
})
it('returns buffer values when executed in .batch', function (done) { })
client.batch().hgetall(new Buffer('hash key 2')).exec(function (err, reply) { })
assert.strictEqual(1, reply.length);
assert.strictEqual('object', typeof reply[0]);
assert.strictEqual(2, Object.keys(reply[0]).length);
assert.strictEqual(true, Buffer.isBuffer(reply[0]['key 1']));
assert.strictEqual(true, Buffer.isBuffer(reply[0]['key 2']));
assert.strictEqual('<Buffer 76 61 6c 20 31>', reply[0]['key 1'].inspect());
assert.strictEqual('<Buffer 76 61 6c 20 32>', reply[0]['key 2'].inspect());
return done(err);
});
});
});
});
});

View File

@@ -1,59 +1,58 @@
'use strict'; 'use strict'
var assert = require('assert'); var assert = require('assert')
var config = require('./lib/config'); var config = require('./lib/config')
var fork = require('child_process').fork; var fork = require('child_process').fork
var redis = config.redis; var redis = config.redis
describe('stack traces', function () { describe('stack traces', function () {
it('should return good traces with NODE_ENV=development set', function (done) {
var external = fork('./test/lib/good-traces.js', {
env: {
NODE_ENV: 'development'
}
})
it('should return good traces with NODE_ENV=development set', function (done) { var id = setTimeout(function () {
var external = fork('./test/lib/good-traces.js', { external.kill()
env: { done(new Error('Timeout'))
NODE_ENV: 'development' }, 6000)
}
});
var id = setTimeout(function () { external.on('close', function (code) {
external.kill(); clearTimeout(id)
done(new Error('Timeout')); assert.strictEqual(code, 0)
}, 6000); done()
})
})
external.on('close', function (code) { it('should return good traces with NODE_DEBUG=redis env set', function (done) {
clearTimeout(id); var external = fork('./test/lib/good-traces.js', {
assert.strictEqual(code, 0); env: {
done(); NODE_DEBUG: 'redis'
}); },
}); silent: true
})
it('should return good traces with NODE_DEBUG=redis env set', function (done) { var id = setTimeout(function () {
var external = fork('./test/lib/good-traces.js', { external.kill()
env: { done(new Error('Timeout'))
NODE_DEBUG: 'redis' }, 6000)
},
silent: true
});
var id = setTimeout(function () { external.on('close', function (code) {
external.kill(); clearTimeout(id)
done(new Error('Timeout')); assert.strictEqual(code, 0)
}, 6000); done()
})
})
external.on('close', function (code) { // This is always going to return good stack traces
clearTimeout(id); it('should always return good stack traces for rejected offline commands', function (done) {
assert.strictEqual(code, 0); var client = redis.createClient({
done(); enableOfflineQueue: false
}); })
}); client.set('foo', function (err, res) {
assert(/good_traces.spec.js/.test(err.stack))
// This is always going to return good stack traces client.quit(done)
it('should always return good stack traces for rejected offline commands', function (done) { })
var client = redis.createClient({ })
enableOfflineQueue: false })
});
client.set('foo', function (err, res) {
assert(/good_traces.spec.js/.test(err.stack));
client.quit(done);
});
});
});

View File

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

View File

@@ -1,38 +1,38 @@
'use strict'; 'use strict'
// helpers for configuring a redis client in // helpers for configuring a redis client in
// its various modes, ipV6, ipV4, socket. // its various modes, ipV6, ipV4, socket.
var redis = require('../../index'); var redis = require('../../index')
var bluebird = require('bluebird'); var bluebird = require('bluebird')
// Promisify everything // Promisify everything
bluebird.promisifyAll(redis.RedisClient.prototype); bluebird.promisifyAll(redis.RedisClient.prototype)
bluebird.promisifyAll(redis.Multi.prototype); bluebird.promisifyAll(redis.Multi.prototype)
var config = { var config = {
redis: redis, redis: redis,
PORT: 6379, PORT: 6379,
HOST: { HOST: {
IPv4: '127.0.0.1', IPv4: '127.0.0.1',
IPv6: '::1' IPv6: '::1'
}, },
configureClient: function (ip, opts) { configureClient: function (ip, opts) {
var args = []; var args = []
// Do not manipulate the opts => copy them each time // Do not manipulate the opts => copy them each time
opts = opts ? JSON.parse(JSON.stringify(opts)) : {}; opts = opts ? JSON.parse(JSON.stringify(opts)) : {}
if (ip.match(/\.sock/)) { if (ip.match(/\.sock/)) {
args.push(ip); args.push(ip)
} else { } else {
args.push(config.PORT); args.push(config.PORT)
args.push(config.HOST[ip]); args.push(config.HOST[ip])
opts.family = ip; opts.family = ip
}
args.push(opts);
return args;
} }
};
module.exports = config; args.push(opts)
return args
}
}
module.exports = config

View File

@@ -1,20 +1,20 @@
// Spawned by the goodStacks.spec.js tests // Spawned by the goodStacks.spec.js tests
'use strict'; 'use strict'
var assert = require('assert'); var assert = require('assert')
var redis = require('../../index'); var redis = require('../../index')
var client = redis.createClient(); var client = redis.createClient()
// Both error cases would normally return bad stack traces // Both error cases would normally return bad stack traces
client.set('foo', function (err, res) { client.set('foo', function (err, res) {
assert(/good-traces.js:9:8/.test(err.stack)); assert(/good-traces.js:9:8/.test(err.stack))
client.set('foo', 'bar', function (err, res) { client.set('foo', 'bar', function (err, res) {
assert(/good-traces.js:11:12/.test(err.stack)); assert(/good-traces.js:11:10/.test(err.stack))
client.quit(function () { client.quit(function () {
process.exit(0); process.exit(0)
}); })
}); })
process.nextTick(function () { process.nextTick(function () {
client.stream.destroy(); client.stream.destroy()
}); })
}); })

View File

@@ -1,88 +1,88 @@
'use strict'; 'use strict'
// helper to start and stop the redis process. // helper to start and stop the redis process.
var config = require('./config'); var config = require('./config')
var fs = require('fs'); var fs = require('fs')
var path = require('path'); var path = require('path')
var spawn = require('win-spawn'); var spawn = require('win-spawn')
var tcpPortUsed = require('tcp-port-used'); var tcpPortUsed = require('tcp-port-used')
var bluebird = require('bluebird'); var bluebird = require('bluebird')
// wait for redis to be listening in // wait for redis to be listening in
// all three modes (ipv4, ipv6, socket). // all three modes (ipv4, ipv6, socket).
function waitForRedis (available, cb, port) { function waitForRedis (available, cb, port) {
if (process.platform === 'win32') return cb(); if (process.platform === 'win32') return cb()
var time = Date.now(); var time = Date.now()
var running = false; var running = false
var socket = '/tmp/redis.sock'; var socket = '/tmp/redis.sock'
if (port) { if (port) {
// We have to distinguishe the redis sockets if we have more than a single redis instance running // We have to distinguish the redis sockets if we have more than a single redis instance running
socket = '/tmp/redis' + port + '.sock'; socket = '/tmp/redis' + port + '.sock'
} }
port = port || config.PORT; port = port || config.PORT
var id = setInterval(function () { var id = setInterval(function () {
if (running) return; if (running) return
running = true; running = true
bluebird.join( bluebird.join(
tcpPortUsed.check(port, '127.0.0.1'), tcpPortUsed.check(port, '127.0.0.1'),
tcpPortUsed.check(port, '::1'), tcpPortUsed.check(port, '::1'),
function (ipV4, ipV6) { function (ipV4, ipV6) {
if (ipV6 === available && ipV4 === available) { if (ipV6 === available && ipV4 === available) {
if (fs.existsSync(socket) === available) { if (fs.existsSync(socket) === available) {
clearInterval(id); clearInterval(id)
return cb(); return cb()
} }
// The same message applies for can't stop but we ignore that case // The same message applies for can't stop but we ignore that case
throw new Error('Port ' + port + ' is already in use. Tests can\'t start.\n'); throw new Error('Port ' + port + ' is already in use. Tests can\'t start.\n')
} }
if (Date.now() - time > 6000) { if (Date.now() - time > 6000) {
throw new Error('Redis could not start on port ' + (port || config.PORT) + '\n'); throw new Error('Redis could not start on port ' + (port || config.PORT) + '\n')
} }
running = false; running = false
}).catch(function (err) { }).catch(function (err) {
console.error('\x1b[31m' + err.stack + '\x1b[0m\n'); console.error('\x1b[31m' + err.stack + '\x1b[0m\n')
process.exit(1); process.exit(1)
}); })
}, 100); }, 100)
} }
module.exports = { module.exports = {
start: function (done, conf, port) { start: function (done, conf, port) {
var spawnFailed = false; var spawnFailed = false
// spawn redis with our testing configuration. // spawn redis with our testing configuration.
var confFile = conf || path.resolve(__dirname, '../conf/redis.conf'); var confFile = conf || path.resolve(__dirname, '../conf/redis.conf')
var rp = spawn('redis-server', [confFile], {}); var rp = spawn('redis-server', [confFile], {})
// capture a failure booting redis, and give // capture a failure booting redis, and give
// the user running the test some directions. // the user running the test some directions.
rp.once('exit', function (code) { rp.once('exit', function (code) {
if (code !== 0) spawnFailed = true; if (code !== 0) spawnFailed = true
}); })
// wait for redis to become available, by // wait for redis to become available, by
// checking the port we bind on. // checking the port we bind on.
waitForRedis(true, function () { waitForRedis(true, function () {
// return an object that can be used in // return an object that can be used in
// an after() block to shutdown redis. // an after() block to shutdown redis.
return done(null, { return done(null, {
spawnFailed: function () { spawnFailed: function () {
return spawnFailed; return spawnFailed
}, },
stop: function (done) { stop: function (done) {
if (spawnFailed) return done(); if (spawnFailed) return done()
rp.once('exit', function (code) { rp.once('exit', function (code) {
var error = null; var error = null
if (code !== null && code !== 0) { if (code !== null && code !== 0) {
error = new Error('Redis shutdown failed with code ' + code); error = new Error('Redis shutdown failed with code ' + code)
} }
waitForRedis(false, function () { waitForRedis(false, function () {
return done(error); return done(error)
}, port); }, port)
}); })
rp.kill('SIGTERM'); rp.kill('SIGTERM')
} }
}); })
}, port); }, port)
} }
}; }

View File

@@ -1,83 +1,83 @@
'use strict'; 'use strict'
// helper to start and stop the stunnel process. // helper to start and stop the stunnel process.
var spawn = require('child_process').spawn; var spawn = require('child_process').spawn
var EventEmitter = require('events'); var EventEmitter = require('events')
var fs = require('fs'); var fs = require('fs')
var path = require('path'); var path = require('path')
var util = require('util'); var util = require('util')
function once (cb) { function once (cb) {
var called = false; var called = false
return function () { return function () {
if (called) return; if (called) return
called = true; called = true
cb.apply(this, arguments); cb.apply(this, arguments)
}; }
} }
function StunnelProcess (confDir) { function StunnelProcess (confDir) {
EventEmitter.call(this); EventEmitter.call(this)
// set up an stunnel to redis; edit the conf file to include required absolute paths // set up an stunnel to redis; edit the conf file to include required absolute paths
var confFile = path.resolve(confDir, 'stunnel.conf'); var confFile = path.resolve(confDir, 'stunnel.conf')
var confText = fs.readFileSync(confFile + '.template').toString().replace(/__dirname,/g, confDir); var confText = fs.readFileSync(confFile + '.template').toString().replace(/__dirname,/g, confDir)
fs.writeFileSync(confFile, confText); fs.writeFileSync(confFile, confText)
var stunnel = this.stunnel = spawn('stunnel', [confFile]); var stunnel = this.stunnel = spawn('stunnel', [confFile])
// handle child process events, and failure to set up tunnel // handle child process events, and failure to set up tunnel
var self = this; var self = this
this.timer = setTimeout(function () { this.timer = setTimeout(function () {
self.emit('error', new Error('Timeout waiting for stunnel to start')); self.emit('error', new Error('Timeout waiting for stunnel to start'))
}, 8000); }, 8000)
stunnel.on('error', function (err) { stunnel.on('error', function (err) {
self.clear(); self.clear()
self.emit('error', err); self.emit('error', err)
}); })
stunnel.on('exit', function (code) { stunnel.on('exit', function (code) {
self.clear(); self.clear()
if (code === 0) { if (code === 0) {
self.emit('stopped'); self.emit('stopped')
} else { } else {
self.emit('error', new Error('Stunnel exited unexpectedly; code = ' + code)); self.emit('error', new Error('Stunnel exited unexpectedly; code = ' + code))
} }
}); })
// wait to stunnel to start // wait to stunnel to start
stunnel.stderr.on('data', function (data) { stunnel.stderr.on('data', function (data) {
if (data.toString().match(/Service.+redis.+bound/)) { if (data.toString().match(/Service.+redis.+bound/)) {
clearTimeout(this.timer); clearTimeout(this.timer)
self.emit('started'); self.emit('started')
} }
}); })
} }
util.inherits(StunnelProcess, EventEmitter); util.inherits(StunnelProcess, EventEmitter)
StunnelProcess.prototype.clear = function () { StunnelProcess.prototype.clear = function () {
this.stunnel = null; this.stunnel = null
clearTimeout(this.timer); clearTimeout(this.timer)
}; }
StunnelProcess.prototype.stop = function (done) { StunnelProcess.prototype.stop = function (done) {
if (this.stunnel) { if (this.stunnel) {
this.stunnel.kill(); this.stunnel.kill()
} }
}; }
module.exports = { module.exports = {
start: function (done, confDir) { start: function (done, confDir) {
done = once(done); done = once(done)
var stunnel = new StunnelProcess(confDir); var 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))
}, },
stop: function (stunnel, done) { stop: function (stunnel, done) {
stunnel.removeAllListeners(); stunnel.removeAllListeners()
stunnel.stop(); stunnel.stop()
stunnel.once('error', done.bind(done)); stunnel.once('error', done.bind(done))
stunnel.once('stopped', done.bind(done, null)); stunnel.once('stopped', done.bind(done, null))
} }
}; }

View File

@@ -1,17 +1,17 @@
// 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'
var redis = require('../../index'); var redis = require('../../index')
var HOST = process.argv[2] || '127.0.0.1'; var HOST = process.argv[2] || '127.0.0.1'
var PORT = process.argv[3]; var PORT = process.argv[3]
var args = PORT ? [PORT, HOST] : [HOST]; var args = PORT ? [PORT, HOST] : [HOST]
var c = redis.createClient.apply(redis, args); var c = redis.createClient.apply(redis, args)
c.info(function (err, reply) { c.info(function (err, reply) {
if (err) process.exit(-1); if (err) process.exit(-1)
if (!reply.length) process.exit(-1); if (!reply.length) process.exit(-1)
process.stdout.write(reply.length.toString()); process.stdout.write(reply.length.toString())
}); })
c.unref(); c.unref()

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@@ -1,118 +1,94 @@
'use strict'; 'use strict'
var assert = require('assert'); var assert = require('assert')
var config = require('./lib/config'); var config = require('./lib/config')
var helper = require('./helper'); var helper = require('./helper')
var redis = config.redis; var redis = config.redis
describe('prefix key names', function () { describe('prefix key names', function () {
helper.allTests(function (ip, args) {
describe('using ' + ip, function () {
var client = null
helper.allTests(function (ip, args) { beforeEach(function (done) {
client = redis.createClient({
prefix: 'test:prefix:'
})
client.on('ready', function () {
client.flushdb(function (err) {
done(err)
})
})
})
describe('using ' + ip, function () { afterEach(function () {
var client = null; client.end(true)
})
beforeEach(function (done) { it('auto prefix set / get', function (done) {
client = redis.createClient({ client.set('key', 'value', helper.isString('OK'))
prefix: 'test:prefix:' client.get('key', helper.isString('value'))
}); client.getrange('key', 1, -1, function (err, reply) {
client.on('ready', function () { assert.strictEqual(reply, 'alue')
client.flushdb(function (err) { assert.strictEqual(err, null)
done(err); })
}); client.exists('key', helper.isNumber(1))
}); // The key will be prefixed itself
}); client.exists('test:prefix:key', helper.isNumber(0))
client.mset('key2', 'value2', 'key3', 'value3')
client.keys('*', function (err, res) {
assert.strictEqual(err, null)
assert.strictEqual(res.length, 3)
assert(res.indexOf('test:prefix:key') !== -1)
assert(res.indexOf('test:prefix:key2') !== -1)
assert(res.indexOf('test:prefix:key3') !== -1)
done()
})
})
afterEach(function () { it('auto prefix set / get with .batch', function (done) {
client.end(true); var batch = client.batch()
}); batch.set('key', 'value', helper.isString('OK'))
batch.get('key', helper.isString('value'))
batch.getrange('key', 1, -1, function (err, reply) {
assert.strictEqual(reply, 'alue')
assert.strictEqual(err, null)
})
batch.exists('key', helper.isNumber(1))
// The key will be prefixed itself
batch.exists('test:prefix:key', helper.isNumber(0))
batch.mset('key2', 'value2', 'key3', 'value3')
batch.keys('*', function (err, res) {
assert.strictEqual(err, null)
assert.strictEqual(res.length, 3)
assert(res.indexOf('test:prefix:key') !== -1)
assert(res.indexOf('test:prefix:key2') !== -1)
assert(res.indexOf('test:prefix:key3') !== -1)
})
batch.exec(done)
})
it('auto prefix set / get', function (done) { it('auto prefix set / get with .multi', function (done) {
client.set('key', 'value', function (err, reply) { var multi = client.multi()
assert.strictEqual(reply, 'OK'); multi.set('key', 'value', helper.isString('OK'))
}); multi.get('key', helper.isString('value'))
client.get('key', function (err, reply) { multi.getrange('key', 1, -1, function (err, reply) {
assert.strictEqual(reply, 'value'); assert.strictEqual(reply, 'alue')
}); assert.strictEqual(err, null)
client.getrange('key', 1, -1, function (err, reply) { })
assert.strictEqual(reply, 'alue'); multi.exists('key', helper.isNumber(1))
assert.strictEqual(err, null); // The key will be prefixed itself
}); multi.exists('test:prefix:key', helper.isNumber(0))
client.exists('key', function (err, res) { multi.mset('key2', 'value2', 'key3', 'value3')
assert.strictEqual(res, 1); multi.keys('*', function (err, res) {
}); assert.strictEqual(err, null)
client.exists('test:prefix:key', function (err, res) { assert.strictEqual(res.length, 3)
// The key will be prefixed itself assert(res.indexOf('test:prefix:key') !== -1)
assert.strictEqual(res, 0); assert(res.indexOf('test:prefix:key2') !== -1)
}); assert(res.indexOf('test:prefix:key3') !== -1)
client.mset('key2', 'value2', 'key3', 'value3'); })
client.keys('*', function (err, res) { multi.exec(done)
assert.strictEqual(res.length, 3); })
assert(res.indexOf('test:prefix:key') !== -1); })
assert(res.indexOf('test:prefix:key2') !== -1); })
assert(res.indexOf('test:prefix:key3') !== -1); })
done();
});
});
it('auto prefix set / get with .batch', function (done) {
var batch = client.batch();
batch.set('key', 'value', function (err, reply) {
assert.strictEqual(reply, 'OK');
});
batch.get('key', function (err, reply) {
assert.strictEqual(reply, 'value');
});
batch.getrange('key', 1, -1, function (err, reply) {
assert.strictEqual(reply, 'alue');
assert.strictEqual(err, null);
});
batch.exists('key', function (err, res) {
assert.strictEqual(res, 1);
});
batch.exists('test:prefix:key', function (err, res) {
// The key will be prefixed itself
assert.strictEqual(res, 0);
});
batch.mset('key2', 'value2', 'key3', 'value3');
batch.keys('*', function (err, res) {
assert.strictEqual(res.length, 3);
assert(res.indexOf('test:prefix:key') !== -1);
assert(res.indexOf('test:prefix:key2') !== -1);
assert(res.indexOf('test:prefix:key3') !== -1);
});
batch.exec(done);
});
it('auto prefix set / get with .multi', function (done) {
var multi = client.multi();
multi.set('key', 'value', function (err, reply) {
assert.strictEqual(reply, 'OK');
});
multi.get('key', function (err, reply) {
assert.strictEqual(reply, 'value');
});
multi.getrange('key', 1, -1, function (err, reply) {
assert.strictEqual(reply, 'alue');
assert.strictEqual(err, null);
});
multi.exists('key', function (err, res) {
assert.strictEqual(res, 1);
});
multi.exists('test:prefix:key', function (err, res) {
// The key will be prefixed itself
assert.strictEqual(res, 0);
});
multi.mset('key2', 'value2', 'key3', 'value3');
multi.keys('*', function (err, res) {
assert.strictEqual(res.length, 3);
assert(res.indexOf('test:prefix:key') !== -1);
assert(res.indexOf('test:prefix:key2') !== -1);
assert(res.indexOf('test:prefix:key3') !== -1);
});
multi.exec(done);
});
});
});
});

Some files were not shown because too many files have changed in this diff Show More