-
Notifications
You must be signed in to change notification settings - Fork 1.9k
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Fix monitor mode not working with IPv6, sockets or lua scripts
- Loading branch information
Ruben Bridgewater
committed
Jan 12, 2017
1 parent
4b27f79
commit b9540d4
Showing
5 changed files
with
220 additions
and
187 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,212 @@ | ||
'use strict'; | ||
|
||
var assert = require('assert'); | ||
var config = require('../lib/config'); | ||
var helper = require('../helper'); | ||
var utils = require('../../lib/utils'); | ||
var redis = config.redis; | ||
|
||
describe("The 'monitor' method", function () { | ||
|
||
helper.allTests(function (parser, ip, args) { | ||
|
||
var client; | ||
|
||
afterEach(function () { | ||
client.end(true); | ||
}); | ||
|
||
beforeEach(function (done) { | ||
client = redis.createClient.apply(null, args); | ||
client.once('connect', function () { | ||
client.flushdb(done); | ||
}); | ||
}); | ||
|
||
it('monitors commands on all redis clients and works in the correct order', function (done) { | ||
var monitorClient = redis.createClient.apply(null, args); | ||
var responses = [ | ||
['mget', 'some', 'keys', 'foo', 'bar'], | ||
['set', 'json', '{"foo":"123","bar":"sdflkdfsjk","another":false}'], | ||
['eval', "return redis.call('set', 'sha', 'test')", '0'], | ||
['set', 'sha', 'test'], | ||
['get', 'baz'], | ||
['set', 'foo', 'bar" "s are " " good!"'], | ||
['mget', 'foo', 'baz'], | ||
['subscribe', 'foo', 'baz'] | ||
]; | ||
var end = helper.callFuncAfter(done, 5); | ||
|
||
monitorClient.set('foo', 'bar'); | ||
monitorClient.flushdb(); | ||
monitorClient.monitor(function (err, res) { | ||
assert.strictEqual(res, 'OK'); | ||
client.mget('some', 'keys', 'foo', 'bar'); | ||
client.set('json', JSON.stringify({ | ||
foo: '123', | ||
bar: 'sdflkdfsjk', | ||
another: false | ||
})); | ||
client.eval("return redis.call('set', 'sha', 'test')", 0); | ||
monitorClient.get('baz', function (err, res) { | ||
assert.strictEqual(res, null); | ||
end(err); | ||
}); | ||
monitorClient.set('foo', 'bar" "s are " " good!"', function (err, res) { | ||
assert.strictEqual(res, 'OK'); | ||
end(err); | ||
}); | ||
monitorClient.mget('foo', 'baz', function (err, res) { | ||
assert.strictEqual(res[0], 'bar" "s are " " good!"'); | ||
assert.strictEqual(res[1], null); | ||
end(err); | ||
}); | ||
monitorClient.subscribe('foo', 'baz', function (err, res) { | ||
// The return value might change in v.3 | ||
// assert.strictEqual(res, 'baz'); | ||
// TODO: Fix the return value of subscribe calls | ||
end(err); | ||
}); | ||
}); | ||
|
||
monitorClient.on('monitor', function (time, args, rawOutput) { | ||
assert.strictEqual(monitorClient.monitoring, true); | ||
assert.deepEqual(args, responses.shift()); | ||
assert(utils.monitor_regex.test(rawOutput), rawOutput); | ||
if (responses.length === 0) { | ||
monitorClient.quit(end); | ||
} | ||
}); | ||
}); | ||
|
||
it('monitors returns strings in the rawOutput even with return_buffers activated', function (done) { | ||
var monitorClient = redis.createClient({ | ||
return_buffers: true, | ||
path: '/tmp/redis.sock' | ||
}); | ||
|
||
monitorClient.MONITOR(function (err, res) { | ||
assert.strictEqual(monitorClient.monitoring, true); | ||
assert.strictEqual(res.inspect(), new Buffer('OK').inspect()); | ||
monitorClient.mget('hello', new Buffer('world')); | ||
}); | ||
|
||
monitorClient.on('monitor', function (time, args, rawOutput) { | ||
assert.strictEqual(typeof rawOutput, 'string'); | ||
assert(utils.monitor_regex.test(rawOutput), rawOutput); | ||
assert.deepEqual(args, ['mget', 'hello', 'world']); | ||
// Quit immediatly ends monitoring mode and therefore does not stream back the quit command | ||
monitorClient.quit(done); | ||
}); | ||
}); | ||
|
||
it('monitors reconnects properly and works with the offline queue', function (done) { | ||
var called = false; | ||
client.MONITOR(helper.isString('OK')); | ||
client.mget('hello', 'world'); | ||
client.on('monitor', function (time, args, rawOutput) { | ||
assert.strictEqual(client.monitoring, true); | ||
assert(utils.monitor_regex.test(rawOutput), rawOutput); | ||
assert.deepEqual(args, ['mget', 'hello', 'world']); | ||
if (called) { | ||
// End after a reconnect | ||
return done(); | ||
} | ||
client.stream.destroy(); | ||
client.mget('hello', 'world'); | ||
called = true; | ||
}); | ||
}); | ||
|
||
it('monitors reconnects properly and works with the offline queue in a batch statement', function (done) { | ||
var called = false; | ||
var multi = client.batch(); | ||
multi.MONITOR(helper.isString('OK')); | ||
multi.mget('hello', 'world'); | ||
multi.exec(function (err, res) { | ||
assert.deepEqual(res, ['OK', [null, null]]); | ||
}); | ||
client.on('monitor', function (time, args, rawOutput) { | ||
assert.strictEqual(client.monitoring, true); | ||
assert(utils.monitor_regex.test(rawOutput), rawOutput); | ||
assert.deepEqual(args, ['mget', 'hello', 'world']); | ||
if (called) { | ||
// End after a reconnect | ||
return done(); | ||
} | ||
client.stream.destroy(); | ||
client.mget('hello', 'world'); | ||
called = true; | ||
}); | ||
}); | ||
|
||
it('monitor activates even if the command could not be processed properly after a reconnect', function (done) { | ||
client.MONITOR(function (err, res) { | ||
assert.strictEqual(err.code, 'UNCERTAIN_STATE'); | ||
}); | ||
client.on('error', function (err) {}); // Ignore error here | ||
client.stream.destroy(); | ||
var end = helper.callFuncAfter(done, 2); | ||
client.on('monitor', function (time, args, rawOutput) { | ||
assert.strictEqual(client.monitoring, true); | ||
end(); | ||
}); | ||
client.on('reconnecting', function () { | ||
client.get('foo', function (err, res) { | ||
assert(!err); | ||
assert.strictEqual(client.monitoring, true); | ||
end(); | ||
}); | ||
}); | ||
}); | ||
|
||
it('monitors works in combination with the pub sub mode and the offline queue', function (done) { | ||
var responses = [ | ||
['subscribe', '/foo', '/bar'], | ||
['unsubscribe', '/bar'], | ||
['get', 'foo'], | ||
['subscribe', '/foo'], | ||
['subscribe', 'baz'], | ||
['unsubscribe', 'baz'], | ||
['publish', '/foo', 'hello world'] | ||
]; | ||
var pub = redis.createClient(); | ||
pub.on('ready', function () { | ||
client.MONITOR(function (err, res) { | ||
assert.strictEqual(res, 'OK'); | ||
pub.get('foo', helper.isNull()); | ||
}); | ||
client.subscribe('/foo', '/bar'); | ||
client.unsubscribe('/bar'); | ||
setTimeout(function () { | ||
client.stream.destroy(); | ||
client.once('ready', function () { | ||
pub.publish('/foo', 'hello world'); | ||
}); | ||
client.set('foo', 'bar', helper.isError()); | ||
client.subscribe('baz'); | ||
client.unsubscribe('baz'); | ||
}, 150); | ||
var called = false; | ||
client.on('monitor', function (time, args, rawOutput) { | ||
assert.deepEqual(args, responses.shift()); | ||
assert(utils.monitor_regex.test(rawOutput), rawOutput); | ||
if (responses.length === 0) { | ||
// The publish is called right after the reconnect and the monitor is called before the message is emitted. | ||
// Therefore we have to wait till the next tick | ||
process.nextTick(function () { | ||
assert(called); | ||
client.quit(done); | ||
pub.end(false); | ||
}); | ||
} | ||
}); | ||
client.on('message', function (channel, msg) { | ||
assert.strictEqual(channel, '/foo'); | ||
assert.strictEqual(msg, 'hello world'); | ||
called = true; | ||
}); | ||
}); | ||
}); | ||
}); | ||
}); |
Oops, something went wrong.