You've already forked node-redis
mirror of
https://github.com/redis/node-redis.git
synced 2025-08-01 16:46:54 +03:00
Added individual error classes Don't silently fail for commands without callback from now on General polishing (e.g. better error messages) Fix typos
351 lines
16 KiB
JavaScript
351 lines
16 KiB
JavaScript
'use strict';
|
|
|
|
var assert = require('assert');
|
|
var config = require('./lib/config');
|
|
var helper = require('./helper');
|
|
var redis = config.redis;
|
|
|
|
describe("The 'batch' method", function () {
|
|
|
|
helper.allTests(function (parser, ip, args) {
|
|
|
|
describe('using ' + parser + ' and ' + ip, function () {
|
|
|
|
describe('when not connected', function () {
|
|
var client;
|
|
|
|
beforeEach(function (done) {
|
|
client = redis.createClient.apply(null, args);
|
|
client.once('connect', function () {
|
|
client.quit();
|
|
});
|
|
client.on('end', done);
|
|
});
|
|
|
|
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();
|
|
});
|
|
});
|
|
|
|
it('returns an error for batch with commands', function (done) {
|
|
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();
|
|
});
|
|
});
|
|
|
|
it('returns an empty array for missing commands if promisified', function () {
|
|
return client.batch().execAsync().then(function (res) {
|
|
assert.strictEqual(res.length, 0);
|
|
});
|
|
});
|
|
});
|
|
|
|
describe('when connected', function () {
|
|
var client;
|
|
|
|
beforeEach(function (done) {
|
|
client = redis.createClient.apply(null, args);
|
|
client.once('ready', function () {
|
|
client.flushdb(function (err) {
|
|
return done(err);
|
|
});
|
|
});
|
|
});
|
|
|
|
afterEach(function () {
|
|
client.end(true);
|
|
});
|
|
|
|
it('returns an empty array and keep the execution order in takt', function (done) {
|
|
var called = false;
|
|
client.set('foo', 'bar', function (err, res) {
|
|
called = true;
|
|
});
|
|
var batch = client.batch();
|
|
batch.exec(function (err, res) {
|
|
assert.strictEqual(err, null);
|
|
assert.strictEqual(res.length, 0);
|
|
assert(called);
|
|
done();
|
|
});
|
|
});
|
|
|
|
it('runs normal calls inbetween batch', function (done) {
|
|
var batch = client.batch();
|
|
batch.set('m1', '123');
|
|
client.set('m2', '456', done);
|
|
});
|
|
|
|
it('returns an empty array if promisified', function () {
|
|
return client.batch().execAsync().then(function (res) {
|
|
assert.strictEqual(res.length, 0);
|
|
});
|
|
});
|
|
|
|
it('returns an empty result array', function (done) {
|
|
var batch = client.batch();
|
|
var async = true;
|
|
var notBuffering = batch.exec(function (err, res) {
|
|
assert.strictEqual(err, null);
|
|
assert.strictEqual(res.length, 0);
|
|
async = false;
|
|
done();
|
|
});
|
|
assert(async);
|
|
assert.strictEqual(notBuffering, true);
|
|
});
|
|
|
|
it('fail individually when one command fails using chaining notation', function (done) {
|
|
var batch1, batch2;
|
|
batch1 = client.batch();
|
|
batch1.mset('batchfoo', '10', 'batchbar', '20', helper.isString('OK'));
|
|
|
|
// Provoke an error at queue time
|
|
batch1.set('foo2', helper.isError());
|
|
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(null, replies[0]);
|
|
assert.strictEqual(22, replies[1]);
|
|
assert.strictEqual(12, replies[2]);
|
|
return done();
|
|
});
|
|
});
|
|
});
|
|
|
|
it('fail individually when one command fails and emit the error if no callback has been provided', function (done) {
|
|
var batch1;
|
|
client.on('error', function (err) {
|
|
done(err);
|
|
});
|
|
batch1 = client.batch();
|
|
batch1.mset('batchfoo', '10', 'batchbar', '20', helper.isString('OK'));
|
|
|
|
// Provoke an error at queue time
|
|
batch1.set('foo2');
|
|
batch1.incr('batchfoo');
|
|
batch1.incr('batchbar');
|
|
batch1.exec(function (err, res) {
|
|
assert.strictEqual(res[1].command, 'SET');
|
|
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
|
|
client.batch([
|
|
['mget', 'batchfoo', 'batchbar', function (err, res) {
|
|
assert.strictEqual(2, res.length);
|
|
assert.strictEqual(0, +res[0]);
|
|
assert.strictEqual(0, +res[1]);
|
|
}],
|
|
['set', 'foo2', helper.isError()],
|
|
['incr', 'batchfoo'],
|
|
['incr', 'batchbar']
|
|
]).exec(function (err, replies) {
|
|
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) {
|
|
client.sadd('some set', 'mem 1');
|
|
client.sadd(['some set', 'mem 2']);
|
|
client.sadd('some set', 'mem 3');
|
|
client.sadd('some set', 'mem 4');
|
|
|
|
// make sure empty mb reply works
|
|
client.del('some missing set');
|
|
client.smembers('some missing set', function (err, reply) {
|
|
// make sure empty mb reply works
|
|
assert.strictEqual(0, reply.length);
|
|
});
|
|
|
|
// test nested batch-bulk replies with empty mb elements.
|
|
client.BATCH([
|
|
['smembers', ['some set']],
|
|
['del', 'some set'],
|
|
['smembers', 'some set', undefined] // The explicit undefined is handled as a callback that is undefined
|
|
])
|
|
.scard('some set')
|
|
.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) {
|
|
var now = Date.now();
|
|
var arr = ['batchhmset', 'batchbar', 'batchbaz'];
|
|
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) {
|
|
// TODO: Converting the key might change soon again.
|
|
client.batch().hmset(true, {
|
|
test: 123,
|
|
bar: 'baz'
|
|
}).exec(done);
|
|
});
|
|
|
|
it('runs a batch without any further commands', function (done) {
|
|
var buffering = client.batch().exec(function (err, res) {
|
|
assert.strictEqual(err, null);
|
|
assert.strictEqual(res.length, 0);
|
|
done();
|
|
});
|
|
assert(typeof buffering === 'boolean');
|
|
});
|
|
|
|
it('runs a batch without any further commands and without callback', function () {
|
|
var buffering = client.batch().exec();
|
|
assert.strictEqual(buffering, true);
|
|
});
|
|
|
|
it('allows multiple operations to be performed using a chaining API', function (done) {
|
|
client.batch()
|
|
.mset('some', '10', 'keys', '20')
|
|
.incr('some')
|
|
.incr('keys')
|
|
.mget('some', 'keys')
|
|
.exec(function (err, replies) {
|
|
assert.strictEqual(null, err);
|
|
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());
|
|
return done();
|
|
});
|
|
});
|
|
|
|
it('allows multiple commands to work the same as normal to be performed using a chaining API', function (done) {
|
|
client.batch()
|
|
.mset(['some', '10', 'keys', '20'])
|
|
.incr('some', helper.isNumber(11))
|
|
.incr(['keys'], helper.isNumber(21))
|
|
.mget('some', 'keys')
|
|
.exec(function (err, replies) {
|
|
assert.strictEqual(null, err);
|
|
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());
|
|
return done();
|
|
});
|
|
});
|
|
|
|
it('allows multiple commands to work the same as normal to be performed using a chaining API promisified', function () {
|
|
return client.batch()
|
|
.mset(['some', '10', 'keys', '20'])
|
|
.incr('some', helper.isNumber(11))
|
|
.incr(['keys'], helper.isNumber(21))
|
|
.mget('some', 'keys')
|
|
.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) {
|
|
// 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));
|
|
});
|
|
|
|
});
|
|
});
|
|
});
|
|
});
|