From 504f8f16cb9cac9af5f59c3202a263f9f5dfc5d6 Mon Sep 17 00:00:00 2001 From: Ian Taylor Date: Wed, 30 Aug 2017 22:36:55 -0700 Subject: [PATCH 1/2] Add ioRedis support --- _src/index.ts | 41 +- index.js | 36 +- package.json | 4 +- test/ioredis.coffee | 682 +++++++++++++++++++ test/ioredis.js | 905 +++++++++++++++++++++++++ test/test.js | 1549 ++++++++++++++++++++++--------------------- 6 files changed, 2436 insertions(+), 781 deletions(-) create mode 100644 test/ioredis.coffee create mode 100644 test/ioredis.js diff --git a/_src/index.ts b/_src/index.ts index d3a9d88..1b7d075 100644 --- a/_src/index.ts +++ b/_src/index.ts @@ -60,14 +60,24 @@ class RedisSMQ extends EventEmitter { this.realtime = opts.realtime; this.redisns = opts.ns + ":"; - if (opts.client && options.client.constructor.name === "RedisClient") { - this.redis = opts.client + if (opts.client) { + if (opts.client.constructor.name === "Redis") { + this.redis = opts.client + this.isIoRedis = true + } else if (opts.client.constructor.name === "RedisClient") { + this.redis = opts.client + } } else { this.redis = RedisInst.createClient(opts) } - this.connected = this.redis.connected || false; + if (this.isIoRedis) { + this.connected = this.redis.status === 'ready'; + } + else { + this.connected = this.redis.connected || false; + } // If external client is used it might alrdy be connected. So we check here: if (this.connected) { @@ -122,6 +132,7 @@ class RedisSMQ extends EventEmitter { ["time"] ]; this.redis.multi(mc).exec( (err, resp) => { + resp = this._ioRedisMultiToRedisMulti(resp) if (err) { this._handleError(cb, err); return; } if (resp[0][0] === null || resp[0][1] === null || resp[0][2] === null) { this._handleError(cb, "queueNotFound"); @@ -129,7 +140,7 @@ class RedisSMQ extends EventEmitter { } // Make sure to always have correct 6digit millionth seconds from redis const ms: any = this._formatZeroPad(Number(resp[1][1]), 6); - // Create the epoch time in ms from the redis timestamp + // Create the epoch time in ms from the redis timestamp const ts = Number(resp[1][0] + ms.toString(10).slice(0, 3)); const q: any = { @@ -207,6 +218,7 @@ class RedisSMQ extends EventEmitter { ]; this.redis.multi(mc).exec( (err, resp) => { + resp = this._ioRedisMultiToRedisMulti(resp) if (err) { this._handleError(cb, err); return @@ -238,6 +250,7 @@ class RedisSMQ extends EventEmitter { ]; this.redis.multi(mc).exec( (err, resp) => { + resp = this._ioRedisMultiToRedisMulti(resp) if (err) { this._handleError(cb, err); return; } if (resp[0] === 1 && resp[1] > 0) { cb(null, 1) @@ -259,6 +272,7 @@ class RedisSMQ extends EventEmitter { ]; this.redis.multi(mc).exec( (err,resp) => { + resp = this._ioRedisMultiToRedisMulti(resp) if (err) { this._handleError(cb, err); return; } if (resp[0] === 0) { this._handleError(cb, "queueNotFound"); @@ -285,6 +299,7 @@ class RedisSMQ extends EventEmitter { ["zcount", key, resp[0] + "000", "+inf"] ]; this.redis.multi(mc).exec( (err, resp) => { + resp = this._ioRedisMultiToRedisMulti(resp) if (err) { this._handleError(cb, err); return; @@ -530,6 +545,7 @@ class RedisSMQ extends EventEmitter { mc.push(["zcard", key]); } this.redis.multi(mc).exec( (err, resp) => { + resp = this._ioRedisMultiToRedisMulti(resp) if (err) { this._handleError(cb, err); return; @@ -586,9 +602,26 @@ class RedisSMQ extends EventEmitter { } // Helpers + + private _ioRedisMultiToRedisMulti (multiResult) { + if (this.isIoRedis) { + return multiResult.map((r) => { + const err = r[0] + const val = r[1] + if (err) { + throw err + } + return val + }) + } + return multiResult + } + + private _formatZeroPad (num, count) { return ((Math.pow(10, count) + num) + "").substr(1); } + private _handleError = (cb, err, data = {}) => { // try to create a error Object with humanized message diff --git a/index.js b/index.js index 03158e2..592ebf1 100644 --- a/index.js +++ b/index.js @@ -29,6 +29,7 @@ class RedisSMQ extends EventEmitter { ["time"] ]; this.redis.multi(mc).exec((err, resp) => { + resp = this._ioRedisMultiToRedisMulti(resp); if (err) { this._handleError(cb, err); return; @@ -98,6 +99,7 @@ class RedisSMQ extends EventEmitter { ["hsetnx", key, "modified", resp[0]], ]; this.redis.multi(mc).exec((err, resp) => { + resp = this._ioRedisMultiToRedisMulti(resp); if (err) { this._handleError(cb, err); return; @@ -125,6 +127,7 @@ class RedisSMQ extends EventEmitter { ["hdel", `${key}:Q`, `${options.id}`, `${options.id}:rc`, `${options.id}:fr`] ]; this.redis.multi(mc).exec((err, resp) => { + resp = this._ioRedisMultiToRedisMulti(resp); if (err) { this._handleError(cb, err); return; @@ -146,6 +149,7 @@ class RedisSMQ extends EventEmitter { ["srem", `${this.redisns}QUEUES`, options.qname] ]; this.redis.multi(mc).exec((err, resp) => { + resp = this._ioRedisMultiToRedisMulti(resp); if (err) { this._handleError(cb, err); return; @@ -172,6 +176,7 @@ class RedisSMQ extends EventEmitter { ["zcount", key, resp[0] + "000", "+inf"] ]; this.redis.multi(mc).exec((err, resp) => { + resp = this._ioRedisMultiToRedisMulti(resp); if (err) { this._handleError(cb, err); return; @@ -362,6 +367,7 @@ class RedisSMQ extends EventEmitter { mc.push(["zcard", key]); } this.redis.multi(mc).exec((err, resp) => { + resp = this._ioRedisMultiToRedisMulti(resp); if (err) { this._handleError(cb, err); return; @@ -513,13 +519,24 @@ class RedisSMQ extends EventEmitter { opts.options.port = opts.port; this.realtime = opts.realtime; this.redisns = opts.ns + ":"; - if (opts.client && options.client.constructor.name === "RedisClient") { - this.redis = opts.client; + if (opts.client) { + if (opts.client.constructor.name === "Redis") { + this.redis = opts.client; + this.isIoRedis = true; + } + else if (opts.client.constructor.name === "RedisClient") { + this.redis = opts.client; + } } else { this.redis = RedisInst.createClient(opts); } - this.connected = this.redis.connected || false; + if (this.isIoRedis) { + this.connected = this.redis.status === 'ready'; + } + else { + this.connected = this.redis.connected || false; + } if (this.connected) { this.emit("connect"); this.initScript(); @@ -541,6 +558,19 @@ class RedisSMQ extends EventEmitter { }); this._initErrors(); } + _ioRedisMultiToRedisMulti(multiResult) { + if (this.isIoRedis) { + return multiResult.map((r) => { + const err = r[0]; + const val = r[1]; + if (err) { + throw err; + } + return val; + }); + } + return multiResult; + } _formatZeroPad(num, count) { return ((Math.pow(10, count) + num) + "").substr(1); } diff --git a/package.json b/package.json index 2d1e329..195a128 100644 --- a/package.json +++ b/package.json @@ -9,8 +9,9 @@ }, "scripts": { "build": "tsc", + "build:tests": "coffee -c ./", "watch": "tsc -w", - "test": "mocha ./test/test.js" + "test": "mocha ./test/*.js" }, "dependencies": { "@types/redis": "^2.8.0", @@ -20,6 +21,7 @@ "devDependencies": { "async": "^2.6.2", "coffeescript": "^2.4.1", + "ioredis": "^4.14.1", "mocha": "^4.0.1", "should": "^13.1.3", "ts-loader": "^5.4.3", diff --git a/test/ioredis.coffee b/test/ioredis.coffee new file mode 100644 index 0000000..8f377eb --- /dev/null +++ b/test/ioredis.coffee @@ -0,0 +1,682 @@ +_ = require "lodash" +should = require "should" +async = require "async" +RedisSMQ = require "../index" + +Redis = require "ioredis" +redis = new Redis() +redis2 = new Redis() +redissub = new Redis() +redissub.subscribe("rsmq:rt:test1") +Q1LENGTH = 0 +redissub.on "message", (channel, depth) -> + Q1LENGTH = Number(depth) + return + +describe 'Redis-Simple-Message-Queue Test - with ioRedis', -> + rsmq = null + rsmq2 = null + queue1 = + name: "test1" + queue2 = + name: "test2" + queue3 = + name: "test3promises" + m1: "Hello" + m2: "World" + + q1m1 = null + q1m2 = null + q1m3 = null + q2m2 = null + q2msgs = {} + + looong_string = -> + o = "" + while o.length < 66000 + o = o + 'A very long Message...' + return o + + before (done) -> + done() + return + + after (done) -> + console.log("Removing Queues") + # Kill all queues + rsmq.deleteQueue {qname: queue1.name}, (err) -> + return + + rsmq.deleteQueue {qname: queue2.name}, (err) -> + return + @timeout(100) + console.log("Disconnecting Redis") + rsmq.quit() + done() + + return + + it 'get a RedisSMQ instance', (done) -> + rsmq = new RedisSMQ({client: redis, realtime: true}) + rsmq.should.be.an.instanceOf RedisSMQ + done() + return + + it 'use an existing Redis Client', (done) -> + rsmq2 = new RedisSMQ({client: redis2}) + rsmq2.should.be.an.instanceOf RedisSMQ + done() + return + + it 'should delete all leftover queues', (done) -> + rsmq.deleteQueue {qname: queue1.name}, (err) -> + return + + rsmq.deleteQueue {qname: queue2.name}, (err) -> + return + + rsmq.deleteQueue {qname: queue3.name}, (err) -> + return + + setTimeout(done, 100) + return + + describe 'Promise Api', -> + it 'should create a queue', () -> rsmq.createQueueAsync({qname: queue3.name, vt: 0}) + it 'should send a message', () -> rsmq.sendMessageAsync({qname: queue3.name, message: queue3.m1}) + it 'should send another message', () -> rsmq.sendMessageAsync({qname: queue3.name, message: queue3.m2}) + it 'should receive a message', () -> + return rsmq.receiveMessageAsync({qname: queue3.name, vt: 2}).then((resp) -> + resp.message.should.equal(queue3.m1) + return + ) + it 'should receive another message', () -> + return rsmq.receiveMessageAsync({qname: queue3.name, vt: 1}).then((resp) -> + resp.message.should.equal(queue3.m2) + return + ) + it 'Should fail: receive another message - no availabe message', () -> + return rsmq.receiveMessageAsync({qname: queue3.name, vt: 1}).then((resp) -> + should.not.exist(resp.id) + return + ) + it 'wait 1010ms', (done) -> setTimeout(done, 1010) + it 'should receive another message', () -> + return rsmq.receiveMessageAsync({qname: queue3.name, vt: 3}).then((resp) -> + resp.message.should.equal(queue3.m2) + return + ) + it 'wait 1010ms', (done) -> setTimeout(done, 1010) + it 'should receive another message', () -> + return rsmq.receiveMessageAsync({qname: queue3.name, vt: 3}).then((resp) -> + resp.message.should.equal(queue3.m1) + return + ) + it 'should delete the created queue', () -> rsmq.deleteQueueAsync({qname: queue3.name}) + return + + describe 'Queues', -> + + it 'Should fail: Create a new queue with invalid characters in name', (done) -> + rsmq.createQueue {qname:"should throw"}, (err, resp) -> + err.message.should.equal("Invalid qname format") + done() + return + return + it 'Should fail: Create a new queue with name longer 160 chars', (done) -> + rsmq.createQueue {qname:"name01234567890123456789012345678901234567890123456789012345678901234567890123456789name01234567890123456789012345678901234567890123456789012345678901234567890123456789"}, (err, resp) -> + err.message.should.equal("Invalid qname format") + done() + return + return + it 'Should fail: Create a new queue with negative vt', (done) -> + rsmq.createQueue {qname: queue1.name, vt: -20}, (err, resp) -> + err.message.should.equal("vt must be between 0 and 9999999") + done() + return + return + it 'Should fail: Create a new queue with negative vt - using createQueueAsync', () -> + return rsmq.createQueueAsync({qname: queue1.name, vt: -20}).should.be.rejectedWith(Error, { message: "vt must be between 0 and 9999999" }) + + it 'Should fail: Create a new queue with non numeric vt', (done) -> + rsmq.createQueue {qname: queue1.name, vt: "not_a_number"}, (err, resp) -> + err.message.should.equal("vt must be between 0 and 9999999") + done() + return + return + it 'Should fail: Create a new queue with non numeric vt', () -> + return rsmq.createQueueAsync({qname: queue1.name, vt: "not_a_number"}).should.be.rejectedWith(Error, { message: "vt must be between 0 and 9999999" }) + it 'Should fail: Create a new queue with vt too high', (done) -> + rsmq.createQueue {qname: queue1.name, vt: 10000000}, (err, resp) -> + err.message.should.equal("vt must be between 0 and 9999999") + done() + return + return + it 'Should fail: Create a new queue with negative delay', (done) -> + rsmq.createQueue {qname: queue1.name, delay: -20}, (err, resp) -> + err.message.should.equal("delay must be between 0 and 9999999") + done() + return + return + it 'Should fail: Create a new queue with non numeric delay', (done) -> + rsmq.createQueue {qname: queue1.name, delay: "not_a_number"}, (err, resp) -> + err.message.should.equal("delay must be between 0 and 9999999") + done() + return + return + it 'Should fail: Create a new queue with delay too high', (done) -> + rsmq.createQueue {qname: queue1.name, delay: 10000000}, (err, resp) -> + err.message.should.equal("delay must be between 0 and 9999999") + done() + return + return + it 'Should fail: Create a new queue with negative maxsize', (done) -> + rsmq.createQueue {qname: queue1.name, maxsize: -20}, (err, resp) -> + err.message.should.equal("maxsize must be between 1024 and 65536") + done() + return + return + it 'Should fail: Create a new queue with non numeric maxsize', (done) -> + rsmq.createQueue {qname: queue1.name, maxsize: "not_a_number"}, (err, resp) -> + err.message.should.equal("maxsize must be between 1024 and 65536") + done() + return + return + it 'Should fail: Create a new queue with maxsize too high', (done) -> + rsmq.createQueue {qname: queue1.name, maxsize: 66000}, (err, resp) -> + err.message.should.equal("maxsize must be between 1024 and 65536") + done() + return + return + it 'Should fail: Create a new queue with maxsize too low', (done) -> + rsmq.createQueue {qname: queue1.name, maxsize: 900}, (err, resp) -> + err.message.should.equal("maxsize must be between 1024 and 65536") + done() + return + return + it 'Should fail: Create a new queue with maxsize `-2`', (done) -> + rsmq.createQueue {qname: queue1.name, maxsize: -2}, (err, resp) -> + err.message.should.equal("maxsize must be between 1024 and 65536") + done() + return + return + + it 'ListQueues: Should return empty array', (done) -> + rsmq.listQueues (err, resp) -> + should.not.exist(err) + resp.length.should.equal(0) + done() + return + return + + it 'Create a new queue: queue1', (done) -> + rsmq.createQueue {qname: queue1.name}, (err, resp) -> + should.not.exist(err) + resp.should.equal(1) + done() + return + return + + it 'Should fail: Create the same queue again', (done) -> + rsmq.createQueue {qname: queue1.name}, (err, resp) -> + err.message.should.equal("Queue exists") + done() + return + return + + it 'ListQueues: Should return array with one element', (done) -> + rsmq.listQueues (err, resp) -> + should.not.exist(err) + resp.length.should.equal(1) + resp.should.containEql( queue1.name) + done() + return + return + + + it 'Create a new queue: queue2', (done) -> + rsmq.createQueue {qname: queue2.name, maxsize:2048}, (err, resp) -> + should.not.exist(err) + resp.should.equal(1) + done() + return + return + + + it 'ListQueues: Should return array with two elements', (done) -> + rsmq.listQueues (err, resp) -> + should.not.exist(err) + resp.length.should.equal(2) + resp.should.containEql(queue1.name) + resp.should.containEql(queue2.name) + done() + return + return + + it 'Should succeed: GetQueueAttributes of queue 1', (done) -> + rsmq.getQueueAttributes {qname: queue1.name}, (err, resp) -> + should.not.exist(err) + resp.msgs.should.equal(0) + queue1.modified = resp.modified + done() + return + return + + it 'Should fail: GetQueueAttributes of bogus queue', (done) -> + rsmq.getQueueAttributes {qname:"sdfsdfsdf"}, (err, resp) -> + err.message.should.equal("Queue not found") + done() + return + return + + it 'Should fail: setQueueAttributes of bogus queue with no supplied attributes', (done) -> + rsmq.setQueueAttributes {qname:"kjdsfh3h"}, (err, resp) -> + err.message.should.equal("No attribute was supplied") + done() + return + return + + it 'Should fail: setQueueAttributes of bogus queue with supplied attributes', (done) -> + rsmq.setQueueAttributes {qname:"kjdsfh3h",vt: 1000}, (err, resp) -> + err.message.should.equal("Queue not found") + done() + return + return + + it 'setQueueAttributes: Should return the queue with a new vt attribute', (done) -> + rsmq.setQueueAttributes {qname: queue1.name, vt: 1234}, (err, resp) -> + resp.vt.should.equal(1234) + resp.delay.should.equal(0) + resp.maxsize.should.equal(65536) + done() + return + return + + it 'setQueueAttributes: Should return the queue with a new delay attribute', (done) -> + @timeout(2000) + setTimeout -> + rsmq.setQueueAttributes {qname: queue1.name, delay: 7}, (err, resp) -> + resp.vt.should.equal(1234) + resp.delay.should.equal(7) + resp.maxsize.should.equal(65536) + resp.modified.should.be.above(queue1.modified) + done() + return + return + , 1100 + return + + it 'setQueueAttributes: Should return the queue with an umlimited maxsize', (done) -> + rsmq.setQueueAttributes {qname: queue1.name, maxsize: -1}, (err, resp) -> + resp.vt.should.equal(1234) + resp.delay.should.equal(7) + resp.maxsize.should.equal(-1) + done() + return + return + + it 'setQueueAttributes: Should return the queue with a new maxsize attribute', (done) -> + rsmq.setQueueAttributes {qname: queue1.name, maxsize: 2048}, (err, resp) -> + resp.vt.should.equal(1234) + resp.delay.should.equal(7) + resp.maxsize.should.equal(2048) + done() + return + return + + it 'setQueueAttributes: Should return the queue with a new attribute', (done) -> + rsmq.setQueueAttributes {qname: queue1.name, maxsize: 65536, vt: 30, delay: 0}, (err, resp) -> + resp.vt.should.equal(30) + resp.delay.should.equal(0) + resp.maxsize.should.equal(65536) + done() + return + return + + it 'Should fail:setQueueAttributes: Should not accept too small maxsize', (done) -> + rsmq.setQueueAttributes {qname: queue1.name, maxsize: 50}, (err, resp) -> + err.message.should.equal("maxsize must be between 1024 and 65536") + done() + return + return + + it 'Should fail:setQueueAttributes: Should not accept negative value', (done) -> + rsmq.setQueueAttributes {qname: queue1.name, vt: -5}, (err, resp) -> + err.message.should.equal("vt must be between 0 and 9999999") + done() + return + return + + return + + describe 'Messages', -> + it 'Should fail: Send a message to non-existing queue', (done) -> + rsmq.sendMessage {qname:"rtlbrmpft", message:"foo"}, (err, resp) -> + err.message.should.equal("Queue not found") + done() + return + return + it 'Should fail: Send a message without any parameters', (done) -> + rsmq.sendMessage {}, (err, resp) -> + err.message.should.equal("No qname supplied") + done() + return + return + it 'Should fail: Send a message without a message key', (done) -> + rsmq.sendMessage {qname: queue1.name, messXage:"Hello"}, (err, resp) -> + err.message.should.equal("Message must be a string") + done() + return + return + it 'Should fail: Send a message with message being a number', (done) -> + rsmq.sendMessage {qname: queue1.name, message:123}, (err, resp) -> + err.message.should.equal("Message must be a string") + done() + return + return + + # TODO: Try to send a loooong msg + + it 'Send message 1 with existing Redis instance', (done) -> + rsmq2.sendMessage {qname: queue1.name, message:"Hello"}, (err, resp) -> + should.not.exist(err) + q1m1 = + id: resp + message: "Hello" + done() + return + return + + # Send 1000 msgs to q2 so we can delay sending of msg 2 to q1 + + it 'Send 1000 messages to queue2: succeed', (done) -> + pq = [] + for i in [0...1000] + pq.push({qname: queue2.name, message: "test message number:" + i}) + async.map pq, rsmq.sendMessage, (err, resp) -> + for e in resp + q2msgs[e] = 1 + e.length.should.equal(32) + _.keys(q2msgs).length.should.equal(1000) + done() + return + return + + it 'Send message 2', (done) -> + rsmq.sendMessage {qname: queue1.name, message:"World"}, (err, resp) -> + should.not.exist(err) + q1m2 = + id: resp + message: "World" + done() + return + return + + + it 'Receive a message. Should return message 1', (done) -> + rsmq2.receiveMessage {qname: queue1.name}, (err, resp) -> + resp.id.should.equal(q1m1.id) + done() + return + return + + it 'Receive a message. Should return message 2', (done) -> + rsmq.receiveMessage {qname: queue1.name}, (err, resp) -> + resp.id.should.equal(q1m2.id) + done() + return + return + + + it 'Check queue properties. Should have 2 msgs', (done) -> + rsmq.getQueueAttributes {qname: queue1.name}, (err, resp) -> + resp.msgs.should.equal(2) + resp.hiddenmsgs.should.equal(2) + done() + return + return + + it 'Send message 3', (done) -> + rsmq.sendMessage {qname: queue1.name, message:"Booo!!"}, (err, resp) -> + should.not.exist(err) + q1m3= + id: resp + message: "Booo!!" + done() + return + return + + it 'Check queue properties. Should have 3 msgs', (done) -> + rsmq.getQueueAttributes {qname: queue1.name}, (err, resp) -> + resp.msgs.should.equal(3) + resp.totalrecv.should.equal(2) + done() + return + return + + it 'Pop a message. Should return message 3 and delete it', (done) -> + rsmq.popMessage {qname: queue1.name}, (err, resp) -> + resp.id.should.equal(q1m3.id) + done() + return + return + + it 'Check queue properties. Should have 2 msgs', (done) -> + rsmq.getQueueAttributes {qname: queue1.name}, (err, resp) -> + resp.msgs.should.equal(2) + resp.totalrecv.should.equal(3) + done() + return + return + + it 'Pop a message. Should not return a message', (done) -> + rsmq.popMessage {qname: queue1.name}, (err, resp) -> + should.not.exist(resp.id) + done() + return + return + + it 'Should fail. Set the visibility of a non existing message', (done) -> + rsmq.changeMessageVisibility {qname: queue1.name, id:"abcdefghij0123456789abcdefghij01", vt:10}, (err, resp) -> + resp.should.equal(0) + done() + return + return + + it 'Set new visibility timeout of message 2 to 10s', (done) -> + rsmq.changeMessageVisibility {qname: queue1.name, id:q1m2.id, vt: 10}, (err, resp) -> + resp.should.equal(1) + done() + return + return + + it 'Receive a message. Should return nothing', (done) -> + rsmq.receiveMessage {qname: queue1.name}, (err, resp) -> + should.not.exist(resp.id) + done() + return + return + + it 'Set new visibility timeout of message 2 to 0s', (done) -> + rsmq.changeMessageVisibility {qname: queue1.name, id:q1m2.id, vt: 0}, (err, resp) -> + resp.should.equal(1) + done() + return + return + + it 'Receive a message. Should return message 2', (done) -> + rsmq.receiveMessage {qname: queue1.name}, (err, resp) -> + resp.id.should.equal(q1m2.id) + done() + return + return + + it 'Receive a message. Should return nothing', (done) -> + rsmq.receiveMessage {qname: queue1.name}, (err, resp) -> + should.not.exist(resp.id) + done() + return + return + + it 'Should fail: Delete a message without supplying an id', (done) -> + rsmq.deleteMessage {qname: queue1.name}, (err, resp) -> + err.message.should.equal("No id supplied") + done() + return + return + + it 'Should fail: Delete a message with invalid id', (done) -> + rsmq.deleteMessage {qname: queue1.name, id:"sdafsdf"}, (err, resp) -> + err.message.should.equal("Invalid id format") + done() + return + return + + it 'Delete message 1. Should return 1', (done) -> + rsmq.deleteMessage {qname: queue1.name, id: q1m1.id}, (err, resp) -> + resp.should.equal(1) + done() + return + return + + it 'Delete message 1 again. Should return 0', (done) -> + rsmq.deleteMessage {qname: queue1.name, id: q1m1.id}, (err, resp) -> + resp.should.equal(0) + done() + return + return + + it 'Set new visibility timeout of message 1. Should return 0.', (done) -> + rsmq.changeMessageVisibility {qname: queue1.name, id:q1m1.id, vt: 10}, (err, resp) -> + resp.should.equal(0) + done() + return + return + + it 'Should fail: Send a message that is too long', (done) -> + text = JSON.stringify([0..15000]) + rsmq.sendMessage {qname: queue1.name, message:text}, (err, resp) -> + should.not.exist(resp) + err.message.should.equal("Message too long") + done() + return + return + + it 'Receive 1000 messages from queue2 and delete 500 (those where number is even)', (done) -> + pq = [] + # we keep vt = 0 so we can query them again quickly + for i in [0...1000] + pq.push({qname: queue2.name, vt:0}) + async.map pq, rsmq.receiveMessage, (err, resp) -> + dq = [] + for e in resp when not (e.message.split(":")[1] % 2) + dq.push({qname: queue2.name, id:e.id}) + delete q2msgs[e.id] + async.map dq, rsmq.deleteMessage, (err, resp) -> + for e in resp + e.should.equal(1) + done() + return + return + return + + it 'GetQueueAttributes: Should return queue attributes', (done) -> + rsmq.getQueueAttributes {qname: queue2.name}, (err, resp) -> + should.not.exist(err) + resp.msgs.should.equal(500) + done() + return + return + + it 'Receive 500 messages from queue2 and delete them', (done) -> + pq = [] + # we keep vt = 0 so we can query them again quickly + for i in [0...500] + pq.push({qname: queue2.name, vt:0}) + async.map pq, rsmq.receiveMessage, (err, resp) -> + dq = [] + for e in resp when e.message.split(":")[1] % 2 + dq.push({qname: queue2.name, id:e.id}) + delete q2msgs[e.id] + async.map dq, rsmq.deleteMessage, (err, resp) -> + for e in resp + e.should.equal(1) + done() + + # q2msgs should be empty + _.keys(q2msgs).length.should.equal(0) + return + return + return + + it 'Receive a message from queue2. Should return {}', (done) -> + rsmq.receiveMessage {qname: queue2.name}, (err, resp) -> + should.not.exist(resp.id) + done() + return + return + + + it 'GetQueueAttributes: Should return queue attributes', (done) -> + rsmq.getQueueAttributes {qname: queue2.name}, (err, resp) -> + should.not.exist(err) + resp.totalrecv.should.equal(1500) + resp.totalsent.should.equal(1000) + resp.msgs.should.equal(0) + done() + return + return + + it 'setQueueAttributes: Should return the queue2 with an umlimited maxsize', (done) -> + rsmq.setQueueAttributes {qname: queue2.name , delay: 0, vt: 30, maxsize: -1}, (err, resp) -> + resp.vt.should.equal(30) + resp.delay.should.equal(0) + resp.maxsize.should.equal(-1) + done() + return + return + + it 'Send/Recevice a longer than 64k msg to test unlimited functionality', (done) -> + longmsg = looong_string() + rsmq.sendMessage {qname: queue2.name, message: longmsg}, (err, resp1) -> + should.not.exist(err) + rsmq.receiveMessage {qname: queue2.name}, (err, resp2) -> + should.not.exist(err) + resp2.message.should.equal(longmsg) + resp2.id.should.equal(resp1) + done() + return + return + return + return + + describe 'Realtime Pub/Sub notifications', -> + it 'Send another message to queue1', (done) -> + rsmq.sendMessage {qname: queue1.name, message:"Another World"}, (err, resp) -> + should.not.exist(err) + done() + return + return + + it 'wait 100ms', (done) -> setTimeout(done, 100) + + it 'check queue1 length. Should be 2', (done) -> + Q1LENGTH.should.equal(2) + done() + return + + it 'Send another message to queue1', (done) -> + rsmq.sendMessage {qname: queue1.name, message:"Another World"}, (err, resp) -> + should.not.exist(err) + done() + return + return + + it 'wait 100ms', (done) -> setTimeout(done, 100) + + it 'check queue1 length. Should be 3', (done) -> + Q1LENGTH.should.equal(3) + done() + return + return + return diff --git a/test/ioredis.js b/test/ioredis.js new file mode 100644 index 0000000..c4e414f --- /dev/null +++ b/test/ioredis.js @@ -0,0 +1,905 @@ +// Generated by CoffeeScript 2.4.1 +(function() { + var Q1LENGTH, Redis, RedisSMQ, _, async, redis, redis2, redissub, should; + + _ = require("lodash"); + + should = require("should"); + + async = require("async"); + + RedisSMQ = require("../index"); + + Redis = require("ioredis"); + + redis = new Redis(); + + redis2 = new Redis(); + + redissub = new Redis(); + + redissub.subscribe("rsmq:rt:test1"); + + Q1LENGTH = 0; + + redissub.on("message", function(channel, depth) { + Q1LENGTH = Number(depth); + }); + + describe('Redis-Simple-Message-Queue Test - with ioRedis', function() { + var looong_string, q1m1, q1m2, q1m3, q2m2, q2msgs, queue1, queue2, queue3, rsmq, rsmq2; + rsmq = null; + rsmq2 = null; + queue1 = { + name: "test1" + }; + queue2 = { + name: "test2" + }; + queue3 = { + name: "test3promises", + m1: "Hello", + m2: "World" + }; + q1m1 = null; + q1m2 = null; + q1m3 = null; + q2m2 = null; + q2msgs = {}; + looong_string = function() { + var o; + o = ""; + while (o.length < 66000) { + o = o + 'A very long Message...'; + } + return o; + }; + before(function(done) { + done(); + }); + after(function(done) { + console.log("Removing Queues"); + // Kill all queues + rsmq.deleteQueue({ + qname: queue1.name + }, function(err) {}); + rsmq.deleteQueue({ + qname: queue2.name + }, function(err) {}); + this.timeout(100); + console.log("Disconnecting Redis"); + rsmq.quit(); + done(); + }); + it('get a RedisSMQ instance', function(done) { + rsmq = new RedisSMQ({ + client: redis, + realtime: true + }); + rsmq.should.be.an.instanceOf(RedisSMQ); + done(); + }); + it('use an existing Redis Client', function(done) { + rsmq2 = new RedisSMQ({ + client: redis2 + }); + rsmq2.should.be.an.instanceOf(RedisSMQ); + done(); + }); + it('should delete all leftover queues', function(done) { + rsmq.deleteQueue({ + qname: queue1.name + }, function(err) {}); + rsmq.deleteQueue({ + qname: queue2.name + }, function(err) {}); + rsmq.deleteQueue({ + qname: queue3.name + }, function(err) {}); + setTimeout(done, 100); + }); + describe('Promise Api', function() { + it('should create a queue', function() { + return rsmq.createQueueAsync({ + qname: queue3.name, + vt: 0 + }); + }); + it('should send a message', function() { + return rsmq.sendMessageAsync({ + qname: queue3.name, + message: queue3.m1 + }); + }); + it('should send another message', function() { + return rsmq.sendMessageAsync({ + qname: queue3.name, + message: queue3.m2 + }); + }); + it('should receive a message', function() { + return rsmq.receiveMessageAsync({ + qname: queue3.name, + vt: 2 + }).then(function(resp) { + resp.message.should.equal(queue3.m1); + }); + }); + it('should receive another message', function() { + return rsmq.receiveMessageAsync({ + qname: queue3.name, + vt: 1 + }).then(function(resp) { + resp.message.should.equal(queue3.m2); + }); + }); + it('Should fail: receive another message - no availabe message', function() { + return rsmq.receiveMessageAsync({ + qname: queue3.name, + vt: 1 + }).then(function(resp) { + should.not.exist(resp.id); + }); + }); + it('wait 1010ms', function(done) { + return setTimeout(done, 1010); + }); + it('should receive another message', function() { + return rsmq.receiveMessageAsync({ + qname: queue3.name, + vt: 3 + }).then(function(resp) { + resp.message.should.equal(queue3.m2); + }); + }); + it('wait 1010ms', function(done) { + return setTimeout(done, 1010); + }); + it('should receive another message', function() { + return rsmq.receiveMessageAsync({ + qname: queue3.name, + vt: 3 + }).then(function(resp) { + resp.message.should.equal(queue3.m1); + }); + }); + it('should delete the created queue', function() { + return rsmq.deleteQueueAsync({ + qname: queue3.name + }); + }); + }); + describe('Queues', function() { + it('Should fail: Create a new queue with invalid characters in name', function(done) { + rsmq.createQueue({ + qname: "should throw" + }, function(err, resp) { + err.message.should.equal("Invalid qname format"); + done(); + }); + }); + it('Should fail: Create a new queue with name longer 160 chars', function(done) { + rsmq.createQueue({ + qname: "name01234567890123456789012345678901234567890123456789012345678901234567890123456789name01234567890123456789012345678901234567890123456789012345678901234567890123456789" + }, function(err, resp) { + err.message.should.equal("Invalid qname format"); + done(); + }); + }); + it('Should fail: Create a new queue with negative vt', function(done) { + rsmq.createQueue({ + qname: queue1.name, + vt: -20 + }, function(err, resp) { + err.message.should.equal("vt must be between 0 and 9999999"); + done(); + }); + }); + it('Should fail: Create a new queue with negative vt - using createQueueAsync', function() { + return rsmq.createQueueAsync({ + qname: queue1.name, + vt: -20 + }).should.be.rejectedWith(Error, { + message: "vt must be between 0 and 9999999" + }); + }); + it('Should fail: Create a new queue with non numeric vt', function(done) { + rsmq.createQueue({ + qname: queue1.name, + vt: "not_a_number" + }, function(err, resp) { + err.message.should.equal("vt must be between 0 and 9999999"); + done(); + }); + }); + it('Should fail: Create a new queue with non numeric vt', function() { + return rsmq.createQueueAsync({ + qname: queue1.name, + vt: "not_a_number" + }).should.be.rejectedWith(Error, { + message: "vt must be between 0 and 9999999" + }); + }); + it('Should fail: Create a new queue with vt too high', function(done) { + rsmq.createQueue({ + qname: queue1.name, + vt: 10000000 + }, function(err, resp) { + err.message.should.equal("vt must be between 0 and 9999999"); + done(); + }); + }); + it('Should fail: Create a new queue with negative delay', function(done) { + rsmq.createQueue({ + qname: queue1.name, + delay: -20 + }, function(err, resp) { + err.message.should.equal("delay must be between 0 and 9999999"); + done(); + }); + }); + it('Should fail: Create a new queue with non numeric delay', function(done) { + rsmq.createQueue({ + qname: queue1.name, + delay: "not_a_number" + }, function(err, resp) { + err.message.should.equal("delay must be between 0 and 9999999"); + done(); + }); + }); + it('Should fail: Create a new queue with delay too high', function(done) { + rsmq.createQueue({ + qname: queue1.name, + delay: 10000000 + }, function(err, resp) { + err.message.should.equal("delay must be between 0 and 9999999"); + done(); + }); + }); + it('Should fail: Create a new queue with negative maxsize', function(done) { + rsmq.createQueue({ + qname: queue1.name, + maxsize: -20 + }, function(err, resp) { + err.message.should.equal("maxsize must be between 1024 and 65536"); + done(); + }); + }); + it('Should fail: Create a new queue with non numeric maxsize', function(done) { + rsmq.createQueue({ + qname: queue1.name, + maxsize: "not_a_number" + }, function(err, resp) { + err.message.should.equal("maxsize must be between 1024 and 65536"); + done(); + }); + }); + it('Should fail: Create a new queue with maxsize too high', function(done) { + rsmq.createQueue({ + qname: queue1.name, + maxsize: 66000 + }, function(err, resp) { + err.message.should.equal("maxsize must be between 1024 and 65536"); + done(); + }); + }); + it('Should fail: Create a new queue with maxsize too low', function(done) { + rsmq.createQueue({ + qname: queue1.name, + maxsize: 900 + }, function(err, resp) { + err.message.should.equal("maxsize must be between 1024 and 65536"); + done(); + }); + }); + it('Should fail: Create a new queue with maxsize `-2`', function(done) { + rsmq.createQueue({ + qname: queue1.name, + maxsize: -2 + }, function(err, resp) { + err.message.should.equal("maxsize must be between 1024 and 65536"); + done(); + }); + }); + it('ListQueues: Should return empty array', function(done) { + rsmq.listQueues(function(err, resp) { + should.not.exist(err); + resp.length.should.equal(0); + done(); + }); + }); + it('Create a new queue: queue1', function(done) { + rsmq.createQueue({ + qname: queue1.name + }, function(err, resp) { + should.not.exist(err); + resp.should.equal(1); + done(); + }); + }); + it('Should fail: Create the same queue again', function(done) { + rsmq.createQueue({ + qname: queue1.name + }, function(err, resp) { + err.message.should.equal("Queue exists"); + done(); + }); + }); + it('ListQueues: Should return array with one element', function(done) { + rsmq.listQueues(function(err, resp) { + should.not.exist(err); + resp.length.should.equal(1); + resp.should.containEql(queue1.name); + done(); + }); + }); + it('Create a new queue: queue2', function(done) { + rsmq.createQueue({ + qname: queue2.name, + maxsize: 2048 + }, function(err, resp) { + should.not.exist(err); + resp.should.equal(1); + done(); + }); + }); + it('ListQueues: Should return array with two elements', function(done) { + rsmq.listQueues(function(err, resp) { + should.not.exist(err); + resp.length.should.equal(2); + resp.should.containEql(queue1.name); + resp.should.containEql(queue2.name); + done(); + }); + }); + it('Should succeed: GetQueueAttributes of queue 1', function(done) { + rsmq.getQueueAttributes({ + qname: queue1.name + }, function(err, resp) { + should.not.exist(err); + resp.msgs.should.equal(0); + queue1.modified = resp.modified; + done(); + }); + }); + it('Should fail: GetQueueAttributes of bogus queue', function(done) { + rsmq.getQueueAttributes({ + qname: "sdfsdfsdf" + }, function(err, resp) { + err.message.should.equal("Queue not found"); + done(); + }); + }); + it('Should fail: setQueueAttributes of bogus queue with no supplied attributes', function(done) { + rsmq.setQueueAttributes({ + qname: "kjdsfh3h" + }, function(err, resp) { + err.message.should.equal("No attribute was supplied"); + done(); + }); + }); + it('Should fail: setQueueAttributes of bogus queue with supplied attributes', function(done) { + rsmq.setQueueAttributes({ + qname: "kjdsfh3h", + vt: 1000 + }, function(err, resp) { + err.message.should.equal("Queue not found"); + done(); + }); + }); + it('setQueueAttributes: Should return the queue with a new vt attribute', function(done) { + rsmq.setQueueAttributes({ + qname: queue1.name, + vt: 1234 + }, function(err, resp) { + resp.vt.should.equal(1234); + resp.delay.should.equal(0); + resp.maxsize.should.equal(65536); + done(); + }); + }); + it('setQueueAttributes: Should return the queue with a new delay attribute', function(done) { + this.timeout(2000); + setTimeout(function() { + rsmq.setQueueAttributes({ + qname: queue1.name, + delay: 7 + }, function(err, resp) { + resp.vt.should.equal(1234); + resp.delay.should.equal(7); + resp.maxsize.should.equal(65536); + resp.modified.should.be.above(queue1.modified); + done(); + }); + }, 1100); + }); + it('setQueueAttributes: Should return the queue with an umlimited maxsize', function(done) { + rsmq.setQueueAttributes({ + qname: queue1.name, + maxsize: -1 + }, function(err, resp) { + resp.vt.should.equal(1234); + resp.delay.should.equal(7); + resp.maxsize.should.equal(-1); + done(); + }); + }); + it('setQueueAttributes: Should return the queue with a new maxsize attribute', function(done) { + rsmq.setQueueAttributes({ + qname: queue1.name, + maxsize: 2048 + }, function(err, resp) { + resp.vt.should.equal(1234); + resp.delay.should.equal(7); + resp.maxsize.should.equal(2048); + done(); + }); + }); + it('setQueueAttributes: Should return the queue with a new attribute', function(done) { + rsmq.setQueueAttributes({ + qname: queue1.name, + maxsize: 65536, + vt: 30, + delay: 0 + }, function(err, resp) { + resp.vt.should.equal(30); + resp.delay.should.equal(0); + resp.maxsize.should.equal(65536); + done(); + }); + }); + it('Should fail:setQueueAttributes: Should not accept too small maxsize', function(done) { + rsmq.setQueueAttributes({ + qname: queue1.name, + maxsize: 50 + }, function(err, resp) { + err.message.should.equal("maxsize must be between 1024 and 65536"); + done(); + }); + }); + it('Should fail:setQueueAttributes: Should not accept negative value', function(done) { + rsmq.setQueueAttributes({ + qname: queue1.name, + vt: -5 + }, function(err, resp) { + err.message.should.equal("vt must be between 0 and 9999999"); + done(); + }); + }); + }); + describe('Messages', function() { + it('Should fail: Send a message to non-existing queue', function(done) { + rsmq.sendMessage({ + qname: "rtlbrmpft", + message: "foo" + }, function(err, resp) { + err.message.should.equal("Queue not found"); + done(); + }); + }); + it('Should fail: Send a message without any parameters', function(done) { + rsmq.sendMessage({}, function(err, resp) { + err.message.should.equal("No qname supplied"); + done(); + }); + }); + it('Should fail: Send a message without a message key', function(done) { + rsmq.sendMessage({ + qname: queue1.name, + messXage: "Hello" + }, function(err, resp) { + err.message.should.equal("Message must be a string"); + done(); + }); + }); + it('Should fail: Send a message with message being a number', function(done) { + rsmq.sendMessage({ + qname: queue1.name, + message: 123 + }, function(err, resp) { + err.message.should.equal("Message must be a string"); + done(); + }); + }); + // TODO: Try to send a loooong msg + it('Send message 1 with existing Redis instance', function(done) { + rsmq2.sendMessage({ + qname: queue1.name, + message: "Hello" + }, function(err, resp) { + should.not.exist(err); + q1m1 = { + id: resp, + message: "Hello" + }; + done(); + }); + }); + // Send 1000 msgs to q2 so we can delay sending of msg 2 to q1 + it('Send 1000 messages to queue2: succeed', function(done) { + var i, j, pq; + pq = []; + for (i = j = 0; j < 1000; i = ++j) { + pq.push({ + qname: queue2.name, + message: "test message number:" + i + }); + } + async.map(pq, rsmq.sendMessage, function(err, resp) { + var e, k, len; + for (k = 0, len = resp.length; k < len; k++) { + e = resp[k]; + q2msgs[e] = 1; + e.length.should.equal(32); + } + _.keys(q2msgs).length.should.equal(1000); + done(); + }); + }); + it('Send message 2', function(done) { + rsmq.sendMessage({ + qname: queue1.name, + message: "World" + }, function(err, resp) { + should.not.exist(err); + q1m2 = { + id: resp, + message: "World" + }; + done(); + }); + }); + it('Receive a message. Should return message 1', function(done) { + rsmq2.receiveMessage({ + qname: queue1.name + }, function(err, resp) { + resp.id.should.equal(q1m1.id); + done(); + }); + }); + it('Receive a message. Should return message 2', function(done) { + rsmq.receiveMessage({ + qname: queue1.name + }, function(err, resp) { + resp.id.should.equal(q1m2.id); + done(); + }); + }); + it('Check queue properties. Should have 2 msgs', function(done) { + rsmq.getQueueAttributes({ + qname: queue1.name + }, function(err, resp) { + resp.msgs.should.equal(2); + resp.hiddenmsgs.should.equal(2); + done(); + }); + }); + it('Send message 3', function(done) { + rsmq.sendMessage({ + qname: queue1.name, + message: "Booo!!" + }, function(err, resp) { + should.not.exist(err); + q1m3 = { + id: resp, + message: "Booo!!" + }; + done(); + }); + }); + it('Check queue properties. Should have 3 msgs', function(done) { + rsmq.getQueueAttributes({ + qname: queue1.name + }, function(err, resp) { + resp.msgs.should.equal(3); + resp.totalrecv.should.equal(2); + done(); + }); + }); + it('Pop a message. Should return message 3 and delete it', function(done) { + rsmq.popMessage({ + qname: queue1.name + }, function(err, resp) { + resp.id.should.equal(q1m3.id); + done(); + }); + }); + it('Check queue properties. Should have 2 msgs', function(done) { + rsmq.getQueueAttributes({ + qname: queue1.name + }, function(err, resp) { + resp.msgs.should.equal(2); + resp.totalrecv.should.equal(3); + done(); + }); + }); + it('Pop a message. Should not return a message', function(done) { + rsmq.popMessage({ + qname: queue1.name + }, function(err, resp) { + should.not.exist(resp.id); + done(); + }); + }); + it('Should fail. Set the visibility of a non existing message', function(done) { + rsmq.changeMessageVisibility({ + qname: queue1.name, + id: "abcdefghij0123456789abcdefghij01", + vt: 10 + }, function(err, resp) { + resp.should.equal(0); + done(); + }); + }); + it('Set new visibility timeout of message 2 to 10s', function(done) { + rsmq.changeMessageVisibility({ + qname: queue1.name, + id: q1m2.id, + vt: 10 + }, function(err, resp) { + resp.should.equal(1); + done(); + }); + }); + it('Receive a message. Should return nothing', function(done) { + rsmq.receiveMessage({ + qname: queue1.name + }, function(err, resp) { + should.not.exist(resp.id); + done(); + }); + }); + it('Set new visibility timeout of message 2 to 0s', function(done) { + rsmq.changeMessageVisibility({ + qname: queue1.name, + id: q1m2.id, + vt: 0 + }, function(err, resp) { + resp.should.equal(1); + done(); + }); + }); + it('Receive a message. Should return message 2', function(done) { + rsmq.receiveMessage({ + qname: queue1.name + }, function(err, resp) { + resp.id.should.equal(q1m2.id); + done(); + }); + }); + it('Receive a message. Should return nothing', function(done) { + rsmq.receiveMessage({ + qname: queue1.name + }, function(err, resp) { + should.not.exist(resp.id); + done(); + }); + }); + it('Should fail: Delete a message without supplying an id', function(done) { + rsmq.deleteMessage({ + qname: queue1.name + }, function(err, resp) { + err.message.should.equal("No id supplied"); + done(); + }); + }); + it('Should fail: Delete a message with invalid id', function(done) { + rsmq.deleteMessage({ + qname: queue1.name, + id: "sdafsdf" + }, function(err, resp) { + err.message.should.equal("Invalid id format"); + done(); + }); + }); + it('Delete message 1. Should return 1', function(done) { + rsmq.deleteMessage({ + qname: queue1.name, + id: q1m1.id + }, function(err, resp) { + resp.should.equal(1); + done(); + }); + }); + it('Delete message 1 again. Should return 0', function(done) { + rsmq.deleteMessage({ + qname: queue1.name, + id: q1m1.id + }, function(err, resp) { + resp.should.equal(0); + done(); + }); + }); + it('Set new visibility timeout of message 1. Should return 0.', function(done) { + rsmq.changeMessageVisibility({ + qname: queue1.name, + id: q1m1.id, + vt: 10 + }, function(err, resp) { + resp.should.equal(0); + done(); + }); + }); + it('Should fail: Send a message that is too long', function(done) { + var text; + text = JSON.stringify((function() { + var results = []; + for (var j = 0; j <= 15000; j++){ results.push(j); } + return results; + }).apply(this)); + rsmq.sendMessage({ + qname: queue1.name, + message: text + }, function(err, resp) { + should.not.exist(resp); + err.message.should.equal("Message too long"); + done(); + }); + }); + it('Receive 1000 messages from queue2 and delete 500 (those where number is even)', function(done) { + var i, j, pq; + pq = []; +// we keep vt = 0 so we can query them again quickly + for (i = j = 0; j < 1000; i = ++j) { + pq.push({ + qname: queue2.name, + vt: 0 + }); + } + async.map(pq, rsmq.receiveMessage, function(err, resp) { + var dq, e, k, len; + dq = []; + for (k = 0, len = resp.length; k < len; k++) { + e = resp[k]; + if (!(!(e.message.split(":")[1] % 2))) { + continue; + } + dq.push({ + qname: queue2.name, + id: e.id + }); + delete q2msgs[e.id]; + } + async.map(dq, rsmq.deleteMessage, function(err, resp) { + var l, len1; + for (l = 0, len1 = resp.length; l < len1; l++) { + e = resp[l]; + e.should.equal(1); + } + done(); + }); + }); + }); + it('GetQueueAttributes: Should return queue attributes', function(done) { + rsmq.getQueueAttributes({ + qname: queue2.name + }, function(err, resp) { + should.not.exist(err); + resp.msgs.should.equal(500); + done(); + }); + }); + it('Receive 500 messages from queue2 and delete them', function(done) { + var i, j, pq; + pq = []; +// we keep vt = 0 so we can query them again quickly + for (i = j = 0; j < 500; i = ++j) { + pq.push({ + qname: queue2.name, + vt: 0 + }); + } + async.map(pq, rsmq.receiveMessage, function(err, resp) { + var dq, e, k, len; + dq = []; + for (k = 0, len = resp.length; k < len; k++) { + e = resp[k]; + if (!(e.message.split(":")[1] % 2)) { + continue; + } + dq.push({ + qname: queue2.name, + id: e.id + }); + delete q2msgs[e.id]; + } + async.map(dq, rsmq.deleteMessage, function(err, resp) { + var l, len1; + for (l = 0, len1 = resp.length; l < len1; l++) { + e = resp[l]; + e.should.equal(1); + } + done(); + // q2msgs should be empty + _.keys(q2msgs).length.should.equal(0); + }); + }); + }); + it('Receive a message from queue2. Should return {}', function(done) { + rsmq.receiveMessage({ + qname: queue2.name + }, function(err, resp) { + should.not.exist(resp.id); + done(); + }); + }); + it('GetQueueAttributes: Should return queue attributes', function(done) { + rsmq.getQueueAttributes({ + qname: queue2.name + }, function(err, resp) { + should.not.exist(err); + resp.totalrecv.should.equal(1500); + resp.totalsent.should.equal(1000); + resp.msgs.should.equal(0); + done(); + }); + }); + it('setQueueAttributes: Should return the queue2 with an umlimited maxsize', function(done) { + rsmq.setQueueAttributes({ + qname: queue2.name, + delay: 0, + vt: 30, + maxsize: -1 + }, function(err, resp) { + resp.vt.should.equal(30); + resp.delay.should.equal(0); + resp.maxsize.should.equal(-1); + done(); + }); + }); + it('Send/Recevice a longer than 64k msg to test unlimited functionality', function(done) { + var longmsg; + longmsg = looong_string(); + rsmq.sendMessage({ + qname: queue2.name, + message: longmsg + }, function(err, resp1) { + should.not.exist(err); + rsmq.receiveMessage({ + qname: queue2.name + }, function(err, resp2) { + should.not.exist(err); + resp2.message.should.equal(longmsg); + resp2.id.should.equal(resp1); + done(); + }); + }); + }); + }); + describe('Realtime Pub/Sub notifications', function() { + it('Send another message to queue1', function(done) { + rsmq.sendMessage({ + qname: queue1.name, + message: "Another World" + }, function(err, resp) { + should.not.exist(err); + done(); + }); + }); + it('wait 100ms', function(done) { + return setTimeout(done, 100); + }); + it('check queue1 length. Should be 2', function(done) { + Q1LENGTH.should.equal(2); + done(); + }); + it('Send another message to queue1', function(done) { + rsmq.sendMessage({ + qname: queue1.name, + message: "Another World" + }, function(err, resp) { + should.not.exist(err); + done(); + }); + }); + it('wait 100ms', function(done) { + return setTimeout(done, 100); + }); + it('check queue1 length. Should be 3', function(done) { + Q1LENGTH.should.equal(3); + done(); + }); + }); + }); + +}).call(this); diff --git a/test/test.js b/test/test.js index 39d3cb2..55e1215 100644 --- a/test/test.js +++ b/test/test.js @@ -1,899 +1,902 @@ // Generated by CoffeeScript 2.4.1 -var Q1LENGTH, RedisInst, RedisSMQ, _, async, redis, redissub, should; +(function() { + var Q1LENGTH, RedisInst, RedisSMQ, _, async, redis, redissub, should; -_ = require("lodash"); + _ = require("lodash"); -should = require("should"); + should = require("should"); -async = require("async"); + async = require("async"); -RedisSMQ = require("../index"); + RedisSMQ = require("../index"); -RedisInst = require("redis"); + RedisInst = require("redis"); -redis = RedisInst.createClient(); + redis = RedisInst.createClient(); -redissub = RedisInst.createClient(); + redissub = RedisInst.createClient(); -redissub.subscribe("rsmq:rt:test1"); + redissub.subscribe("rsmq:rt:test1"); -Q1LENGTH = 0; + Q1LENGTH = 0; -redissub.on("message", function(channel, depth) { - Q1LENGTH = Number(depth); -}); - -describe('Redis-Simple-Message-Queue Test', function() { - var looong_string, q1m1, q1m2, q1m3, q2m2, q2msgs, queue1, queue2, queue3, rsmq, rsmq2; - rsmq = null; - rsmq2 = null; - queue1 = { - name: "test1" - }; - queue2 = { - name: "test2" - }; - queue3 = { - name: "test3promises", - m1: "Hello", - m2: "World" - }; - q1m1 = null; - q1m2 = null; - q1m3 = null; - q2m2 = null; - q2msgs = {}; - looong_string = function() { - var o; - o = ""; - while (o.length < 66000) { - o = o + 'A very long Message...'; - } - return o; - }; - before(function(done) { - done(); - }); - after(function(done) { - console.log("Removing Queues"); - // Kill all queues - rsmq.deleteQueue({ - qname: queue1.name - }, function(err) {}); - rsmq.deleteQueue({ - qname: queue2.name - }, function(err) {}); - this.timeout(100); - console.log("Disconnecting Redis"); - rsmq.quit(); - done(); + redissub.on("message", function(channel, depth) { + Q1LENGTH = Number(depth); }); - it('get a RedisSMQ instance', function(done) { - rsmq = new RedisSMQ({ - realtime: true + + describe('Redis-Simple-Message-Queue Test', function() { + var looong_string, q1m1, q1m2, q1m3, q2m2, q2msgs, queue1, queue2, queue3, rsmq, rsmq2; + rsmq = null; + rsmq2 = null; + queue1 = { + name: "test1" + }; + queue2 = { + name: "test2" + }; + queue3 = { + name: "test3promises", + m1: "Hello", + m2: "World" + }; + q1m1 = null; + q1m2 = null; + q1m3 = null; + q2m2 = null; + q2msgs = {}; + looong_string = function() { + var o; + o = ""; + while (o.length < 66000) { + o = o + 'A very long Message...'; + } + return o; + }; + before(function(done) { + done(); }); - rsmq.should.be.an.instanceOf(RedisSMQ); - done(); - }); - it('use an existing Redis Client', function(done) { - rsmq2 = new RedisSMQ({ - client: redis + after(function(done) { + console.log("Removing Queues"); + // Kill all queues + rsmq.deleteQueue({ + qname: queue1.name + }, function(err) {}); + rsmq.deleteQueue({ + qname: queue2.name + }, function(err) {}); + this.timeout(100); + console.log("Disconnecting Redis"); + rsmq.quit(); + done(); }); - rsmq2.should.be.an.instanceOf(RedisSMQ); - done(); - }); - it('should delete all leftover queues', function(done) { - rsmq.deleteQueue({ - qname: queue1.name - }, function(err) {}); - rsmq.deleteQueue({ - qname: queue2.name - }, function(err) {}); - rsmq.deleteQueue({ - qname: queue3.name - }, function(err) {}); - setTimeout(done, 100); - }); - describe('Promise Api', function() { - it('should create a queue', function() { - return rsmq.createQueueAsync({ - qname: queue3.name, - vt: 0 + it('get a RedisSMQ instance', function(done) { + rsmq = new RedisSMQ({ + realtime: true }); + rsmq.should.be.an.instanceOf(RedisSMQ); + done(); }); - it('should send a message', function() { - return rsmq.sendMessageAsync({ - qname: queue3.name, - message: queue3.m1 + it('use an existing Redis Client', function(done) { + rsmq2 = new RedisSMQ({ + client: redis }); + rsmq2.should.be.an.instanceOf(RedisSMQ); + done(); }); - it('should send another message', function() { - return rsmq.sendMessageAsync({ - qname: queue3.name, - message: queue3.m2 - }); + it('should delete all leftover queues', function(done) { + rsmq.deleteQueue({ + qname: queue1.name + }, function(err) {}); + rsmq.deleteQueue({ + qname: queue2.name + }, function(err) {}); + rsmq.deleteQueue({ + qname: queue3.name + }, function(err) {}); + setTimeout(done, 100); }); - it('should receive a message', function() { - return rsmq.receiveMessageAsync({ - qname: queue3.name, - vt: 2 - }).then(function(resp) { - resp.message.should.equal(queue3.m1); + describe('Promise Api', function() { + it('should create a queue', function() { + return rsmq.createQueueAsync({ + qname: queue3.name, + vt: 0 + }); }); - }); - it('should receive another message', function() { - return rsmq.receiveMessageAsync({ - qname: queue3.name, - vt: 1 - }).then(function(resp) { - resp.message.should.equal(queue3.m2); + it('should send a message', function() { + return rsmq.sendMessageAsync({ + qname: queue3.name, + message: queue3.m1 + }); }); - }); - it('Should fail: receive another message - no availabe message', function() { - return rsmq.receiveMessageAsync({ - qname: queue3.name, - vt: 1 - }).then(function(resp) { - should.not.exist(resp.id); + it('should send another message', function() { + return rsmq.sendMessageAsync({ + qname: queue3.name, + message: queue3.m2 + }); }); - }); - it('wait 1010ms', function(done) { - return setTimeout(done, 1010); - }); - it('should receive another message', function() { - return rsmq.receiveMessageAsync({ - qname: queue3.name, - vt: 3 - }).then(function(resp) { - resp.message.should.equal(queue3.m2); + it('should receive a message', function() { + return rsmq.receiveMessageAsync({ + qname: queue3.name, + vt: 2 + }).then(function(resp) { + resp.message.should.equal(queue3.m1); + }); }); - }); - it('wait 1010ms', function(done) { - return setTimeout(done, 1010); - }); - it('should receive another message', function() { - return rsmq.receiveMessageAsync({ - qname: queue3.name, - vt: 3 - }).then(function(resp) { - resp.message.should.equal(queue3.m1); + it('should receive another message', function() { + return rsmq.receiveMessageAsync({ + qname: queue3.name, + vt: 1 + }).then(function(resp) { + resp.message.should.equal(queue3.m2); + }); }); - }); - it('should delete the created queue', function() { - return rsmq.deleteQueueAsync({ - qname: queue3.name + it('Should fail: receive another message - no availabe message', function() { + return rsmq.receiveMessageAsync({ + qname: queue3.name, + vt: 1 + }).then(function(resp) { + should.not.exist(resp.id); + }); }); - }); - }); - describe('Queues', function() { - it('Should fail: Create a new queue with invalid characters in name', function(done) { - rsmq.createQueue({ - qname: "should throw" - }, function(err, resp) { - err.message.should.equal("Invalid qname format"); - done(); + it('wait 1010ms', function(done) { + return setTimeout(done, 1010); }); - }); - it('Should fail: Create a new queue with name longer 160 chars', function(done) { - rsmq.createQueue({ - qname: "name01234567890123456789012345678901234567890123456789012345678901234567890123456789name01234567890123456789012345678901234567890123456789012345678901234567890123456789" - }, function(err, resp) { - err.message.should.equal("Invalid qname format"); - done(); + it('should receive another message', function() { + return rsmq.receiveMessageAsync({ + qname: queue3.name, + vt: 3 + }).then(function(resp) { + resp.message.should.equal(queue3.m2); + }); }); - }); - it('Should fail: Create a new queue with negative vt', function(done) { - rsmq.createQueue({ - qname: queue1.name, - vt: -20 - }, function(err, resp) { - err.message.should.equal("vt must be between 0 and 9999999"); - done(); + it('wait 1010ms', function(done) { + return setTimeout(done, 1010); }); - }); - it('Should fail: Create a new queue with negative vt - using createQueueAsync', function() { - return rsmq.createQueueAsync({ - qname: queue1.name, - vt: -20 - }).should.be.rejectedWith(Error, { - message: "vt must be between 0 and 9999999" + it('should receive another message', function() { + return rsmq.receiveMessageAsync({ + qname: queue3.name, + vt: 3 + }).then(function(resp) { + resp.message.should.equal(queue3.m1); + }); }); - }); - it('Should fail: Create a new queue with non numeric vt', function(done) { - rsmq.createQueue({ - qname: queue1.name, - vt: "not_a_number" - }, function(err, resp) { - err.message.should.equal("vt must be between 0 and 9999999"); - done(); + it('should delete the created queue', function() { + return rsmq.deleteQueueAsync({ + qname: queue3.name + }); }); }); - it('Should fail: Create a new queue with non numeric vt', function() { - return rsmq.createQueueAsync({ - qname: queue1.name, - vt: "not_a_number" - }).should.be.rejectedWith(Error, { - message: "vt must be between 0 and 9999999" + describe('Queues', function() { + it('Should fail: Create a new queue with invalid characters in name', function(done) { + rsmq.createQueue({ + qname: "should throw" + }, function(err, resp) { + err.message.should.equal("Invalid qname format"); + done(); + }); }); - }); - it('Should fail: Create a new queue with vt too high', function(done) { - rsmq.createQueue({ - qname: queue1.name, - vt: 10000000 - }, function(err, resp) { - err.message.should.equal("vt must be between 0 and 9999999"); - done(); + it('Should fail: Create a new queue with name longer 160 chars', function(done) { + rsmq.createQueue({ + qname: "name01234567890123456789012345678901234567890123456789012345678901234567890123456789name01234567890123456789012345678901234567890123456789012345678901234567890123456789" + }, function(err, resp) { + err.message.should.equal("Invalid qname format"); + done(); + }); }); - }); - it('Should fail: Create a new queue with negative delay', function(done) { - rsmq.createQueue({ - qname: queue1.name, - delay: -20 - }, function(err, resp) { - err.message.should.equal("delay must be between 0 and 9999999"); - done(); + it('Should fail: Create a new queue with negative vt', function(done) { + rsmq.createQueue({ + qname: queue1.name, + vt: -20 + }, function(err, resp) { + err.message.should.equal("vt must be between 0 and 9999999"); + done(); + }); }); - }); - it('Should fail: Create a new queue with non numeric delay', function(done) { - rsmq.createQueue({ - qname: queue1.name, - delay: "not_a_number" - }, function(err, resp) { - err.message.should.equal("delay must be between 0 and 9999999"); - done(); + it('Should fail: Create a new queue with negative vt - using createQueueAsync', function() { + return rsmq.createQueueAsync({ + qname: queue1.name, + vt: -20 + }).should.be.rejectedWith(Error, { + message: "vt must be between 0 and 9999999" + }); }); - }); - it('Should fail: Create a new queue with delay too high', function(done) { - rsmq.createQueue({ - qname: queue1.name, - delay: 10000000 - }, function(err, resp) { - err.message.should.equal("delay must be between 0 and 9999999"); - done(); + it('Should fail: Create a new queue with non numeric vt', function(done) { + rsmq.createQueue({ + qname: queue1.name, + vt: "not_a_number" + }, function(err, resp) { + err.message.should.equal("vt must be between 0 and 9999999"); + done(); + }); }); - }); - it('Should fail: Create a new queue with negative maxsize', function(done) { - rsmq.createQueue({ - qname: queue1.name, - maxsize: -20 - }, function(err, resp) { - err.message.should.equal("maxsize must be between 1024 and 65536"); - done(); + it('Should fail: Create a new queue with non numeric vt', function() { + return rsmq.createQueueAsync({ + qname: queue1.name, + vt: "not_a_number" + }).should.be.rejectedWith(Error, { + message: "vt must be between 0 and 9999999" + }); }); - }); - it('Should fail: Create a new queue with non numeric maxsize', function(done) { - rsmq.createQueue({ - qname: queue1.name, - maxsize: "not_a_number" - }, function(err, resp) { - err.message.should.equal("maxsize must be between 1024 and 65536"); - done(); + it('Should fail: Create a new queue with vt too high', function(done) { + rsmq.createQueue({ + qname: queue1.name, + vt: 10000000 + }, function(err, resp) { + err.message.should.equal("vt must be between 0 and 9999999"); + done(); + }); }); - }); - it('Should fail: Create a new queue with maxsize too high', function(done) { - rsmq.createQueue({ - qname: queue1.name, - maxsize: 66000 - }, function(err, resp) { - err.message.should.equal("maxsize must be between 1024 and 65536"); - done(); + it('Should fail: Create a new queue with negative delay', function(done) { + rsmq.createQueue({ + qname: queue1.name, + delay: -20 + }, function(err, resp) { + err.message.should.equal("delay must be between 0 and 9999999"); + done(); + }); }); - }); - it('Should fail: Create a new queue with maxsize too low', function(done) { - rsmq.createQueue({ - qname: queue1.name, - maxsize: 900 - }, function(err, resp) { - err.message.should.equal("maxsize must be between 1024 and 65536"); - done(); + it('Should fail: Create a new queue with non numeric delay', function(done) { + rsmq.createQueue({ + qname: queue1.name, + delay: "not_a_number" + }, function(err, resp) { + err.message.should.equal("delay must be between 0 and 9999999"); + done(); + }); }); - }); - it('Should fail: Create a new queue with maxsize `-2`', function(done) { - rsmq.createQueue({ - qname: queue1.name, - maxsize: -2 - }, function(err, resp) { - err.message.should.equal("maxsize must be between 1024 and 65536"); - done(); + it('Should fail: Create a new queue with delay too high', function(done) { + rsmq.createQueue({ + qname: queue1.name, + delay: 10000000 + }, function(err, resp) { + err.message.should.equal("delay must be between 0 and 9999999"); + done(); + }); }); - }); - it('ListQueues: Should return empty array', function(done) { - rsmq.listQueues(function(err, resp) { - should.not.exist(err); - resp.length.should.equal(0); - done(); + it('Should fail: Create a new queue with negative maxsize', function(done) { + rsmq.createQueue({ + qname: queue1.name, + maxsize: -20 + }, function(err, resp) { + err.message.should.equal("maxsize must be between 1024 and 65536"); + done(); + }); }); - }); - it('Create a new queue: queue1', function(done) { - rsmq.createQueue({ - qname: queue1.name - }, function(err, resp) { - should.not.exist(err); - resp.should.equal(1); - done(); + it('Should fail: Create a new queue with non numeric maxsize', function(done) { + rsmq.createQueue({ + qname: queue1.name, + maxsize: "not_a_number" + }, function(err, resp) { + err.message.should.equal("maxsize must be between 1024 and 65536"); + done(); + }); }); - }); - it('Should fail: Create the same queue again', function(done) { - rsmq.createQueue({ - qname: queue1.name - }, function(err, resp) { - err.message.should.equal("Queue exists"); - done(); + it('Should fail: Create a new queue with maxsize too high', function(done) { + rsmq.createQueue({ + qname: queue1.name, + maxsize: 66000 + }, function(err, resp) { + err.message.should.equal("maxsize must be between 1024 and 65536"); + done(); + }); }); - }); - it('ListQueues: Should return array with one element', function(done) { - rsmq.listQueues(function(err, resp) { - should.not.exist(err); - resp.length.should.equal(1); - resp.should.containEql(queue1.name); - done(); + it('Should fail: Create a new queue with maxsize too low', function(done) { + rsmq.createQueue({ + qname: queue1.name, + maxsize: 900 + }, function(err, resp) { + err.message.should.equal("maxsize must be between 1024 and 65536"); + done(); + }); }); - }); - it('Create a new queue: queue2', function(done) { - rsmq.createQueue({ - qname: queue2.name, - maxsize: 2048 - }, function(err, resp) { - should.not.exist(err); - resp.should.equal(1); - done(); + it('Should fail: Create a new queue with maxsize `-2`', function(done) { + rsmq.createQueue({ + qname: queue1.name, + maxsize: -2 + }, function(err, resp) { + err.message.should.equal("maxsize must be between 1024 and 65536"); + done(); + }); }); - }); - it('ListQueues: Should return array with two elements', function(done) { - rsmq.listQueues(function(err, resp) { - should.not.exist(err); - resp.length.should.equal(2); - resp.should.containEql(queue1.name); - resp.should.containEql(queue2.name); - done(); + it('ListQueues: Should return empty array', function(done) { + rsmq.listQueues(function(err, resp) { + should.not.exist(err); + resp.length.should.equal(0); + done(); + }); }); - }); - it('Should succeed: GetQueueAttributes of queue 1', function(done) { - rsmq.getQueueAttributes({ - qname: queue1.name - }, function(err, resp) { - should.not.exist(err); - resp.msgs.should.equal(0); - queue1.modified = resp.modified; - done(); + it('Create a new queue: queue1', function(done) { + rsmq.createQueue({ + qname: queue1.name + }, function(err, resp) { + should.not.exist(err); + resp.should.equal(1); + done(); + }); }); - }); - it('Should fail: GetQueueAttributes of bogus queue', function(done) { - rsmq.getQueueAttributes({ - qname: "sdfsdfsdf" - }, function(err, resp) { - err.message.should.equal("Queue not found"); - done(); + it('Should fail: Create the same queue again', function(done) { + rsmq.createQueue({ + qname: queue1.name + }, function(err, resp) { + err.message.should.equal("Queue exists"); + done(); + }); }); - }); - it('Should fail: setQueueAttributes of bogus queue with no supplied attributes', function(done) { - rsmq.setQueueAttributes({ - qname: "kjdsfh3h" - }, function(err, resp) { - err.message.should.equal("No attribute was supplied"); - done(); + it('ListQueues: Should return array with one element', function(done) { + rsmq.listQueues(function(err, resp) { + should.not.exist(err); + resp.length.should.equal(1); + resp.should.containEql(queue1.name); + done(); + }); }); - }); - it('Should fail: setQueueAttributes of bogus queue with supplied attributes', function(done) { - rsmq.setQueueAttributes({ - qname: "kjdsfh3h", - vt: 1000 - }, function(err, resp) { - err.message.should.equal("Queue not found"); - done(); + it('Create a new queue: queue2', function(done) { + rsmq.createQueue({ + qname: queue2.name, + maxsize: 2048 + }, function(err, resp) { + should.not.exist(err); + resp.should.equal(1); + done(); + }); }); - }); - it('setQueueAttributes: Should return the queue with a new vt attribute', function(done) { - rsmq.setQueueAttributes({ - qname: queue1.name, - vt: 1234 - }, function(err, resp) { - resp.vt.should.equal(1234); - resp.delay.should.equal(0); - resp.maxsize.should.equal(65536); - done(); + it('ListQueues: Should return array with two elements', function(done) { + rsmq.listQueues(function(err, resp) { + should.not.exist(err); + resp.length.should.equal(2); + resp.should.containEql(queue1.name); + resp.should.containEql(queue2.name); + done(); + }); }); - }); - it('setQueueAttributes: Should return the queue with a new delay attribute', function(done) { - this.timeout(2000); - setTimeout(function() { + it('Should succeed: GetQueueAttributes of queue 1', function(done) { + rsmq.getQueueAttributes({ + qname: queue1.name + }, function(err, resp) { + should.not.exist(err); + resp.msgs.should.equal(0); + queue1.modified = resp.modified; + done(); + }); + }); + it('Should fail: GetQueueAttributes of bogus queue', function(done) { + rsmq.getQueueAttributes({ + qname: "sdfsdfsdf" + }, function(err, resp) { + err.message.should.equal("Queue not found"); + done(); + }); + }); + it('Should fail: setQueueAttributes of bogus queue with no supplied attributes', function(done) { + rsmq.setQueueAttributes({ + qname: "kjdsfh3h" + }, function(err, resp) { + err.message.should.equal("No attribute was supplied"); + done(); + }); + }); + it('Should fail: setQueueAttributes of bogus queue with supplied attributes', function(done) { + rsmq.setQueueAttributes({ + qname: "kjdsfh3h", + vt: 1000 + }, function(err, resp) { + err.message.should.equal("Queue not found"); + done(); + }); + }); + it('setQueueAttributes: Should return the queue with a new vt attribute', function(done) { rsmq.setQueueAttributes({ qname: queue1.name, - delay: 7 + vt: 1234 }, function(err, resp) { resp.vt.should.equal(1234); - resp.delay.should.equal(7); + resp.delay.should.equal(0); resp.maxsize.should.equal(65536); - resp.modified.should.be.above(queue1.modified); done(); }); - }, 1100); - }); - it('setQueueAttributes: Should return the queue with an umlimited maxsize', function(done) { - rsmq.setQueueAttributes({ - qname: queue1.name, - maxsize: -1 - }, function(err, resp) { - resp.vt.should.equal(1234); - resp.delay.should.equal(7); - resp.maxsize.should.equal(-1); - done(); }); - }); - it('setQueueAttributes: Should return the queue with a new maxsize attribute', function(done) { - rsmq.setQueueAttributes({ - qname: queue1.name, - maxsize: 2048 - }, function(err, resp) { - resp.vt.should.equal(1234); - resp.delay.should.equal(7); - resp.maxsize.should.equal(2048); - done(); + it('setQueueAttributes: Should return the queue with a new delay attribute', function(done) { + this.timeout(2000); + setTimeout(function() { + rsmq.setQueueAttributes({ + qname: queue1.name, + delay: 7 + }, function(err, resp) { + resp.vt.should.equal(1234); + resp.delay.should.equal(7); + resp.maxsize.should.equal(65536); + resp.modified.should.be.above(queue1.modified); + done(); + }); + }, 1100); }); - }); - it('setQueueAttributes: Should return the queue with a new attribute', function(done) { - rsmq.setQueueAttributes({ - qname: queue1.name, - maxsize: 65536, - vt: 30, - delay: 0 - }, function(err, resp) { - resp.vt.should.equal(30); - resp.delay.should.equal(0); - resp.maxsize.should.equal(65536); - done(); + it('setQueueAttributes: Should return the queue with an umlimited maxsize', function(done) { + rsmq.setQueueAttributes({ + qname: queue1.name, + maxsize: -1 + }, function(err, resp) { + resp.vt.should.equal(1234); + resp.delay.should.equal(7); + resp.maxsize.should.equal(-1); + done(); + }); }); - }); - it('Should fail:setQueueAttributes: Should not accept too small maxsize', function(done) { - rsmq.setQueueAttributes({ - qname: queue1.name, - maxsize: 50 - }, function(err, resp) { - err.message.should.equal("maxsize must be between 1024 and 65536"); - done(); + it('setQueueAttributes: Should return the queue with a new maxsize attribute', function(done) { + rsmq.setQueueAttributes({ + qname: queue1.name, + maxsize: 2048 + }, function(err, resp) { + resp.vt.should.equal(1234); + resp.delay.should.equal(7); + resp.maxsize.should.equal(2048); + done(); + }); }); - }); - it('Should fail:setQueueAttributes: Should not accept negative value', function(done) { - rsmq.setQueueAttributes({ - qname: queue1.name, - vt: -5 - }, function(err, resp) { - err.message.should.equal("vt must be between 0 and 9999999"); - done(); + it('setQueueAttributes: Should return the queue with a new attribute', function(done) { + rsmq.setQueueAttributes({ + qname: queue1.name, + maxsize: 65536, + vt: 30, + delay: 0 + }, function(err, resp) { + resp.vt.should.equal(30); + resp.delay.should.equal(0); + resp.maxsize.should.equal(65536); + done(); + }); }); - }); - }); - describe('Messages', function() { - it('Should fail: Send a message to non-existing queue', function(done) { - rsmq.sendMessage({ - qname: "rtlbrmpft", - message: "foo" - }, function(err, resp) { - err.message.should.equal("Queue not found"); - done(); + it('Should fail:setQueueAttributes: Should not accept too small maxsize', function(done) { + rsmq.setQueueAttributes({ + qname: queue1.name, + maxsize: 50 + }, function(err, resp) { + err.message.should.equal("maxsize must be between 1024 and 65536"); + done(); + }); }); - }); - it('Should fail: Send a message without any parameters', function(done) { - rsmq.sendMessage({}, function(err, resp) { - err.message.should.equal("No qname supplied"); - done(); + it('Should fail:setQueueAttributes: Should not accept negative value', function(done) { + rsmq.setQueueAttributes({ + qname: queue1.name, + vt: -5 + }, function(err, resp) { + err.message.should.equal("vt must be between 0 and 9999999"); + done(); + }); }); }); - it('Should fail: Send a message without a message key', function(done) { - rsmq.sendMessage({ - qname: queue1.name, - messXage: "Hello" - }, function(err, resp) { - err.message.should.equal("Message must be a string"); - done(); + describe('Messages', function() { + it('Should fail: Send a message to non-existing queue', function(done) { + rsmq.sendMessage({ + qname: "rtlbrmpft", + message: "foo" + }, function(err, resp) { + err.message.should.equal("Queue not found"); + done(); + }); }); - }); - it('Should fail: Send a message with message being a number', function(done) { - rsmq.sendMessage({ - qname: queue1.name, - message: 123 - }, function(err, resp) { - err.message.should.equal("Message must be a string"); - done(); + it('Should fail: Send a message without any parameters', function(done) { + rsmq.sendMessage({}, function(err, resp) { + err.message.should.equal("No qname supplied"); + done(); + }); }); - }); - // TODO: Try to send a loooong msg - it('Send message 1 with existing Redis instance', function(done) { - rsmq2.sendMessage({ - qname: queue1.name, - message: "Hello" - }, function(err, resp) { - should.not.exist(err); - q1m1 = { - id: resp, - message: "Hello" - }; - done(); + it('Should fail: Send a message without a message key', function(done) { + rsmq.sendMessage({ + qname: queue1.name, + messXage: "Hello" + }, function(err, resp) { + err.message.should.equal("Message must be a string"); + done(); + }); }); - }); - // Send 1000 msgs to q2 so we can delay sending of msg 2 to q1 - it('Send 1000 messages to queue2: succeed', function(done) { - var i, j, pq; - pq = []; - for (i = j = 0; j < 1000; i = ++j) { - pq.push({ - qname: queue2.name, - message: "test message number:" + i + it('Should fail: Send a message with message being a number', function(done) { + rsmq.sendMessage({ + qname: queue1.name, + message: 123 + }, function(err, resp) { + err.message.should.equal("Message must be a string"); + done(); }); - } - async.map(pq, rsmq.sendMessage, function(err, resp) { - var e, k, len; - for (k = 0, len = resp.length; k < len; k++) { - e = resp[k]; - q2msgs[e] = 1; - e.length.should.equal(32); + }); + // TODO: Try to send a loooong msg + it('Send message 1 with existing Redis instance', function(done) { + rsmq2.sendMessage({ + qname: queue1.name, + message: "Hello" + }, function(err, resp) { + should.not.exist(err); + q1m1 = { + id: resp, + message: "Hello" + }; + done(); + }); + }); + // Send 1000 msgs to q2 so we can delay sending of msg 2 to q1 + it('Send 1000 messages to queue2: succeed', function(done) { + var i, j, pq; + pq = []; + for (i = j = 0; j < 1000; i = ++j) { + pq.push({ + qname: queue2.name, + message: "test message number:" + i + }); } - _.keys(q2msgs).length.should.equal(1000); - done(); + async.map(pq, rsmq.sendMessage, function(err, resp) { + var e, k, len; + for (k = 0, len = resp.length; k < len; k++) { + e = resp[k]; + q2msgs[e] = 1; + e.length.should.equal(32); + } + _.keys(q2msgs).length.should.equal(1000); + done(); + }); }); - }); - it('Send message 2', function(done) { - rsmq.sendMessage({ - qname: queue1.name, - message: "World" - }, function(err, resp) { - should.not.exist(err); - q1m2 = { - id: resp, + it('Send message 2', function(done) { + rsmq.sendMessage({ + qname: queue1.name, message: "World" - }; - done(); + }, function(err, resp) { + should.not.exist(err); + q1m2 = { + id: resp, + message: "World" + }; + done(); + }); }); - }); - it('Receive a message. Should return message 1', function(done) { - rsmq2.receiveMessage({ - qname: queue1.name - }, function(err, resp) { - resp.id.should.equal(q1m1.id); - done(); + it('Receive a message. Should return message 1', function(done) { + rsmq2.receiveMessage({ + qname: queue1.name + }, function(err, resp) { + resp.id.should.equal(q1m1.id); + done(); + }); }); - }); - it('Receive a message. Should return message 2', function(done) { - rsmq.receiveMessage({ - qname: queue1.name - }, function(err, resp) { - resp.id.should.equal(q1m2.id); - done(); + it('Receive a message. Should return message 2', function(done) { + rsmq.receiveMessage({ + qname: queue1.name + }, function(err, resp) { + resp.id.should.equal(q1m2.id); + done(); + }); }); - }); - it('Check queue properties. Should have 2 msgs', function(done) { - rsmq.getQueueAttributes({ - qname: queue1.name - }, function(err, resp) { - resp.msgs.should.equal(2); - resp.hiddenmsgs.should.equal(2); - done(); + it('Check queue properties. Should have 2 msgs', function(done) { + rsmq.getQueueAttributes({ + qname: queue1.name + }, function(err, resp) { + resp.msgs.should.equal(2); + resp.hiddenmsgs.should.equal(2); + done(); + }); }); - }); - it('Send message 3', function(done) { - rsmq.sendMessage({ - qname: queue1.name, - message: "Booo!!" - }, function(err, resp) { - should.not.exist(err); - q1m3 = { - id: resp, + it('Send message 3', function(done) { + rsmq.sendMessage({ + qname: queue1.name, message: "Booo!!" - }; - done(); + }, function(err, resp) { + should.not.exist(err); + q1m3 = { + id: resp, + message: "Booo!!" + }; + done(); + }); }); - }); - it('Check queue properties. Should have 3 msgs', function(done) { - rsmq.getQueueAttributes({ - qname: queue1.name - }, function(err, resp) { - resp.msgs.should.equal(3); - resp.totalrecv.should.equal(2); - done(); + it('Check queue properties. Should have 3 msgs', function(done) { + rsmq.getQueueAttributes({ + qname: queue1.name + }, function(err, resp) { + resp.msgs.should.equal(3); + resp.totalrecv.should.equal(2); + done(); + }); }); - }); - it('Pop a message. Should return message 3 and delete it', function(done) { - rsmq.popMessage({ - qname: queue1.name - }, function(err, resp) { - resp.id.should.equal(q1m3.id); - done(); + it('Pop a message. Should return message 3 and delete it', function(done) { + rsmq.popMessage({ + qname: queue1.name + }, function(err, resp) { + resp.id.should.equal(q1m3.id); + done(); + }); }); - }); - it('Check queue properties. Should have 2 msgs', function(done) { - rsmq.getQueueAttributes({ - qname: queue1.name - }, function(err, resp) { - resp.msgs.should.equal(2); - resp.totalrecv.should.equal(3); - done(); + it('Check queue properties. Should have 2 msgs', function(done) { + rsmq.getQueueAttributes({ + qname: queue1.name + }, function(err, resp) { + resp.msgs.should.equal(2); + resp.totalrecv.should.equal(3); + done(); + }); }); - }); - it('Pop a message. Should not return a message', function(done) { - rsmq.popMessage({ - qname: queue1.name - }, function(err, resp) { - should.not.exist(resp.id); - done(); + it('Pop a message. Should not return a message', function(done) { + rsmq.popMessage({ + qname: queue1.name + }, function(err, resp) { + should.not.exist(resp.id); + done(); + }); }); - }); - it('Should fail. Set the visibility of a non existing message', function(done) { - rsmq.changeMessageVisibility({ - qname: queue1.name, - id: "abcdefghij0123456789abcdefghij01", - vt: 10 - }, function(err, resp) { - resp.should.equal(0); - done(); + it('Should fail. Set the visibility of a non existing message', function(done) { + rsmq.changeMessageVisibility({ + qname: queue1.name, + id: "abcdefghij0123456789abcdefghij01", + vt: 10 + }, function(err, resp) { + resp.should.equal(0); + done(); + }); }); - }); - it('Set new visibility timeout of message 2 to 10s', function(done) { - rsmq.changeMessageVisibility({ - qname: queue1.name, - id: q1m2.id, - vt: 10 - }, function(err, resp) { - resp.should.equal(1); - done(); + it('Set new visibility timeout of message 2 to 10s', function(done) { + rsmq.changeMessageVisibility({ + qname: queue1.name, + id: q1m2.id, + vt: 10 + }, function(err, resp) { + resp.should.equal(1); + done(); + }); }); - }); - it('Receive a message. Should return nothing', function(done) { - rsmq.receiveMessage({ - qname: queue1.name - }, function(err, resp) { - should.not.exist(resp.id); - done(); + it('Receive a message. Should return nothing', function(done) { + rsmq.receiveMessage({ + qname: queue1.name + }, function(err, resp) { + should.not.exist(resp.id); + done(); + }); }); - }); - it('Set new visibility timeout of message 2 to 0s', function(done) { - rsmq.changeMessageVisibility({ - qname: queue1.name, - id: q1m2.id, - vt: 0 - }, function(err, resp) { - resp.should.equal(1); - done(); + it('Set new visibility timeout of message 2 to 0s', function(done) { + rsmq.changeMessageVisibility({ + qname: queue1.name, + id: q1m2.id, + vt: 0 + }, function(err, resp) { + resp.should.equal(1); + done(); + }); }); - }); - it('Receive a message. Should return message 2', function(done) { - rsmq.receiveMessage({ - qname: queue1.name - }, function(err, resp) { - resp.id.should.equal(q1m2.id); - done(); + it('Receive a message. Should return message 2', function(done) { + rsmq.receiveMessage({ + qname: queue1.name + }, function(err, resp) { + resp.id.should.equal(q1m2.id); + done(); + }); }); - }); - it('Receive a message. Should return nothing', function(done) { - rsmq.receiveMessage({ - qname: queue1.name - }, function(err, resp) { - should.not.exist(resp.id); - done(); + it('Receive a message. Should return nothing', function(done) { + rsmq.receiveMessage({ + qname: queue1.name + }, function(err, resp) { + should.not.exist(resp.id); + done(); + }); }); - }); - it('Should fail: Delete a message without supplying an id', function(done) { - rsmq.deleteMessage({ - qname: queue1.name - }, function(err, resp) { - err.message.should.equal("No id supplied"); - done(); + it('Should fail: Delete a message without supplying an id', function(done) { + rsmq.deleteMessage({ + qname: queue1.name + }, function(err, resp) { + err.message.should.equal("No id supplied"); + done(); + }); }); - }); - it('Should fail: Delete a message with invalid id', function(done) { - rsmq.deleteMessage({ - qname: queue1.name, - id: "sdafsdf" - }, function(err, resp) { - err.message.should.equal("Invalid id format"); - done(); + it('Should fail: Delete a message with invalid id', function(done) { + rsmq.deleteMessage({ + qname: queue1.name, + id: "sdafsdf" + }, function(err, resp) { + err.message.should.equal("Invalid id format"); + done(); + }); }); - }); - it('Delete message 1. Should return 1', function(done) { - rsmq.deleteMessage({ - qname: queue1.name, - id: q1m1.id - }, function(err, resp) { - resp.should.equal(1); - done(); + it('Delete message 1. Should return 1', function(done) { + rsmq.deleteMessage({ + qname: queue1.name, + id: q1m1.id + }, function(err, resp) { + resp.should.equal(1); + done(); + }); }); - }); - it('Delete message 1 again. Should return 0', function(done) { - rsmq.deleteMessage({ - qname: queue1.name, - id: q1m1.id - }, function(err, resp) { - resp.should.equal(0); - done(); + it('Delete message 1 again. Should return 0', function(done) { + rsmq.deleteMessage({ + qname: queue1.name, + id: q1m1.id + }, function(err, resp) { + resp.should.equal(0); + done(); + }); }); - }); - it('Set new visibility timeout of message 1. Should return 0.', function(done) { - rsmq.changeMessageVisibility({ - qname: queue1.name, - id: q1m1.id, - vt: 10 - }, function(err, resp) { - resp.should.equal(0); - done(); + it('Set new visibility timeout of message 1. Should return 0.', function(done) { + rsmq.changeMessageVisibility({ + qname: queue1.name, + id: q1m1.id, + vt: 10 + }, function(err, resp) { + resp.should.equal(0); + done(); + }); }); - }); - it('Should fail: Send a message that is too long', function(done) { - var text; - text = JSON.stringify((function() { - var results = []; - for (var j = 0; j <= 15000; j++){ results.push(j); } - return results; - }).apply(this)); - rsmq.sendMessage({ - qname: queue1.name, - message: text - }, function(err, resp) { - should.not.exist(resp); - err.message.should.equal("Message too long"); - done(); + it('Should fail: Send a message that is too long', function(done) { + var text; + text = JSON.stringify((function() { + var results = []; + for (var j = 0; j <= 15000; j++){ results.push(j); } + return results; + }).apply(this)); + rsmq.sendMessage({ + qname: queue1.name, + message: text + }, function(err, resp) { + should.not.exist(resp); + err.message.should.equal("Message too long"); + done(); + }); }); - }); - it('Receive 1000 messages from queue2 and delete 500 (those where number is even)', function(done) { - var i, j, pq; - pq = []; + it('Receive 1000 messages from queue2 and delete 500 (those where number is even)', function(done) { + var i, j, pq; + pq = []; // we keep vt = 0 so we can query them again quickly - for (i = j = 0; j < 1000; i = ++j) { - pq.push({ - qname: queue2.name, - vt: 0 - }); - } - async.map(pq, rsmq.receiveMessage, function(err, resp) { - var dq, e, k, len; - dq = []; - for (k = 0, len = resp.length; k < len; k++) { - e = resp[k]; - if (!(!(e.message.split(":")[1] % 2))) { - continue; - } - dq.push({ + for (i = j = 0; j < 1000; i = ++j) { + pq.push({ qname: queue2.name, - id: e.id + vt: 0 }); - delete q2msgs[e.id]; } - async.map(dq, rsmq.deleteMessage, function(err, resp) { - var l, len1; - for (l = 0, len1 = resp.length; l < len1; l++) { - e = resp[l]; - e.should.equal(1); + async.map(pq, rsmq.receiveMessage, function(err, resp) { + var dq, e, k, len; + dq = []; + for (k = 0, len = resp.length; k < len; k++) { + e = resp[k]; + if (!(!(e.message.split(":")[1] % 2))) { + continue; + } + dq.push({ + qname: queue2.name, + id: e.id + }); + delete q2msgs[e.id]; } - done(); + async.map(dq, rsmq.deleteMessage, function(err, resp) { + var l, len1; + for (l = 0, len1 = resp.length; l < len1; l++) { + e = resp[l]; + e.should.equal(1); + } + done(); + }); }); }); - }); - it('GetQueueAttributes: Should return queue attributes', function(done) { - rsmq.getQueueAttributes({ - qname: queue2.name - }, function(err, resp) { - should.not.exist(err); - resp.msgs.should.equal(500); - done(); + it('GetQueueAttributes: Should return queue attributes', function(done) { + rsmq.getQueueAttributes({ + qname: queue2.name + }, function(err, resp) { + should.not.exist(err); + resp.msgs.should.equal(500); + done(); + }); }); - }); - it('Receive 500 messages from queue2 and delete them', function(done) { - var i, j, pq; - pq = []; + it('Receive 500 messages from queue2 and delete them', function(done) { + var i, j, pq; + pq = []; // we keep vt = 0 so we can query them again quickly - for (i = j = 0; j < 500; i = ++j) { - pq.push({ - qname: queue2.name, - vt: 0 - }); - } - async.map(pq, rsmq.receiveMessage, function(err, resp) { - var dq, e, k, len; - dq = []; - for (k = 0, len = resp.length; k < len; k++) { - e = resp[k]; - if (!(e.message.split(":")[1] % 2)) { - continue; - } - dq.push({ + for (i = j = 0; j < 500; i = ++j) { + pq.push({ qname: queue2.name, - id: e.id + vt: 0 }); - delete q2msgs[e.id]; } - async.map(dq, rsmq.deleteMessage, function(err, resp) { - var l, len1; - for (l = 0, len1 = resp.length; l < len1; l++) { - e = resp[l]; - e.should.equal(1); + async.map(pq, rsmq.receiveMessage, function(err, resp) { + var dq, e, k, len; + dq = []; + for (k = 0, len = resp.length; k < len; k++) { + e = resp[k]; + if (!(e.message.split(":")[1] % 2)) { + continue; + } + dq.push({ + qname: queue2.name, + id: e.id + }); + delete q2msgs[e.id]; } + async.map(dq, rsmq.deleteMessage, function(err, resp) { + var l, len1; + for (l = 0, len1 = resp.length; l < len1; l++) { + e = resp[l]; + e.should.equal(1); + } + done(); + // q2msgs should be empty + _.keys(q2msgs).length.should.equal(0); + }); + }); + }); + it('Receive a message from queue2. Should return {}', function(done) { + rsmq.receiveMessage({ + qname: queue2.name + }, function(err, resp) { + should.not.exist(resp.id); done(); - // q2msgs should be empty - _.keys(q2msgs).length.should.equal(0); }); }); - }); - it('Receive a message from queue2. Should return {}', function(done) { - rsmq.receiveMessage({ - qname: queue2.name - }, function(err, resp) { - should.not.exist(resp.id); - done(); + it('GetQueueAttributes: Should return queue attributes', function(done) { + rsmq.getQueueAttributes({ + qname: queue2.name + }, function(err, resp) { + should.not.exist(err); + resp.totalrecv.should.equal(1500); + resp.totalsent.should.equal(1000); + resp.msgs.should.equal(0); + done(); + }); }); - }); - it('GetQueueAttributes: Should return queue attributes', function(done) { - rsmq.getQueueAttributes({ - qname: queue2.name - }, function(err, resp) { - should.not.exist(err); - resp.totalrecv.should.equal(1500); - resp.totalsent.should.equal(1000); - resp.msgs.should.equal(0); - done(); + it('setQueueAttributes: Should return the queue2 with an umlimited maxsize', function(done) { + rsmq.setQueueAttributes({ + qname: queue2.name, + delay: 0, + vt: 30, + maxsize: -1 + }, function(err, resp) { + resp.vt.should.equal(30); + resp.delay.should.equal(0); + resp.maxsize.should.equal(-1); + done(); + }); }); - }); - it('setQueueAttributes: Should return the queue2 with an umlimited maxsize', function(done) { - rsmq.setQueueAttributes({ - qname: queue2.name, - delay: 0, - vt: 30, - maxsize: -1 - }, function(err, resp) { - resp.vt.should.equal(30); - resp.delay.should.equal(0); - resp.maxsize.should.equal(-1); - done(); + it('Send/Recevice a longer than 64k msg to test unlimited functionality', function(done) { + var longmsg; + longmsg = looong_string(); + rsmq.sendMessage({ + qname: queue2.name, + message: longmsg + }, function(err, resp1) { + should.not.exist(err); + rsmq.receiveMessage({ + qname: queue2.name + }, function(err, resp2) { + should.not.exist(err); + resp2.message.should.equal(longmsg); + resp2.id.should.equal(resp1); + done(); + }); + }); }); }); - it('Send/Recevice a longer than 64k msg to test unlimited functionality', function(done) { - var longmsg; - longmsg = looong_string(); - rsmq.sendMessage({ - qname: queue2.name, - message: longmsg - }, function(err, resp1) { - should.not.exist(err); - rsmq.receiveMessage({ - qname: queue2.name - }, function(err, resp2) { + describe('Realtime Pub/Sub notifications', function() { + it('Send another message to queue1', function(done) { + rsmq.sendMessage({ + qname: queue1.name, + message: "Another World" + }, function(err, resp) { should.not.exist(err); - resp2.message.should.equal(longmsg); - resp2.id.should.equal(resp1); done(); }); }); - }); - }); - describe('Realtime Pub/Sub notifications', function() { - it('Send another message to queue1', function(done) { - rsmq.sendMessage({ - qname: queue1.name, - message: "Another World" - }, function(err, resp) { - should.not.exist(err); + it('wait 100ms', function(done) { + return setTimeout(done, 100); + }); + it('check queue1 length. Should be 2', function(done) { + Q1LENGTH.should.equal(2); done(); }); - }); - it('wait 100ms', function(done) { - return setTimeout(done, 100); - }); - it('check queue1 length. Should be 2', function(done) { - Q1LENGTH.should.equal(2); - done(); - }); - it('Send another message to queue1', function(done) { - rsmq.sendMessage({ - qname: queue1.name, - message: "Another World" - }, function(err, resp) { - should.not.exist(err); + it('Send another message to queue1', function(done) { + rsmq.sendMessage({ + qname: queue1.name, + message: "Another World" + }, function(err, resp) { + should.not.exist(err); + done(); + }); + }); + it('wait 100ms', function(done) { + return setTimeout(done, 100); + }); + it('check queue1 length. Should be 3', function(done) { + Q1LENGTH.should.equal(3); done(); }); }); - it('wait 100ms', function(done) { - return setTimeout(done, 100); - }); - it('check queue1 length. Should be 3', function(done) { - Q1LENGTH.should.equal(3); - done(); - }); }); -}); + +}).call(this); From 5ccfbdfdc9f02bc0d40c489007049f911a842d50 Mon Sep 17 00:00:00 2001 From: Ian Taylor Date: Thu, 5 Dec 2019 22:30:11 -0800 Subject: [PATCH 2/2] Update package-lock --- package-lock.json | 577 ++++++++++++++++++++++++++-------------------- 1 file changed, 331 insertions(+), 246 deletions(-) diff --git a/package-lock.json b/package-lock.json index f13e5ca..a98c7ef 100644 --- a/package-lock.json +++ b/package-lock.json @@ -14,7 +14,7 @@ "resolved": "https://registry.npmjs.org/@types/redis/-/redis-2.8.0.tgz", "integrity": "sha512-2CDJ6GuEb+CkD+9mh1eDlS0jvdYUD46SSEpLSQ6It8g6TmDcBB4QjFzgEnTyDMF7PldseXitVaylJ+ijoEH/WA==", "requires": { - "@types/node": "*" + "@types/node": "9.6.6" } }, "ansi-styles": { @@ -23,7 +23,7 @@ "integrity": "sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA==", "dev": true, "requires": { - "color-convert": "^1.9.0" + "color-convert": "1.9.3" } }, "arr-diff": { @@ -62,7 +62,7 @@ "integrity": "sha512-H1qVYh1MYhEEFLsP97cVKqCGo7KfCyTt6uEWqsTBr9SO84oK9Uwbyd/yCW+6rKJLHksBNUVWZDAjfS+Ccx0Bbg==", "dev": true, "requires": { - "lodash": "^4.17.11" + "lodash": "4.17.11" } }, "atob": { @@ -83,13 +83,13 @@ "integrity": "sha512-5T6P4xPgpp0YDFvSWwEZ4NoE3aM4QBQXDzmVbraCkFj8zHM+mba8SyqB5DbZWyR7mYHo6Y7BdQo3MoA4m0TeQg==", "dev": true, "requires": { - "cache-base": "^1.0.1", - "class-utils": "^0.3.5", - "component-emitter": "^1.2.1", - "define-property": "^1.0.0", - "isobject": "^3.0.1", - "mixin-deep": "^1.2.0", - "pascalcase": "^0.1.1" + "cache-base": "1.0.1", + "class-utils": "0.3.6", + "component-emitter": "1.3.0", + "define-property": "1.0.0", + "isobject": "3.0.1", + "mixin-deep": "1.3.1", + "pascalcase": "0.1.1" }, "dependencies": { "define-property": { @@ -98,7 +98,7 @@ "integrity": "sha1-dp66rz9KY6rTr56NMEybvnm/sOY=", "dev": true, "requires": { - "is-descriptor": "^1.0.0" + "is-descriptor": "1.0.2" } }, "is-accessor-descriptor": { @@ -107,7 +107,7 @@ "integrity": "sha512-m5hnHTkcVsPfqx3AKlyttIPb7J+XykHvJP2B9bZDjlhLIoEq4XoK64Vg7boZlVWYK6LUY94dYPEE7Lh0ZkZKcQ==", "dev": true, "requires": { - "kind-of": "^6.0.0" + "kind-of": "6.0.2" } }, "is-data-descriptor": { @@ -116,7 +116,7 @@ "integrity": "sha512-jbRXy1FmtAoCjQkVmIVYwuuqDFUbaOeDjmed1tOGPrsMhtJA4rD9tkgA0F1qJ3gRFRXcHYVkdeaP50Q5rE/jLQ==", "dev": true, "requires": { - "kind-of": "^6.0.0" + "kind-of": "6.0.2" } }, "is-descriptor": { @@ -125,9 +125,9 @@ "integrity": "sha512-2eis5WqQGV7peooDyLmNEPUrps9+SXX5c9pL3xEB+4e9HnGuDa7mB7kHxHw4CbqS9k1T2hOH3miL8n8WtiYVtg==", "dev": true, "requires": { - "is-accessor-descriptor": "^1.0.0", - "is-data-descriptor": "^1.0.0", - "kind-of": "^6.0.2" + "is-accessor-descriptor": "1.0.0", + "is-data-descriptor": "1.0.0", + "kind-of": "6.0.2" } } } @@ -144,7 +144,7 @@ "integrity": "sha1-wHshHHyVLsH479Uad+8NHTmQopI=", "dev": true, "requires": { - "balanced-match": "^1.0.0", + "balanced-match": "1.0.0", "concat-map": "0.0.1" } }, @@ -154,16 +154,16 @@ "integrity": "sha512-aNdbnj9P8PjdXU4ybaWLK2IF3jc/EoDYbC7AazW6to3TRsfXxscC9UXOB5iDiEQrkyIbWp2SLQda4+QAa7nc3w==", "dev": true, "requires": { - "arr-flatten": "^1.1.0", - "array-unique": "^0.3.2", - "extend-shallow": "^2.0.1", - "fill-range": "^4.0.0", - "isobject": "^3.0.1", - "repeat-element": "^1.1.2", - "snapdragon": "^0.8.1", - "snapdragon-node": "^2.0.1", - "split-string": "^3.0.2", - "to-regex": "^3.0.1" + "arr-flatten": "1.1.0", + "array-unique": "0.3.2", + "extend-shallow": "2.0.1", + "fill-range": "4.0.0", + "isobject": "3.0.1", + "repeat-element": "1.1.3", + "snapdragon": "0.8.2", + "snapdragon-node": "2.1.1", + "split-string": "3.1.0", + "to-regex": "3.0.2" }, "dependencies": { "extend-shallow": { @@ -172,7 +172,7 @@ "integrity": "sha1-Ua99YUrZqfYQ6huvu5idaxxWiQ8=", "dev": true, "requires": { - "is-extendable": "^0.1.0" + "is-extendable": "0.1.1" } } } @@ -189,15 +189,15 @@ "integrity": "sha512-AKcdTnFSWATd5/GCPRxr2ChwIJ85CeyrEyjRHlKxQ56d4XJMGym0uAiKn0xbLOGOl3+yRpOTi484dVCEc5AUzQ==", "dev": true, "requires": { - "collection-visit": "^1.0.0", - "component-emitter": "^1.2.1", - "get-value": "^2.0.6", - "has-value": "^1.0.0", - "isobject": "^3.0.1", - "set-value": "^2.0.0", - "to-object-path": "^0.3.0", - "union-value": "^1.0.0", - "unset-value": "^1.0.0" + "collection-visit": "1.0.0", + "component-emitter": "1.3.0", + "get-value": "2.0.6", + "has-value": "1.0.0", + "isobject": "3.0.1", + "set-value": "2.0.0", + "to-object-path": "0.3.0", + "union-value": "1.0.0", + "unset-value": "1.0.0" } }, "chalk": { @@ -206,9 +206,9 @@ "integrity": "sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==", "dev": true, "requires": { - "ansi-styles": "^3.2.1", - "escape-string-regexp": "^1.0.5", - "supports-color": "^5.3.0" + "ansi-styles": "3.2.1", + "escape-string-regexp": "1.0.5", + "supports-color": "5.5.0" }, "dependencies": { "has-flag": { @@ -223,7 +223,7 @@ "integrity": "sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==", "dev": true, "requires": { - "has-flag": "^3.0.0" + "has-flag": "3.0.0" } } } @@ -234,10 +234,10 @@ "integrity": "sha512-qOhPa/Fj7s6TY8H8esGu5QNpMMQxz79h+urzrNYN6mn+9BnxlDGf5QZ+XeCDsxSjPqsSR56XOZOJmpeurnLMeg==", "dev": true, "requires": { - "arr-union": "^3.1.0", - "define-property": "^0.2.5", - "isobject": "^3.0.0", - "static-extend": "^0.1.1" + "arr-union": "3.1.0", + "define-property": "0.2.5", + "isobject": "3.0.1", + "static-extend": "0.1.2" }, "dependencies": { "define-property": { @@ -246,11 +246,17 @@ "integrity": "sha1-w1se+RjsPJkPmlvFe+BKrOxcgRY=", "dev": true, "requires": { - "is-descriptor": "^0.1.0" + "is-descriptor": "0.1.6" } } } }, + "cluster-key-slot": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/cluster-key-slot/-/cluster-key-slot-1.1.0.tgz", + "integrity": "sha512-2Nii8p3RwAPiFwsnZvukotvow2rIHM+yQ6ZcBXGHdniadkYGZYiGmkHJIbZPIV9nfv7m/U1IPMVVcAhoWFeklw==", + "dev": true + }, "coffeescript": { "version": "2.4.1", "resolved": "https://registry.npmjs.org/coffeescript/-/coffeescript-2.4.1.tgz", @@ -263,8 +269,8 @@ "integrity": "sha1-S8A3PBZLwykbTTaMgpzxqApZ3KA=", "dev": true, "requires": { - "map-visit": "^1.0.0", - "object-visit": "^1.0.0" + "map-visit": "1.0.0", + "object-visit": "1.0.1" } }, "color-convert": { @@ -333,8 +339,8 @@ "integrity": "sha512-jwK2UV4cnPpbcG7+VRARKTZPUWowwXA8bzH5NP6ud0oeAxyYPuGZUAC7hMugpCdz4BeSZl2Dl9k66CHJ/46ZYQ==", "dev": true, "requires": { - "is-descriptor": "^1.0.2", - "isobject": "^3.0.1" + "is-descriptor": "1.0.2", + "isobject": "3.0.1" }, "dependencies": { "is-accessor-descriptor": { @@ -343,7 +349,7 @@ "integrity": "sha512-m5hnHTkcVsPfqx3AKlyttIPb7J+XykHvJP2B9bZDjlhLIoEq4XoK64Vg7boZlVWYK6LUY94dYPEE7Lh0ZkZKcQ==", "dev": true, "requires": { - "kind-of": "^6.0.0" + "kind-of": "6.0.2" } }, "is-data-descriptor": { @@ -352,7 +358,7 @@ "integrity": "sha512-jbRXy1FmtAoCjQkVmIVYwuuqDFUbaOeDjmed1tOGPrsMhtJA4rD9tkgA0F1qJ3gRFRXcHYVkdeaP50Q5rE/jLQ==", "dev": true, "requires": { - "kind-of": "^6.0.0" + "kind-of": "6.0.2" } }, "is-descriptor": { @@ -361,13 +367,19 @@ "integrity": "sha512-2eis5WqQGV7peooDyLmNEPUrps9+SXX5c9pL3xEB+4e9HnGuDa7mB7kHxHw4CbqS9k1T2hOH3miL8n8WtiYVtg==", "dev": true, "requires": { - "is-accessor-descriptor": "^1.0.0", - "is-data-descriptor": "^1.0.0", - "kind-of": "^6.0.2" + "is-accessor-descriptor": "1.0.0", + "is-data-descriptor": "1.0.0", + "kind-of": "6.0.2" } } } }, + "denque": { + "version": "1.4.1", + "resolved": "https://registry.npmjs.org/denque/-/denque-1.4.1.tgz", + "integrity": "sha512-OfzPuSZKGcgr96rf1oODnfjqBFmr1DVoc/TrItj3Ohe0Ah1C5WX5Baquw/9U9KovnQ88EqmJbD66rKYUQYN1tQ==", + "dev": true + }, "diff": { "version": "3.3.1", "resolved": "https://registry.npmjs.org/diff/-/diff-3.3.1.tgz", @@ -391,9 +403,9 @@ "integrity": "sha512-F/7vkyTtyc/llOIn8oWclcB25KdRaiPBpZYDgJHgh/UHtpgT2p2eldQgtQnLtUvfMKPKxbRaQM/hHkvLHt1Vng==", "dev": true, "requires": { - "graceful-fs": "^4.1.2", - "memory-fs": "^0.4.0", - "tapable": "^1.0.0" + "graceful-fs": "4.1.15", + "memory-fs": "0.4.1", + "tapable": "1.1.3" } }, "errno": { @@ -402,7 +414,7 @@ "integrity": "sha512-MfrRBDWzIWifgq6tJj60gkAwtLNb6sQPlcFrSOflcP1aFmmruKQ2wRnze/8V6kgyz7H3FF8Npzv78mZ7XLLflg==", "dev": true, "requires": { - "prr": "~1.0.1" + "prr": "1.0.1" } }, "escape-string-regexp": { @@ -417,13 +429,13 @@ "integrity": "sha1-t3c14xXOMPa27/D4OwQVGiJEliI=", "dev": true, "requires": { - "debug": "^2.3.3", - "define-property": "^0.2.5", - "extend-shallow": "^2.0.1", - "posix-character-classes": "^0.1.0", - "regex-not": "^1.0.0", - "snapdragon": "^0.8.1", - "to-regex": "^3.0.1" + "debug": "2.6.9", + "define-property": "0.2.5", + "extend-shallow": "2.0.1", + "posix-character-classes": "0.1.1", + "regex-not": "1.0.2", + "snapdragon": "0.8.2", + "to-regex": "3.0.2" }, "dependencies": { "debug": { @@ -441,7 +453,7 @@ "integrity": "sha1-w1se+RjsPJkPmlvFe+BKrOxcgRY=", "dev": true, "requires": { - "is-descriptor": "^0.1.0" + "is-descriptor": "0.1.6" } }, "extend-shallow": { @@ -450,7 +462,7 @@ "integrity": "sha1-Ua99YUrZqfYQ6huvu5idaxxWiQ8=", "dev": true, "requires": { - "is-extendable": "^0.1.0" + "is-extendable": "0.1.1" } } } @@ -461,8 +473,8 @@ "integrity": "sha1-Jqcarwc7OfshJxcnRhMcJwQCjbg=", "dev": true, "requires": { - "assign-symbols": "^1.0.0", - "is-extendable": "^1.0.1" + "assign-symbols": "1.0.0", + "is-extendable": "1.0.1" }, "dependencies": { "is-extendable": { @@ -471,7 +483,7 @@ "integrity": "sha512-arnXMxT1hhoKo9k1LZdmlNyJdDDfy2v0fXjFlmok4+i8ul/6WlbVge9bhM74OpNPQPMGUToDtz+KXa1PneJxOA==", "dev": true, "requires": { - "is-plain-object": "^2.0.4" + "is-plain-object": "2.0.4" } } } @@ -482,14 +494,14 @@ "integrity": "sha512-Nmb6QXkELsuBr24CJSkilo6UHHgbekK5UiZgfE6UHD3Eb27YC6oD+bhcT+tJ6cl8dmsgdQxnWlcry8ksBIBLpw==", "dev": true, "requires": { - "array-unique": "^0.3.2", - "define-property": "^1.0.0", - "expand-brackets": "^2.1.4", - "extend-shallow": "^2.0.1", - "fragment-cache": "^0.2.1", - "regex-not": "^1.0.0", - "snapdragon": "^0.8.1", - "to-regex": "^3.0.1" + "array-unique": "0.3.2", + "define-property": "1.0.0", + "expand-brackets": "2.1.4", + "extend-shallow": "2.0.1", + "fragment-cache": "0.2.1", + "regex-not": "1.0.2", + "snapdragon": "0.8.2", + "to-regex": "3.0.2" }, "dependencies": { "define-property": { @@ -498,7 +510,7 @@ "integrity": "sha1-dp66rz9KY6rTr56NMEybvnm/sOY=", "dev": true, "requires": { - "is-descriptor": "^1.0.0" + "is-descriptor": "1.0.2" } }, "extend-shallow": { @@ -507,7 +519,7 @@ "integrity": "sha1-Ua99YUrZqfYQ6huvu5idaxxWiQ8=", "dev": true, "requires": { - "is-extendable": "^0.1.0" + "is-extendable": "0.1.1" } }, "is-accessor-descriptor": { @@ -516,7 +528,7 @@ "integrity": "sha512-m5hnHTkcVsPfqx3AKlyttIPb7J+XykHvJP2B9bZDjlhLIoEq4XoK64Vg7boZlVWYK6LUY94dYPEE7Lh0ZkZKcQ==", "dev": true, "requires": { - "kind-of": "^6.0.0" + "kind-of": "6.0.2" } }, "is-data-descriptor": { @@ -525,7 +537,7 @@ "integrity": "sha512-jbRXy1FmtAoCjQkVmIVYwuuqDFUbaOeDjmed1tOGPrsMhtJA4rD9tkgA0F1qJ3gRFRXcHYVkdeaP50Q5rE/jLQ==", "dev": true, "requires": { - "kind-of": "^6.0.0" + "kind-of": "6.0.2" } }, "is-descriptor": { @@ -534,9 +546,9 @@ "integrity": "sha512-2eis5WqQGV7peooDyLmNEPUrps9+SXX5c9pL3xEB+4e9HnGuDa7mB7kHxHw4CbqS9k1T2hOH3miL8n8WtiYVtg==", "dev": true, "requires": { - "is-accessor-descriptor": "^1.0.0", - "is-data-descriptor": "^1.0.0", - "kind-of": "^6.0.2" + "is-accessor-descriptor": "1.0.0", + "is-data-descriptor": "1.0.0", + "kind-of": "6.0.2" } } } @@ -547,10 +559,10 @@ "integrity": "sha1-1USBHUKPmOsGpj3EAtJAPDKMOPc=", "dev": true, "requires": { - "extend-shallow": "^2.0.1", - "is-number": "^3.0.0", - "repeat-string": "^1.6.1", - "to-regex-range": "^2.1.0" + "extend-shallow": "2.0.1", + "is-number": "3.0.0", + "repeat-string": "1.6.1", + "to-regex-range": "2.1.1" }, "dependencies": { "extend-shallow": { @@ -559,7 +571,7 @@ "integrity": "sha1-Ua99YUrZqfYQ6huvu5idaxxWiQ8=", "dev": true, "requires": { - "is-extendable": "^0.1.0" + "is-extendable": "0.1.1" } } } @@ -576,7 +588,7 @@ "integrity": "sha1-QpD60n8T6Jvn8zeZxrxaCr//DRk=", "dev": true, "requires": { - "map-cache": "^0.2.2" + "map-cache": "0.2.2" } }, "fs.realpath": { @@ -597,12 +609,12 @@ "integrity": "sha512-MJTUg1kjuLeQCJ+ccE4Vpa6kKVXkPYJ2mOCQyUuKLcLQsdrMCpBPUi8qVE6+YuaJkozeA9NusTAw3hLr8Xe5EQ==", "dev": true, "requires": { - "fs.realpath": "^1.0.0", - "inflight": "^1.0.4", - "inherits": "2", - "minimatch": "^3.0.4", - "once": "^1.3.0", - "path-is-absolute": "^1.0.0" + "fs.realpath": "1.0.0", + "inflight": "1.0.6", + "inherits": "2.0.3", + "minimatch": "3.0.4", + "once": "1.4.0", + "path-is-absolute": "1.0.1" } }, "graceful-fs": { @@ -629,9 +641,9 @@ "integrity": "sha1-GLKB2lhbHFxR3vJMkw7SmgvmsXc=", "dev": true, "requires": { - "get-value": "^2.0.6", - "has-values": "^1.0.0", - "isobject": "^3.0.0" + "get-value": "2.0.6", + "has-values": "1.0.0", + "isobject": "3.0.1" } }, "has-values": { @@ -640,8 +652,8 @@ "integrity": "sha1-lbC2P+whRmGab+V/51Yo1aOe/k8=", "dev": true, "requires": { - "is-number": "^3.0.0", - "kind-of": "^4.0.0" + "is-number": "3.0.0", + "kind-of": "4.0.0" }, "dependencies": { "kind-of": { @@ -650,7 +662,7 @@ "integrity": "sha1-IIE989cSkosgc3hpGkUGb65y3Vc=", "dev": true, "requires": { - "is-buffer": "^1.1.5" + "is-buffer": "1.1.6" } } } @@ -667,8 +679,8 @@ "integrity": "sha1-Sb1jMdfQLQwJvJEKEHW6gWW1bfk=", "dev": true, "requires": { - "once": "^1.3.0", - "wrappy": "1" + "once": "1.4.0", + "wrappy": "1.0.2" } }, "inherits": { @@ -677,13 +689,62 @@ "integrity": "sha1-Yzwsg+PaQqUC9SRmAiSA9CCCYd4=", "dev": true }, + "ioredis": { + "version": "4.14.1", + "resolved": "https://registry.npmjs.org/ioredis/-/ioredis-4.14.1.tgz", + "integrity": "sha512-94W+X//GHM+1GJvDk6JPc+8qlM7Dul+9K+lg3/aHixPN7ZGkW6qlvX0DG6At9hWtH2v3B32myfZqWoANUJYGJA==", + "dev": true, + "requires": { + "cluster-key-slot": "1.1.0", + "debug": "4.1.1", + "denque": "1.4.1", + "lodash.defaults": "4.2.0", + "lodash.flatten": "4.4.0", + "redis-commands": "1.5.0", + "redis-errors": "1.2.0", + "redis-parser": "3.0.0", + "standard-as-callback": "2.0.1" + }, + "dependencies": { + "debug": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.1.1.tgz", + "integrity": "sha512-pYAIzeRo8J6KPEaJ0VWOh5Pzkbw/RetuzehGM7QRRX5he4fPHx2rdKMB256ehJCkX+XRQm16eZLqLNS8RSZXZw==", + "dev": true, + "requires": { + "ms": "2.1.2" + } + }, + "ms": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", + "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==", + "dev": true + }, + "redis-commands": { + "version": "1.5.0", + "resolved": "https://registry.npmjs.org/redis-commands/-/redis-commands-1.5.0.tgz", + "integrity": "sha512-6KxamqpZ468MeQC3bkWmCB1fp56XL64D4Kf0zJSwDZbVLLm7KFkoIcHrgRvQ+sk8dnhySs7+yBg94yIkAK7aJg==", + "dev": true + }, + "redis-parser": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/redis-parser/-/redis-parser-3.0.0.tgz", + "integrity": "sha1-tm2CjNyv5rS4pCin3vTGvKwxyLQ=", + "dev": true, + "requires": { + "redis-errors": "1.2.0" + } + } + } + }, "is-accessor-descriptor": { "version": "0.1.6", "resolved": "https://registry.npmjs.org/is-accessor-descriptor/-/is-accessor-descriptor-0.1.6.tgz", "integrity": "sha1-qeEss66Nh2cn7u84Q/igiXtcmNY=", "dev": true, "requires": { - "kind-of": "^3.0.2" + "kind-of": "3.2.2" }, "dependencies": { "kind-of": { @@ -692,7 +753,7 @@ "integrity": "sha1-MeohpzS6ubuw8yRm2JOupR5KPGQ=", "dev": true, "requires": { - "is-buffer": "^1.1.5" + "is-buffer": "1.1.6" } } } @@ -709,7 +770,7 @@ "integrity": "sha1-C17mSDiOLIYCgueT8YVv7D8wG1Y=", "dev": true, "requires": { - "kind-of": "^3.0.2" + "kind-of": "3.2.2" }, "dependencies": { "kind-of": { @@ -718,7 +779,7 @@ "integrity": "sha1-MeohpzS6ubuw8yRm2JOupR5KPGQ=", "dev": true, "requires": { - "is-buffer": "^1.1.5" + "is-buffer": "1.1.6" } } } @@ -729,9 +790,9 @@ "integrity": "sha512-avDYr0SB3DwO9zsMov0gKCESFYqCnE4hq/4z3TdUlukEy5t9C0YRq7HLrsN52NAcqXKaepeCD0n+B0arnVG3Hg==", "dev": true, "requires": { - "is-accessor-descriptor": "^0.1.6", - "is-data-descriptor": "^0.1.4", - "kind-of": "^5.0.0" + "is-accessor-descriptor": "0.1.6", + "is-data-descriptor": "0.1.4", + "kind-of": "5.1.0" }, "dependencies": { "kind-of": { @@ -754,7 +815,7 @@ "integrity": "sha1-JP1iAaR4LPUFYcgQJ2r8fRLXEZU=", "dev": true, "requires": { - "kind-of": "^3.0.2" + "kind-of": "3.2.2" }, "dependencies": { "kind-of": { @@ -763,7 +824,7 @@ "integrity": "sha1-MeohpzS6ubuw8yRm2JOupR5KPGQ=", "dev": true, "requires": { - "is-buffer": "^1.1.5" + "is-buffer": "1.1.6" } } } @@ -774,7 +835,7 @@ "integrity": "sha512-h5PpgXkWitc38BBMYawTYMWJHFZJVnBquFE57xFpjB8pJFiF6gZ+bU+WyI/yqXiFR5mdLsgYNaPe8uao6Uv9Og==", "dev": true, "requires": { - "isobject": "^3.0.1" + "isobject": "3.0.1" } }, "is-windows": { @@ -801,7 +862,7 @@ "integrity": "sha512-aKS4WQjPenRxiQsC93MNfjx+nbF4PAdYzmd/1JIj8HYzqfbu86beTuNgXDzPknWk0n0uARlyewZo4s++ES36Ow==", "dev": true, "requires": { - "minimist": "^1.2.0" + "minimist": "1.2.0" }, "dependencies": { "minimist": { @@ -824,9 +885,9 @@ "integrity": "sha512-fkpz8ejdnEMG3s37wGL07iSBDg99O9D5yflE9RGNH3hRdx9SOwYfnGYdZOUIZitN8E+E2vkq3MUMYMvPYl5ZZA==", "dev": true, "requires": { - "big.js": "^5.2.2", - "emojis-list": "^2.0.0", - "json5": "^1.0.1" + "big.js": "5.2.2", + "emojis-list": "2.1.0", + "json5": "1.0.1" } }, "lodash": { @@ -834,6 +895,18 @@ "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.11.tgz", "integrity": "sha512-cQKh8igo5QUhZ7lg38DYWAxMvjSAKG0A8wGSVimP07SIUEK2UO+arSRKbRZWtelMtN5V0Hkwh5ryOto/SshYIg==" }, + "lodash.defaults": { + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/lodash.defaults/-/lodash.defaults-4.2.0.tgz", + "integrity": "sha1-0JF4cW/+pN3p5ft7N/bwgCJ0WAw=", + "dev": true + }, + "lodash.flatten": { + "version": "4.4.0", + "resolved": "https://registry.npmjs.org/lodash.flatten/-/lodash.flatten-4.4.0.tgz", + "integrity": "sha1-8xwiIlqWMtK7+OSt2+8kCqdlph8=", + "dev": true + }, "map-cache": { "version": "0.2.2", "resolved": "https://registry.npmjs.org/map-cache/-/map-cache-0.2.2.tgz", @@ -846,7 +919,7 @@ "integrity": "sha1-7Nyo8TFE5mDxtb1B8S80edmN+48=", "dev": true, "requires": { - "object-visit": "^1.0.0" + "object-visit": "1.0.1" } }, "memory-fs": { @@ -855,8 +928,8 @@ "integrity": "sha1-OpoguEYlI+RHz7x+i7gO1me/xVI=", "dev": true, "requires": { - "errno": "^0.1.3", - "readable-stream": "^2.0.1" + "errno": "0.1.7", + "readable-stream": "2.3.6" } }, "micromatch": { @@ -865,19 +938,19 @@ "integrity": "sha512-MWikgl9n9M3w+bpsY3He8L+w9eF9338xRl8IAO5viDizwSzziFEyUzo2xrrloB64ADbTf8uA8vRqqttDTOmccg==", "dev": true, "requires": { - "arr-diff": "^4.0.0", - "array-unique": "^0.3.2", - "braces": "^2.3.1", - "define-property": "^2.0.2", - "extend-shallow": "^3.0.2", - "extglob": "^2.0.4", - "fragment-cache": "^0.2.1", - "kind-of": "^6.0.2", - "nanomatch": "^1.2.9", - "object.pick": "^1.3.0", - "regex-not": "^1.0.0", - "snapdragon": "^0.8.1", - "to-regex": "^3.0.2" + "arr-diff": "4.0.0", + "array-unique": "0.3.2", + "braces": "2.3.2", + "define-property": "2.0.2", + "extend-shallow": "3.0.2", + "extglob": "2.0.4", + "fragment-cache": "0.2.1", + "kind-of": "6.0.2", + "nanomatch": "1.2.13", + "object.pick": "1.3.0", + "regex-not": "1.0.2", + "snapdragon": "0.8.2", + "to-regex": "3.0.2" } }, "minimatch": { @@ -886,7 +959,7 @@ "integrity": "sha512-yJHVQEhyqPLUTgt9B83PXu6W3rx4MvvHvSUvToogpwoGDOUQ+yDrR0HRot+yOCdCO7u4hX3pWft6kWBBcqh0UA==", "dev": true, "requires": { - "brace-expansion": "^1.1.7" + "brace-expansion": "1.1.8" } }, "minimist": { @@ -901,8 +974,8 @@ "integrity": "sha512-8ZItLHeEgaqEvd5lYBXfm4EZSFCX29Jb9K+lAHhDKzReKBQKj3R+7NOF6tjqYi9t4oI8VUfaWITJQm86wnXGNQ==", "dev": true, "requires": { - "for-in": "^1.0.2", - "is-extendable": "^1.0.1" + "for-in": "1.0.2", + "is-extendable": "1.0.1" }, "dependencies": { "is-extendable": { @@ -911,7 +984,7 @@ "integrity": "sha512-arnXMxT1hhoKo9k1LZdmlNyJdDDfy2v0fXjFlmok4+i8ul/6WlbVge9bhM74OpNPQPMGUToDtz+KXa1PneJxOA==", "dev": true, "requires": { - "is-plain-object": "^2.0.4" + "is-plain-object": "2.0.4" } } } @@ -955,17 +1028,17 @@ "integrity": "sha512-fpoe2T0RbHwBTBUOftAfBPaDEi06ufaUai0mE6Yn1kacc3SnTErfb/h+X94VXzI64rKFHYImXSvdwGGCmwOqCA==", "dev": true, "requires": { - "arr-diff": "^4.0.0", - "array-unique": "^0.3.2", - "define-property": "^2.0.2", - "extend-shallow": "^3.0.2", - "fragment-cache": "^0.2.1", - "is-windows": "^1.0.2", - "kind-of": "^6.0.2", - "object.pick": "^1.3.0", - "regex-not": "^1.0.0", - "snapdragon": "^0.8.1", - "to-regex": "^3.0.1" + "arr-diff": "4.0.0", + "array-unique": "0.3.2", + "define-property": "2.0.2", + "extend-shallow": "3.0.2", + "fragment-cache": "0.2.1", + "is-windows": "1.0.2", + "kind-of": "6.0.2", + "object.pick": "1.3.0", + "regex-not": "1.0.2", + "snapdragon": "0.8.2", + "to-regex": "3.0.2" } }, "object-copy": { @@ -974,9 +1047,9 @@ "integrity": "sha1-fn2Fi3gb18mRpBupde04EnVOmYw=", "dev": true, "requires": { - "copy-descriptor": "^0.1.0", - "define-property": "^0.2.5", - "kind-of": "^3.0.3" + "copy-descriptor": "0.1.1", + "define-property": "0.2.5", + "kind-of": "3.2.2" }, "dependencies": { "define-property": { @@ -985,7 +1058,7 @@ "integrity": "sha1-w1se+RjsPJkPmlvFe+BKrOxcgRY=", "dev": true, "requires": { - "is-descriptor": "^0.1.0" + "is-descriptor": "0.1.6" } }, "kind-of": { @@ -994,7 +1067,7 @@ "integrity": "sha1-MeohpzS6ubuw8yRm2JOupR5KPGQ=", "dev": true, "requires": { - "is-buffer": "^1.1.5" + "is-buffer": "1.1.6" } } } @@ -1005,7 +1078,7 @@ "integrity": "sha1-95xEk68MU3e1n+OdOV5BBC3QRbs=", "dev": true, "requires": { - "isobject": "^3.0.0" + "isobject": "3.0.1" } }, "object.pick": { @@ -1014,7 +1087,7 @@ "integrity": "sha1-h6EKxMFpS9Lhy/U1kaZhQftd10c=", "dev": true, "requires": { - "isobject": "^3.0.1" + "isobject": "3.0.1" } }, "once": { @@ -1023,7 +1096,7 @@ "integrity": "sha1-WDsap3WWHUsROsF9nFC6753Xa9E=", "dev": true, "requires": { - "wrappy": "1" + "wrappy": "1.0.2" } }, "pascalcase": { @@ -1062,13 +1135,13 @@ "integrity": "sha512-tQtKA9WIAhBF3+VLAseyMqZeBjW0AHJoxOtYqSUZNJxauErmLbVm2FW1y+J/YA9dUrAC39ITejlZWhVIwawkKw==", "dev": true, "requires": { - "core-util-is": "~1.0.0", - "inherits": "~2.0.3", - "isarray": "~1.0.0", - "process-nextick-args": "~2.0.0", - "safe-buffer": "~5.1.1", - "string_decoder": "~1.1.1", - "util-deprecate": "~1.0.1" + "core-util-is": "1.0.2", + "inherits": "2.0.3", + "isarray": "1.0.0", + "process-nextick-args": "2.0.0", + "safe-buffer": "5.1.2", + "string_decoder": "1.1.1", + "util-deprecate": "1.0.2" } }, "redis": { @@ -1076,9 +1149,9 @@ "resolved": "https://registry.npmjs.org/redis/-/redis-2.8.0.tgz", "integrity": "sha512-M1OkonEQwtRmZv4tEWF2VgpG0JWJ8Fv1PhlgT5+B+uNq2cA3Rt1Yt/ryoR+vQNOQcIEgdCdfH0jr3bDpihAw1A==", "requires": { - "double-ended-queue": "^2.1.0-0", - "redis-commands": "^1.2.0", - "redis-parser": "^2.6.0" + "double-ended-queue": "2.1.0-0", + "redis-commands": "1.3.1", + "redis-parser": "2.6.0" } }, "redis-commands": { @@ -1086,6 +1159,12 @@ "resolved": "https://registry.npmjs.org/redis-commands/-/redis-commands-1.3.1.tgz", "integrity": "sha1-gdgm9F+pyLIBH0zXoP5ZfSQdRCs=" }, + "redis-errors": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/redis-errors/-/redis-errors-1.2.0.tgz", + "integrity": "sha1-62LSrbFeTq9GEMBK/hUpOEJQq60=", + "dev": true + }, "redis-parser": { "version": "2.6.0", "resolved": "https://registry.npmjs.org/redis-parser/-/redis-parser-2.6.0.tgz", @@ -1097,8 +1176,8 @@ "integrity": "sha512-J6SDjUgDxQj5NusnOtdFxDwN/+HWykR8GELwctJ7mdqhcyy1xEc4SRFHUXvxTp661YaVKAjfRLZ9cCqS6tn32A==", "dev": true, "requires": { - "extend-shallow": "^3.0.2", - "safe-regex": "^1.1.0" + "extend-shallow": "3.0.2", + "safe-regex": "1.1.0" } }, "repeat-element": { @@ -1137,7 +1216,7 @@ "integrity": "sha1-QKNmnzsHfR6UPURinhV91IAjvy4=", "dev": true, "requires": { - "ret": "~0.1.10" + "ret": "0.1.15" } }, "semver": { @@ -1152,10 +1231,10 @@ "integrity": "sha512-hw0yxk9GT/Hr5yJEYnHNKYXkIA8mVJgd9ditYZCe16ZczcaELYYcfvaXesNACk2O8O0nTiPQcQhGUQj8JLzeeg==", "dev": true, "requires": { - "extend-shallow": "^2.0.1", - "is-extendable": "^0.1.1", - "is-plain-object": "^2.0.3", - "split-string": "^3.0.1" + "extend-shallow": "2.0.1", + "is-extendable": "0.1.1", + "is-plain-object": "2.0.4", + "split-string": "3.1.0" }, "dependencies": { "extend-shallow": { @@ -1164,7 +1243,7 @@ "integrity": "sha1-Ua99YUrZqfYQ6huvu5idaxxWiQ8=", "dev": true, "requires": { - "is-extendable": "^0.1.0" + "is-extendable": "0.1.1" } } } @@ -1175,11 +1254,11 @@ "integrity": "sha512-1m8FHuNTrJ37pXfjfhjmv1/jBw2eYZIWibQ1pH2EGYhn8TcPOSK6zjNbhF20sZ4Gc0XSIlSaSGupnYRKkk1pKQ==", "dev": true, "requires": { - "should-equal": "^2.0.0", - "should-format": "^3.0.3", - "should-type": "^1.4.0", - "should-type-adaptors": "^1.0.1", - "should-util": "^1.0.0" + "should-equal": "2.0.0", + "should-format": "3.0.3", + "should-type": "1.4.0", + "should-type-adaptors": "1.0.1", + "should-util": "1.0.0" } }, "should-equal": { @@ -1188,7 +1267,7 @@ "integrity": "sha512-ZP36TMrK9euEuWQYBig9W55WPC7uo37qzAEmbjHz4gfyuXrEUgF8cUvQVO+w+d3OMfPvSRQJ22lSm8MQJ43LTA==", "dev": true, "requires": { - "should-type": "^1.4.0" + "should-type": "1.4.0" } }, "should-format": { @@ -1197,8 +1276,8 @@ "integrity": "sha1-m/yPdPo5IFxT04w01xcwPidxJPE=", "dev": true, "requires": { - "should-type": "^1.3.0", - "should-type-adaptors": "^1.0.1" + "should-type": "1.4.0", + "should-type-adaptors": "1.0.1" } }, "should-type": { @@ -1213,8 +1292,8 @@ "integrity": "sha1-7+VVPN9oz/ZuXF9RtxLcNRx3vqo=", "dev": true, "requires": { - "should-type": "^1.3.0", - "should-util": "^1.0.0" + "should-type": "1.4.0", + "should-util": "1.0.0" } }, "should-util": { @@ -1229,14 +1308,14 @@ "integrity": "sha512-FtyOnWN/wCHTVXOMwvSv26d+ko5vWlIDD6zoUJ7LW8vh+ZBC8QdljveRP+crNrtBwioEUWy/4dMtbBjA4ioNlg==", "dev": true, "requires": { - "base": "^0.11.1", - "debug": "^2.2.0", - "define-property": "^0.2.5", - "extend-shallow": "^2.0.1", - "map-cache": "^0.2.2", - "source-map": "^0.5.6", - "source-map-resolve": "^0.5.0", - "use": "^3.1.0" + "base": "0.11.2", + "debug": "2.6.9", + "define-property": "0.2.5", + "extend-shallow": "2.0.1", + "map-cache": "0.2.2", + "source-map": "0.5.7", + "source-map-resolve": "0.5.2", + "use": "3.1.1" }, "dependencies": { "debug": { @@ -1254,7 +1333,7 @@ "integrity": "sha1-w1se+RjsPJkPmlvFe+BKrOxcgRY=", "dev": true, "requires": { - "is-descriptor": "^0.1.0" + "is-descriptor": "0.1.6" } }, "extend-shallow": { @@ -1263,7 +1342,7 @@ "integrity": "sha1-Ua99YUrZqfYQ6huvu5idaxxWiQ8=", "dev": true, "requires": { - "is-extendable": "^0.1.0" + "is-extendable": "0.1.1" } } } @@ -1274,9 +1353,9 @@ "integrity": "sha512-O27l4xaMYt/RSQ5TR3vpWCAB5Kb/czIcqUFOM/C4fYcLnbZUc1PkjTAMjof2pBWaSTwOUd6qUHcFGVGj7aIwnw==", "dev": true, "requires": { - "define-property": "^1.0.0", - "isobject": "^3.0.0", - "snapdragon-util": "^3.0.1" + "define-property": "1.0.0", + "isobject": "3.0.1", + "snapdragon-util": "3.0.1" }, "dependencies": { "define-property": { @@ -1285,7 +1364,7 @@ "integrity": "sha1-dp66rz9KY6rTr56NMEybvnm/sOY=", "dev": true, "requires": { - "is-descriptor": "^1.0.0" + "is-descriptor": "1.0.2" } }, "is-accessor-descriptor": { @@ -1294,7 +1373,7 @@ "integrity": "sha512-m5hnHTkcVsPfqx3AKlyttIPb7J+XykHvJP2B9bZDjlhLIoEq4XoK64Vg7boZlVWYK6LUY94dYPEE7Lh0ZkZKcQ==", "dev": true, "requires": { - "kind-of": "^6.0.0" + "kind-of": "6.0.2" } }, "is-data-descriptor": { @@ -1303,7 +1382,7 @@ "integrity": "sha512-jbRXy1FmtAoCjQkVmIVYwuuqDFUbaOeDjmed1tOGPrsMhtJA4rD9tkgA0F1qJ3gRFRXcHYVkdeaP50Q5rE/jLQ==", "dev": true, "requires": { - "kind-of": "^6.0.0" + "kind-of": "6.0.2" } }, "is-descriptor": { @@ -1312,9 +1391,9 @@ "integrity": "sha512-2eis5WqQGV7peooDyLmNEPUrps9+SXX5c9pL3xEB+4e9HnGuDa7mB7kHxHw4CbqS9k1T2hOH3miL8n8WtiYVtg==", "dev": true, "requires": { - "is-accessor-descriptor": "^1.0.0", - "is-data-descriptor": "^1.0.0", - "kind-of": "^6.0.2" + "is-accessor-descriptor": "1.0.0", + "is-data-descriptor": "1.0.0", + "kind-of": "6.0.2" } } } @@ -1325,7 +1404,7 @@ "integrity": "sha512-mbKkMdQKsjX4BAL4bRYTj21edOf8cN7XHdYUJEe+Zn99hVEYcMvKPct1IqNe7+AZPirn8BCDOQBHQZknqmKlZQ==", "dev": true, "requires": { - "kind-of": "^3.2.0" + "kind-of": "3.2.2" }, "dependencies": { "kind-of": { @@ -1334,7 +1413,7 @@ "integrity": "sha1-MeohpzS6ubuw8yRm2JOupR5KPGQ=", "dev": true, "requires": { - "is-buffer": "^1.1.5" + "is-buffer": "1.1.6" } } } @@ -1351,11 +1430,11 @@ "integrity": "sha512-MjqsvNwyz1s0k81Goz/9vRBe9SZdB09Bdw+/zYyO+3CuPk6fouTaxscHkgtE8jKvf01kVfl8riHzERQ/kefaSA==", "dev": true, "requires": { - "atob": "^2.1.1", - "decode-uri-component": "^0.2.0", - "resolve-url": "^0.2.1", - "source-map-url": "^0.4.0", - "urix": "^0.1.0" + "atob": "2.1.2", + "decode-uri-component": "0.2.0", + "resolve-url": "0.2.1", + "source-map-url": "0.4.0", + "urix": "0.1.0" } }, "source-map-url": { @@ -1370,17 +1449,23 @@ "integrity": "sha512-NzNVhJDYpwceVVii8/Hu6DKfD2G+NrQHlS/V/qgv763EYudVwEcMQNxd2lh+0VrUByXN/oJkl5grOhYWvQUYiw==", "dev": true, "requires": { - "extend-shallow": "^3.0.0" + "extend-shallow": "3.0.2" } }, + "standard-as-callback": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/standard-as-callback/-/standard-as-callback-2.0.1.tgz", + "integrity": "sha512-NQOxSeB8gOI5WjSaxjBgog2QFw55FV8TkS6Y07BiB3VJ8xNTvUYm0wl0s8ObgQ5NhdpnNfigMIKjgPESzgr4tg==", + "dev": true + }, "static-extend": { "version": "0.1.2", "resolved": "https://registry.npmjs.org/static-extend/-/static-extend-0.1.2.tgz", "integrity": "sha1-YICcOcv/VTNyJv1eC1IPNB8ftcY=", "dev": true, "requires": { - "define-property": "^0.2.5", - "object-copy": "^0.1.0" + "define-property": "0.2.5", + "object-copy": "0.1.0" }, "dependencies": { "define-property": { @@ -1389,7 +1474,7 @@ "integrity": "sha1-w1se+RjsPJkPmlvFe+BKrOxcgRY=", "dev": true, "requires": { - "is-descriptor": "^0.1.0" + "is-descriptor": "0.1.6" } } } @@ -1400,7 +1485,7 @@ "integrity": "sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==", "dev": true, "requires": { - "safe-buffer": "~5.1.0" + "safe-buffer": "5.1.2" } }, "supports-color": { @@ -1409,7 +1494,7 @@ "integrity": "sha512-rKC3+DyXWgK0ZLKwmRsrkyHVZAjNkfzeehuFWdGGcqGDTZFH73+RH6S/RDAAxl9GusSjZSUWYLmT9N5pzXFOXQ==", "dev": true, "requires": { - "has-flag": "^2.0.0" + "has-flag": "2.0.0" } }, "tapable": { @@ -1424,7 +1509,7 @@ "integrity": "sha1-KXWIt7Dn4KwI4E5nL4XB9JmeF68=", "dev": true, "requires": { - "kind-of": "^3.0.2" + "kind-of": "3.2.2" }, "dependencies": { "kind-of": { @@ -1433,7 +1518,7 @@ "integrity": "sha1-MeohpzS6ubuw8yRm2JOupR5KPGQ=", "dev": true, "requires": { - "is-buffer": "^1.1.5" + "is-buffer": "1.1.6" } } } @@ -1444,10 +1529,10 @@ "integrity": "sha512-FWtleNAtZ/Ki2qtqej2CXTOayOH9bHDQF+Q48VpWyDXjbYxA4Yz8iDB31zXOBUlOHHKidDbqGVrTUvQMPmBGBw==", "dev": true, "requires": { - "define-property": "^2.0.2", - "extend-shallow": "^3.0.2", - "regex-not": "^1.0.2", - "safe-regex": "^1.1.0" + "define-property": "2.0.2", + "extend-shallow": "3.0.2", + "regex-not": "1.0.2", + "safe-regex": "1.1.0" } }, "to-regex-range": { @@ -1456,8 +1541,8 @@ "integrity": "sha1-fIDBe53+vlmeJzZ+DU3VWQFB2zg=", "dev": true, "requires": { - "is-number": "^3.0.0", - "repeat-string": "^1.6.1" + "is-number": "3.0.0", + "repeat-string": "1.6.1" } }, "ts-loader": { @@ -1466,11 +1551,11 @@ "integrity": "sha512-pHwZFkZioL7Yi2su0bhW2/djxZ+0iGat1cxlAif4Eg9j5znVYuWGtW0YYY/5w8W+IzLcAlD5KwJDrs5unUKIRA==", "dev": true, "requires": { - "chalk": "^2.3.0", - "enhanced-resolve": "^4.0.0", - "loader-utils": "^1.0.2", - "micromatch": "^3.1.4", - "semver": "^5.0.1" + "chalk": "2.4.2", + "enhanced-resolve": "4.1.0", + "loader-utils": "1.2.3", + "micromatch": "3.1.10", + "semver": "5.7.0" } }, "typescript": { @@ -1485,10 +1570,10 @@ "integrity": "sha1-XHHDTLW61dzr4+oM0IIHulqhrqQ=", "dev": true, "requires": { - "arr-union": "^3.1.0", - "get-value": "^2.0.6", - "is-extendable": "^0.1.1", - "set-value": "^0.4.3" + "arr-union": "3.1.0", + "get-value": "2.0.6", + "is-extendable": "0.1.1", + "set-value": "0.4.3" }, "dependencies": { "extend-shallow": { @@ -1497,7 +1582,7 @@ "integrity": "sha1-Ua99YUrZqfYQ6huvu5idaxxWiQ8=", "dev": true, "requires": { - "is-extendable": "^0.1.0" + "is-extendable": "0.1.1" } }, "set-value": { @@ -1506,10 +1591,10 @@ "integrity": "sha1-fbCPnT0i3H945Trzw79GZuzfzPE=", "dev": true, "requires": { - "extend-shallow": "^2.0.1", - "is-extendable": "^0.1.1", - "is-plain-object": "^2.0.1", - "to-object-path": "^0.3.0" + "extend-shallow": "2.0.1", + "is-extendable": "0.1.1", + "is-plain-object": "2.0.4", + "to-object-path": "0.3.0" } } } @@ -1520,8 +1605,8 @@ "integrity": "sha1-g3aHP30jNRef+x5vw6jtDfyKtVk=", "dev": true, "requires": { - "has-value": "^0.3.1", - "isobject": "^3.0.0" + "has-value": "0.3.1", + "isobject": "3.0.1" }, "dependencies": { "has-value": { @@ -1530,9 +1615,9 @@ "integrity": "sha1-ex9YutpiyoJ+wKIHgCVlSEWZXh8=", "dev": true, "requires": { - "get-value": "^2.0.3", - "has-values": "^0.1.4", - "isobject": "^2.0.0" + "get-value": "2.0.6", + "has-values": "0.1.4", + "isobject": "2.1.0" }, "dependencies": { "isobject": {