You've already forked node-redis
mirror of
https://github.com/redis/node-redis.git
synced 2025-08-04 15:02:09 +03:00
Add more tests
Add execution order tests Fix flaky test Add utils tests Improve other tests
This commit is contained in:
@@ -63,11 +63,16 @@ describe("The 'batch' method", function () {
|
|||||||
client.end(true);
|
client.end(true);
|
||||||
});
|
});
|
||||||
|
|
||||||
it("returns an empty array", function (done) {
|
it("returns an empty array and keep the execution order in takt", function (done) {
|
||||||
|
var called = false;
|
||||||
|
client.set('foo', 'bar', function (err, res) {
|
||||||
|
called = true;
|
||||||
|
});
|
||||||
var batch = client.batch();
|
var batch = client.batch();
|
||||||
batch.exec(function (err, res) {
|
batch.exec(function (err, res) {
|
||||||
assert.strictEqual(err, null);
|
assert.strictEqual(err, null);
|
||||||
assert.strictEqual(res.length, 0);
|
assert.strictEqual(res.length, 0);
|
||||||
|
assert(called);
|
||||||
done();
|
done();
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
@@ -328,10 +333,11 @@ describe("The 'batch' method", function () {
|
|||||||
.exec(done);
|
.exec(done);
|
||||||
});
|
});
|
||||||
|
|
||||||
it("should work without any callback", function (done) {
|
it("should work without any callback or arguments", function (done) {
|
||||||
var batch = client.batch();
|
var batch = client.batch();
|
||||||
batch.set("baz", "binary");
|
batch.set("baz", "binary");
|
||||||
batch.set("foo", "bar");
|
batch.set("foo", "bar");
|
||||||
|
batch.ping();
|
||||||
batch.exec();
|
batch.exec();
|
||||||
|
|
||||||
client.get('foo', helper.isString('bar', done));
|
client.get('foo', helper.isString('bar', done));
|
||||||
|
@@ -66,14 +66,21 @@ describe("The 'set' method", function () {
|
|||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
describe("with undefined 'key' and missing 'value' parameter", function () {
|
describe("reports an error with invalid parameters", function () {
|
||||||
it("reports an error", function (done) {
|
it("undefined 'key' and missing 'value' parameter", function (done) {
|
||||||
client.set(undefined, function (err, res) {
|
client.set(undefined, function (err, res) {
|
||||||
helper.isError()(err, null);
|
helper.isError()(err, null);
|
||||||
assert.equal(err.command, 'SET');
|
assert.equal(err.command, 'SET');
|
||||||
done();
|
done();
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
|
it("empty array as second parameter", function (done) {
|
||||||
|
client.set('foo', [], function (err, res) {
|
||||||
|
assert.strictEqual(err.message, "ERR wrong number of arguments for 'set' command");
|
||||||
|
done();
|
||||||
|
});
|
||||||
|
});
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
|
@@ -136,13 +136,14 @@ describe("connection tests", function () {
|
|||||||
var time = Date.now();
|
var time = Date.now();
|
||||||
client = redis.createClient({
|
client = redis.createClient({
|
||||||
parser: parser,
|
parser: parser,
|
||||||
host: '192.168.74.167', // Should be auto detected as ipv4
|
// Auto detect ipv4 and use non routable ip to trigger the timeout
|
||||||
|
host: '10.255.255.1',
|
||||||
connect_timeout: connect_timeout
|
connect_timeout: connect_timeout
|
||||||
});
|
});
|
||||||
process.nextTick(function() {
|
process.nextTick(function() {
|
||||||
assert(client.stream._events.timeout);
|
assert.strictEqual(client.stream.listeners('timeout').length, 1);
|
||||||
});
|
});
|
||||||
assert.strictEqual(client.address, '192.168.74.167:6379');
|
assert.strictEqual(client.address, '10.255.255.1:6379');
|
||||||
assert.strictEqual(client.connection_options.family, 4);
|
assert.strictEqual(client.connection_options.family, 4);
|
||||||
|
|
||||||
client.on("reconnecting", function (params) {
|
client.on("reconnecting", function (params) {
|
||||||
@@ -151,8 +152,8 @@ describe("connection tests", function () {
|
|||||||
|
|
||||||
client.on('error', function(err) {
|
client.on('error', function(err) {
|
||||||
assert(/Redis connection in broken state: connection timeout.*?exceeded./.test(err.message));
|
assert(/Redis connection in broken state: connection timeout.*?exceeded./.test(err.message));
|
||||||
assert(Date.now() - time < connect_timeout + 50);
|
assert(Date.now() - time < connect_timeout + 25);
|
||||||
assert(Date.now() - time >= connect_timeout - 50); // Somehow this is triggered to early at times
|
assert(Date.now() - time >= connect_timeout - 3); // Timers sometimes trigger early (e.g. 1ms to early)
|
||||||
done();
|
done();
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
@@ -165,7 +166,7 @@ describe("connection tests", function () {
|
|||||||
assert.strictEqual(client.address, '2001:db8::ff00:42:8329:6379');
|
assert.strictEqual(client.address, '2001:db8::ff00:42:8329:6379');
|
||||||
assert.strictEqual(client.connection_options.family, 6);
|
assert.strictEqual(client.connection_options.family, 6);
|
||||||
process.nextTick(function() {
|
process.nextTick(function() {
|
||||||
assert.strictEqual(client.stream._events.timeout, undefined);
|
assert.strictEqual(client.stream.listeners('timeout').length, 0);
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
@@ -179,7 +180,7 @@ describe("connection tests", function () {
|
|||||||
});
|
});
|
||||||
client.on('connect', function () {
|
client.on('connect', function () {
|
||||||
assert.strictEqual(client.stream._idleTimeout, -1);
|
assert.strictEqual(client.stream._idleTimeout, -1);
|
||||||
assert.strictEqual(client.stream._events.timeout, undefined);
|
assert.strictEqual(client.stream.listeners('timeout').length, 0);
|
||||||
client.on('ready', done);
|
client.on('ready', done);
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
@@ -241,6 +241,7 @@ describe("The 'multi' method", function () {
|
|||||||
multi1.set("m1", "123");
|
multi1.set("m1", "123");
|
||||||
multi1.get('m1');
|
multi1.get('m1');
|
||||||
multi2.get('m2');
|
multi2.get('m2');
|
||||||
|
multi2.ping();
|
||||||
|
|
||||||
multi1.exec(end);
|
multi1.exec(end);
|
||||||
multi2.exec(function(err, res) {
|
multi2.exec(function(err, res) {
|
||||||
@@ -538,7 +539,7 @@ describe("The 'multi' method", function () {
|
|||||||
client.get('foo', helper.isString('bar', done));
|
client.get('foo', helper.isString('bar', done));
|
||||||
});
|
});
|
||||||
|
|
||||||
it("should not use a transaction with exec_atomic if only no command is used", function () {
|
it("should not use a transaction with exec_atomic if no command is used", function () {
|
||||||
var multi = client.multi();
|
var multi = client.multi();
|
||||||
var test = false;
|
var test = false;
|
||||||
multi.exec_batch = function () {
|
multi.exec_batch = function () {
|
||||||
|
@@ -423,6 +423,41 @@ describe("The node_redis client", function () {
|
|||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
|
describe('execution order / fire query while loading', function () {
|
||||||
|
it('keep execution order for commands that may fire while redis is still loading', function (done) {
|
||||||
|
client = redis.createClient.apply(null, args);
|
||||||
|
var fired = false;
|
||||||
|
client.set('foo', 'bar', function (err, res) {
|
||||||
|
assert(fired === false);
|
||||||
|
done();
|
||||||
|
});
|
||||||
|
client.info(function (err, res) {
|
||||||
|
fired = true;
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should fire early', function (done) {
|
||||||
|
client = redis.createClient.apply(null, args);
|
||||||
|
var fired = false;
|
||||||
|
client.info(function (err, res) {
|
||||||
|
fired = true;
|
||||||
|
});
|
||||||
|
client.set('foo', 'bar', function (err, res) {
|
||||||
|
assert(fired);
|
||||||
|
done();
|
||||||
|
});
|
||||||
|
assert.strictEqual(client.offline_queue.length, 1);
|
||||||
|
assert.strictEqual(client.command_queue.length, 1);
|
||||||
|
client.on('connect', function () {
|
||||||
|
assert.strictEqual(client.offline_queue.length, 1);
|
||||||
|
assert.strictEqual(client.command_queue.length, 1);
|
||||||
|
});
|
||||||
|
client.on('ready', function () {
|
||||||
|
assert.strictEqual(client.offline_queue.length, 0);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
describe('socket_nodelay', function () {
|
describe('socket_nodelay', function () {
|
||||||
describe('true', function () {
|
describe('true', function () {
|
||||||
var args = config.configureClient(parser, ip, {
|
var args = config.configureClient(parser, ip, {
|
||||||
|
@@ -109,6 +109,25 @@ describe("rename commands", function () {
|
|||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
|
it("should also work prefixed commands", function (done) {
|
||||||
|
if (helper.redisProcess().spawnFailed()) this.skip();
|
||||||
|
|
||||||
|
client.end(true);
|
||||||
|
client = redis.createClient({
|
||||||
|
rename_commands: {
|
||||||
|
set: '807081f5afa96845a02816a28b7258c3'
|
||||||
|
},
|
||||||
|
parser: parser,
|
||||||
|
prefix: 'baz'
|
||||||
|
});
|
||||||
|
client.set('foo', 'bar');
|
||||||
|
client.keys('*', function(err, reply) {
|
||||||
|
assert.strictEqual(reply[0], 'bazfoo');
|
||||||
|
assert.strictEqual(err, null);
|
||||||
|
done();
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
|
129
test/utils.spec.js
Normal file
129
test/utils.spec.js
Normal file
@@ -0,0 +1,129 @@
|
|||||||
|
'use strict';
|
||||||
|
|
||||||
|
var assert = require('assert');
|
||||||
|
var Queue = require('double-ended-queue');
|
||||||
|
var utils = require('../lib/utils');
|
||||||
|
|
||||||
|
describe('utils.js', function () {
|
||||||
|
|
||||||
|
describe('clone', function () {
|
||||||
|
it('ignore the object prototype and clone a nested array / object', function () {
|
||||||
|
var obj = {
|
||||||
|
a: [null, 'foo', ['bar'], {
|
||||||
|
"I'm special": true
|
||||||
|
}],
|
||||||
|
number: 5,
|
||||||
|
fn: function noop () {}
|
||||||
|
};
|
||||||
|
var clone = utils.clone(obj);
|
||||||
|
assert.deepEqual(clone, obj);
|
||||||
|
assert.strictEqual(obj.fn, clone.fn);
|
||||||
|
assert(typeof clone.fn === 'function');
|
||||||
|
});
|
||||||
|
|
||||||
|
it('replace faulty values with an empty object as return value', function () {
|
||||||
|
var a = utils.clone();
|
||||||
|
var b = utils.clone(null);
|
||||||
|
assert.strictEqual(Object.keys(a).length, 0);
|
||||||
|
assert.strictEqual(Object.keys(b).length, 0);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('throws on circular data', function () {
|
||||||
|
try {
|
||||||
|
var a = {};
|
||||||
|
a.b = a;
|
||||||
|
utils.clone(a);
|
||||||
|
throw new Error('failed');
|
||||||
|
} catch (e) {
|
||||||
|
assert(e.message !== 'failed');
|
||||||
|
}
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
describe('reply_in_order', function () {
|
||||||
|
|
||||||
|
var err_count = 0;
|
||||||
|
var res_count = 0;
|
||||||
|
var emitted = false;
|
||||||
|
var clientMock = {
|
||||||
|
emit: function () { emitted = true; },
|
||||||
|
offline_queue: new Queue(),
|
||||||
|
command_queue: new Queue()
|
||||||
|
};
|
||||||
|
var create_command_obj = function () {
|
||||||
|
return {
|
||||||
|
callback: function (err, res) {
|
||||||
|
if (err) err_count++;
|
||||||
|
else res_count++;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
beforeEach(function () {
|
||||||
|
clientMock.offline_queue.clear();
|
||||||
|
clientMock.command_queue.clear();
|
||||||
|
err_count = 0;
|
||||||
|
res_count = 0;
|
||||||
|
emitted = false;
|
||||||
|
});
|
||||||
|
|
||||||
|
it('no elements in either queue. Reply in the next tick', function (done) {
|
||||||
|
var called = false;
|
||||||
|
utils.reply_in_order(clientMock, function () {
|
||||||
|
called = true;
|
||||||
|
done();
|
||||||
|
}, null, null);
|
||||||
|
assert(!called);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('no elements in either queue. Reply in the next tick', function (done) {
|
||||||
|
assert(!emitted);
|
||||||
|
utils.reply_in_order(clientMock, null, new Error('tada'));
|
||||||
|
assert(!emitted);
|
||||||
|
setTimeout(function () {
|
||||||
|
assert(emitted);
|
||||||
|
done();
|
||||||
|
}, 1);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('elements in the offline queue. Reply after the offline queue is empty and respect the command_obj callback', function (done) {
|
||||||
|
clientMock.offline_queue.push(create_command_obj(), create_command_obj());
|
||||||
|
utils.reply_in_order(clientMock, function () {
|
||||||
|
assert.strictEqual(clientMock.offline_queue.length, 0);
|
||||||
|
assert.strictEqual(res_count, 2);
|
||||||
|
done();
|
||||||
|
}, null, null);
|
||||||
|
while (clientMock.offline_queue.length) clientMock.offline_queue.shift().callback(null, 'foo');
|
||||||
|
});
|
||||||
|
|
||||||
|
it('elements in the offline queue. Reply after the offline queue is empty and respect the command_obj error emit', function (done) {
|
||||||
|
clientMock.command_queue.push({}, create_command_obj(), {});
|
||||||
|
utils.reply_in_order(clientMock, function () {
|
||||||
|
assert.strictEqual(clientMock.command_queue.length, 0);
|
||||||
|
assert(emitted);
|
||||||
|
assert.strictEqual(err_count, 1);
|
||||||
|
assert.strictEqual(res_count, 0);
|
||||||
|
done();
|
||||||
|
}, null, null);
|
||||||
|
while (clientMock.command_queue.length) {
|
||||||
|
var command_obj = clientMock.command_queue.shift();
|
||||||
|
if (command_obj.callback) {
|
||||||
|
command_obj.callback(new Error('tada'));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
it('elements in the offline queue. Reply after the offline queue is empty and respect the command_obj', function (done) {
|
||||||
|
clientMock.command_queue.push(create_command_obj(), {});
|
||||||
|
utils.reply_in_order(clientMock, function () {
|
||||||
|
assert.strictEqual(clientMock.command_queue.length, 0);
|
||||||
|
assert(!emitted);
|
||||||
|
assert.strictEqual(res_count, 1);
|
||||||
|
done();
|
||||||
|
}, null, null);
|
||||||
|
while (clientMock.command_queue.length) {
|
||||||
|
clientMock.command_queue.shift().callback(null, 'bar');
|
||||||
|
}
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
Reference in New Issue
Block a user