|
| 1 | +'use strict'; |
| 2 | + |
| 3 | +var assert = require('assert'); |
| 4 | +var config = require("../lib/config"); |
| 5 | +var helper = require('../helper'); |
| 6 | +var redis = config.redis; |
| 7 | +var uuid = require('uuid'); |
| 8 | + |
| 9 | +describe("The 'batch' method", function () { |
| 10 | + |
| 11 | + helper.allTests(function(parser, ip, args) { |
| 12 | + |
| 13 | + describe("using " + parser + " and " + ip, function () { |
| 14 | + var key, value; |
| 15 | + |
| 16 | + beforeEach(function () { |
| 17 | + key = uuid.v4(); |
| 18 | + value = uuid.v4(); |
| 19 | + }); |
| 20 | + |
| 21 | + describe("when not connected", function () { |
| 22 | + var client; |
| 23 | + |
| 24 | + beforeEach(function (done) { |
| 25 | + client = redis.createClient.apply(redis.createClient, args); |
| 26 | + client.once("connect", function () { |
| 27 | + client.quit(); |
| 28 | + }); |
| 29 | + client.on('end', function () { |
| 30 | + return done(); |
| 31 | + }); |
| 32 | + }); |
| 33 | + |
| 34 | + it("returns an empty array", function (done) { |
| 35 | + var batch = client.batch(); |
| 36 | + batch.exec(function (err, res) { |
| 37 | + assert.strictEqual(err, null); |
| 38 | + assert.strictEqual(res.length, 0); |
| 39 | + done(); |
| 40 | + }); |
| 41 | + }); |
| 42 | + |
| 43 | + it("returns an empty array if promisified", function () { |
| 44 | + return client.batch().execAsync().then(function(res) { |
| 45 | + assert.strictEqual(res.length, 0); |
| 46 | + }); |
| 47 | + }); |
| 48 | + }); |
| 49 | + |
| 50 | + describe("when connected", function () { |
| 51 | + var client; |
| 52 | + |
| 53 | + beforeEach(function (done) { |
| 54 | + client = redis.createClient.apply(redis.createClient, args); |
| 55 | + client.once("connect", function () { |
| 56 | + client.flushdb(function (err) { |
| 57 | + return done(err); |
| 58 | + }); |
| 59 | + }); |
| 60 | + }); |
| 61 | + |
| 62 | + afterEach(function () { |
| 63 | + client.end(); |
| 64 | + }); |
| 65 | + |
| 66 | + it('fail individually when one command fails using chaining notation', function (done) { |
| 67 | + var batch1, batch2; |
| 68 | + batch1 = client.batch(); |
| 69 | + batch1.mset("batchfoo", "10", "batchbar", "20", helper.isString("OK")); |
| 70 | + |
| 71 | + // Provoke an error at queue time |
| 72 | + batch1.set("foo2", helper.isError()); |
| 73 | + batch1.incr("batchfoo"); |
| 74 | + batch1.incr("batchbar"); |
| 75 | + batch1.exec(function () { |
| 76 | + // Confirm that the previous command, while containing an error, still worked. |
| 77 | + batch2 = client.batch(); |
| 78 | + batch2.get('foo2', helper.isNull()); |
| 79 | + batch2.incr("batchbar", helper.isNumber(22)); |
| 80 | + batch2.incr("batchfoo", helper.isNumber(12)); |
| 81 | + batch2.exec(function (err, replies) { |
| 82 | + assert.strictEqual(null, replies[0]); |
| 83 | + assert.strictEqual(22, replies[1]); |
| 84 | + assert.strictEqual(12, replies[2]); |
| 85 | + return done(); |
| 86 | + }); |
| 87 | + }); |
| 88 | + }); |
| 89 | + |
| 90 | + it('fail individually when one command fails and emit the error if no callback has been provided', function (done) { |
| 91 | + var batch1; |
| 92 | + client.on('error', function (err) { |
| 93 | + done(err); |
| 94 | + }); |
| 95 | + batch1 = client.batch(); |
| 96 | + batch1.mset("batchfoo", "10", "batchbar", "20", helper.isString("OK")); |
| 97 | + |
| 98 | + // Provoke an error at queue time |
| 99 | + batch1.set("foo2"); |
| 100 | + batch1.incr("batchfoo"); |
| 101 | + batch1.incr("batchbar"); |
| 102 | + batch1.exec(function (err, res) { |
| 103 | + assert.strictEqual(res[1].command, 'SET'); |
| 104 | + assert.strictEqual(res[1].code, 'ERR'); |
| 105 | + done(); |
| 106 | + }); |
| 107 | + }); |
| 108 | + |
| 109 | + it('fail individually when one command in an array of commands fails', function (done) { |
| 110 | + // test nested batch-bulk replies |
| 111 | + client.batch([ |
| 112 | + ["mget", "batchfoo", "batchbar", function (err, res) { |
| 113 | + assert.strictEqual(2, res.length); |
| 114 | + assert.strictEqual(0, +res[0]); |
| 115 | + assert.strictEqual(0, +res[1]); |
| 116 | + }], |
| 117 | + ["set", "foo2", helper.isError()], |
| 118 | + ["incr", "batchfoo"], |
| 119 | + ["incr", "batchbar"] |
| 120 | + ]).exec(function (err, replies) { |
| 121 | + assert.strictEqual(2, replies[0].length); |
| 122 | + assert.strictEqual(null, replies[0][0]); |
| 123 | + assert.strictEqual(null, replies[0][1]); |
| 124 | + assert.strictEqual('SET', replies[1].command); |
| 125 | + assert.strictEqual("1", replies[2].toString()); |
| 126 | + assert.strictEqual("1", replies[3].toString()); |
| 127 | + return done(); |
| 128 | + }); |
| 129 | + }); |
| 130 | + |
| 131 | + it('handles batchple operations being applied to a set', function (done) { |
| 132 | + client.sadd("some set", "mem 1"); |
| 133 | + client.sadd(["some set", "mem 2"]); |
| 134 | + client.sadd("some set", "mem 3"); |
| 135 | + client.sadd("some set", "mem 4"); |
| 136 | + |
| 137 | + // make sure empty mb reply works |
| 138 | + client.del("some missing set"); |
| 139 | + client.smembers("some missing set", function (err, reply) { |
| 140 | + // make sure empty mb reply works |
| 141 | + assert.strictEqual(0, reply.length); |
| 142 | + }); |
| 143 | + |
| 144 | + // test nested batch-bulk replies with empty mb elements. |
| 145 | + client.BATCH([ |
| 146 | + ["smembers", ["some set"]], |
| 147 | + ["del", "some set"], |
| 148 | + ["smembers", "some set"] |
| 149 | + ]) |
| 150 | + .scard("some set") |
| 151 | + .exec(function (err, replies) { |
| 152 | + assert.strictEqual(4, replies[0].length); |
| 153 | + assert.strictEqual(0, replies[2].length); |
| 154 | + return done(); |
| 155 | + }); |
| 156 | + }); |
| 157 | + |
| 158 | + it('allows batchple operations to be performed using constructor with all kinds of syntax', function (done) { |
| 159 | + var now = Date.now(); |
| 160 | + var arr = ["batchhmset", "batchbar", "batchbaz"]; |
| 161 | + var arr2 = ['some manner of key', 'otherTypes']; |
| 162 | + var arr3 = [5768, "batchbarx", "batchfoox"]; |
| 163 | + var arr4 = ["mset", [578, "batchbar"], helper.isString('OK')]; |
| 164 | + client.batch([ |
| 165 | + arr4, |
| 166 | + [["mset", "batchfoo2", "batchbar2", "batchfoo3", "batchbar3"], helper.isString('OK')], |
| 167 | + ["hmset", arr], |
| 168 | + [["hmset", "batchhmset2", "batchbar2", "batchfoo3", "batchbar3", "test", helper.isString('OK')]], |
| 169 | + ["hmset", ["batchhmset", "batchbar", "batchfoo", helper.isString('OK')]], |
| 170 | + ["hmset", arr3, helper.isString('OK')], |
| 171 | + ['hmset', now, {123456789: "abcdefghij", "some manner of key": "a type of value", "otherTypes": 555}], |
| 172 | + ['hmset', 'key2', {"0123456789": "abcdefghij", "some manner of key": "a type of value", "otherTypes": 999}, helper.isString('OK')], |
| 173 | + ["HMSET", "batchhmset", ["batchbar", "batchbaz"]], |
| 174 | + ["hmset", "batchhmset", ["batchbar", "batchbaz"], helper.isString('OK')], |
| 175 | + ]) |
| 176 | + .hmget(now, 123456789, 'otherTypes') |
| 177 | + .hmget('key2', arr2, function noop() {}) |
| 178 | + .hmget(['batchhmset2', 'some manner of key', 'batchbar3']) |
| 179 | + .mget('batchfoo2', ['batchfoo3', 'batchfoo'], function(err, res) { |
| 180 | + assert(res[0], 'batchfoo3'); |
| 181 | + assert(res[1], 'batchfoo'); |
| 182 | + }) |
| 183 | + .exec(function (err, replies) { |
| 184 | + assert.equal(arr.length, 3); |
| 185 | + assert.equal(arr2.length, 2); |
| 186 | + assert.equal(arr3.length, 3); |
| 187 | + assert.equal(arr4.length, 3); |
| 188 | + assert.strictEqual(null, err); |
| 189 | + assert.equal(replies[10][1], '555'); |
| 190 | + assert.equal(replies[11][0], 'a type of value'); |
| 191 | + assert.strictEqual(replies[12][0], null); |
| 192 | + assert.equal(replies[12][1], 'test'); |
| 193 | + assert.equal(replies[13][0], 'batchbar2'); |
| 194 | + assert.equal(replies[13].length, 3); |
| 195 | + assert.equal(replies.length, 14); |
| 196 | + return done(); |
| 197 | + }); |
| 198 | + }); |
| 199 | + |
| 200 | + it('converts a non string key to a string', function(done) { |
| 201 | + // TODO: Converting the key might change soon again. |
| 202 | + client.batch().hmset(true, { |
| 203 | + test: 123, |
| 204 | + bar: 'baz' |
| 205 | + }).exec(done); |
| 206 | + }); |
| 207 | + |
| 208 | + it('runs a batch without any further commands', function(done) { |
| 209 | + var buffering = client.batch().exec(function(err, res) { |
| 210 | + assert.strictEqual(err, null); |
| 211 | + assert.strictEqual(res.length, 0); |
| 212 | + done(); |
| 213 | + }); |
| 214 | + assert(typeof buffering === 'boolean'); |
| 215 | + }); |
| 216 | + |
| 217 | + it('runs a batch without any further commands and without callback', function() { |
| 218 | + var buffering = client.batch().exec(); |
| 219 | + assert(typeof buffering === 'boolean'); |
| 220 | + assert(!buffering); |
| 221 | + }); |
| 222 | + |
| 223 | + it('allows batchple operations to be performed using a chaining API', function (done) { |
| 224 | + client.batch() |
| 225 | + .mset('some', '10', 'keys', '20') |
| 226 | + .incr('some') |
| 227 | + .incr('keys') |
| 228 | + .mget('some', 'keys') |
| 229 | + .exec(function (err, replies) { |
| 230 | + assert.strictEqual(null, err); |
| 231 | + assert.equal('OK', replies[0]); |
| 232 | + assert.equal(11, replies[1]); |
| 233 | + assert.equal(21, replies[2]); |
| 234 | + assert.equal(11, replies[3][0].toString()); |
| 235 | + assert.equal(21, replies[3][1].toString()); |
| 236 | + return done(); |
| 237 | + }); |
| 238 | + }); |
| 239 | + |
| 240 | + it('allows batchple commands to work the same as normal to be performed using a chaining API', function (done) { |
| 241 | + client.batch() |
| 242 | + .mset(['some', '10', 'keys', '20']) |
| 243 | + .incr(['some', helper.isNumber(11)]) |
| 244 | + .incr(['keys'], helper.isNumber(21)) |
| 245 | + .mget('some', 'keys') |
| 246 | + .exec(function (err, replies) { |
| 247 | + assert.strictEqual(null, err); |
| 248 | + assert.equal('OK', replies[0]); |
| 249 | + assert.equal(11, replies[1]); |
| 250 | + assert.equal(21, replies[2]); |
| 251 | + assert.equal(11, replies[3][0].toString()); |
| 252 | + assert.equal(21, replies[3][1].toString()); |
| 253 | + return done(); |
| 254 | + }); |
| 255 | + }); |
| 256 | + |
| 257 | + it('allows batchple commands to work the same as normal to be performed using a chaining API promisified', function () { |
| 258 | + return client.batch() |
| 259 | + .mset(['some', '10', 'keys', '20']) |
| 260 | + .incr(['some', helper.isNumber(11)]) |
| 261 | + .incr(['keys'], helper.isNumber(21)) |
| 262 | + .mget('some', 'keys') |
| 263 | + .execAsync() |
| 264 | + .then(function (replies) { |
| 265 | + assert.equal('OK', replies[0]); |
| 266 | + assert.equal(11, replies[1]); |
| 267 | + assert.equal(21, replies[2]); |
| 268 | + assert.equal(11, replies[3][0].toString()); |
| 269 | + assert.equal(21, replies[3][1].toString()); |
| 270 | + }); |
| 271 | + }); |
| 272 | + |
| 273 | + it('allows an array to be provided indicating batchple operations to perform', function (done) { |
| 274 | + // test nested batch-bulk replies with nulls. |
| 275 | + client.batch([ |
| 276 | + ["mget", ["batchfoo", "some", "random value", "keys"]], |
| 277 | + ["incr", "batchfoo"] |
| 278 | + ]) |
| 279 | + .exec(function (err, replies) { |
| 280 | + assert.strictEqual(replies.length, 2); |
| 281 | + assert.strictEqual(replies[0].length, 4); |
| 282 | + return done(); |
| 283 | + }); |
| 284 | + }); |
| 285 | + |
| 286 | + it('allows multiple operations to be performed on a hash', function (done) { |
| 287 | + client.batch() |
| 288 | + .hmset("batchhash", "a", "foo", "b", 1) |
| 289 | + .hmset("batchhash", { |
| 290 | + extra: "fancy", |
| 291 | + things: "here" |
| 292 | + }) |
| 293 | + .hgetall("batchhash") |
| 294 | + .exec(done); |
| 295 | + }); |
| 296 | + |
| 297 | + it("should work without any callback", function (done) { |
| 298 | + helper.serverVersionAtLeast.call(this, client, [2, 6, 5]); |
| 299 | + |
| 300 | + var batch = client.batch(); |
| 301 | + batch.set("baz", "binary"); |
| 302 | + batch.set("foo", "bar"); |
| 303 | + batch.exec(); |
| 304 | + |
| 305 | + client.get('foo', helper.isString('bar', done)); |
| 306 | + }); |
| 307 | + |
| 308 | + }); |
| 309 | + }); |
| 310 | + }); |
| 311 | +}); |
0 commit comments