diff --git a/package.json b/package.json index 0c757198c8..a784a87501 100644 --- a/package.json +++ b/package.json @@ -10,10 +10,10 @@ "license": "MIT", "main": "./index.js", "scripts": { - "coveralls": "nyc report --reporter=text-lcov | coveralls", - "coverage": "nyc report --reporter=html", - "test": "./node_modules/.bin/jshint * && nyc ./node_modules/.bin/_mocha ./test/*.js ./test/commands/*.js ./test/parser/*.js --timeout=8000", - "jshint": "./node_modules/.bin/jshint *" + "coverage": "nyc report --reporter=text-lcov | coveralls", + "test": "nyc ./node_modules/.bin/_mocha ./test/*.js ./test/commands/*.js ./test/parser/*.js --timeout=8000", + "pretest": "optional-dev-dependency hiredis", + "posttest": "jshint *" }, "devDependencies": { "coveralls": "^2.11.2", @@ -22,6 +22,7 @@ "metrics": ">=0.1.5", "mocha": "^2.2.5", "nyc": "^3.2.2", + "optional-dev-dependency": "^1.0.1", "tcp-port-used": "^0.1.2", "uuid": "^2.0.1" }, diff --git a/test/auth.spec.js b/test/auth.spec.js index b4a710b846..b1a9cd86cc 100644 --- a/test/auth.spec.js +++ b/test/auth.spec.js @@ -24,7 +24,7 @@ describe("client authentication", function () { }); it("allows auth to be provided with 'auth' method", function (done) { - abortOnSpawnFailure(done); + if (helper.redisProcess().spawnFailed()) this.skip(); client = redis.createClient.apply(redis.createClient, args); client.auth(auth, function (err, res) { @@ -35,7 +35,7 @@ describe("client authentication", function () { }); it("raises error when auth is bad", function (done) { - abortOnSpawnFailure(done); + if (helper.redisProcess().spawnFailed()) this.skip(); client = redis.createClient.apply(redis.createClient, args); @@ -49,7 +49,7 @@ describe("client authentication", function () { if (ip === 'IPv4') { it('allows auth to be provided as part of redis url', function (done) { - abortOnSpawnFailure(done); + if (helper.redisProcess().spawnFailed()) this.skip(); client = redis.createClient('redis://foo:' + auth + '@' + config.HOST[ip] + ':' + config.PORT); client.on("ready", function () { @@ -59,7 +59,7 @@ describe("client authentication", function () { } it('allows auth to be provided as config option for client', function (done) { - abortOnSpawnFailure(done); + if (helper.redisProcess().spawnFailed()) this.skip(); var args = config.configureClient(parser, ip, { auth_pass: auth @@ -71,7 +71,7 @@ describe("client authentication", function () { }); it('reconnects with appropriate authentication', function (done) { - abortOnSpawnFailure(done); + if (helper.redisProcess().spawnFailed()) this.skip(); var readyCount = 0; client = redis.createClient.apply(redis.createClient, args); @@ -93,13 +93,4 @@ describe("client authentication", function () { helper.startRedis('./conf/redis.conf', done); }); }); - - // if we fail to spawn Redis (spawning Redis directly is - // not possible in some CI environments) skip the auth tests. - function abortOnSpawnFailure (done) { - if (helper.redisProcess().spawnFailed()) { - console.warn('skipped authentication test') - return done(); - } - } }); diff --git a/test/commands/client.spec.js b/test/commands/client.spec.js index 31bb5dc5e7..d6df117fea 100644 --- a/test/commands/client.spec.js +++ b/test/commands/client.spec.js @@ -17,12 +17,7 @@ describe("The 'client' method", function () { client = redis.createClient.apply(redis.createClient, args); client.once("error", done); client.once("connect", function () { - client.flushdb(function (err) { - if (!helper.serverVersionAtLeast(client, [2, 4, 0])) { - err = Error('script not supported in redis <= 2.4.0'); - } - return done(err); - }); + client.flushdb(done) }); }); diff --git a/test/commands/eval.spec.js b/test/commands/eval.spec.js index f5b46942a8..184759a92b 100644 --- a/test/commands/eval.spec.js +++ b/test/commands/eval.spec.js @@ -17,12 +17,7 @@ describe("The 'eval' method", function () { client = redis.createClient.apply(redis.createClient, args); client.once("error", done); client.once("connect", function () { - client.flushdb(function (err) { - if (!helper.serverVersionAtLeast(client, [2, 5, 0])) { - err = Error('exec not supported in redis <= 2.5.0'); - } - return done(err); - }); + client.flushdb(done) }); }); @@ -31,30 +26,37 @@ describe("The 'eval' method", function () { }); it('converts a float to an integer when evaluated', function (done) { + helper.serverVersionAtLeast.bind(this)(client, [2, 5, 0]); client.eval("return 100.5", 0, helper.isNumber(100, done)); }); it('returns a string', function (done) { - client.EVAL("return 'hello world'", 0, helper.isString('hello world', done)); + helper.serverVersionAtLeast.bind(this)(client, [2, 5, 0]); + client.eval("return 'hello world'", 0, helper.isString('hello world', done)); }); it('converts boolean true to integer 1', function (done) { + helper.serverVersionAtLeast.bind(this)(client, [2, 5, 0]); client.eval("return true", 0, helper.isNumber(1, done)); }); it('converts boolean false to null', function (done) { + helper.serverVersionAtLeast.bind(this)(client, [2, 5, 0]); client.eval("return false", 0, helper.isNull(done)); }); it('converts lua status code to string representation', function (done) { + helper.serverVersionAtLeast.bind(this)(client, [2, 5, 0]); client.eval("return {ok='fine'}", 0, helper.isString('fine', done)); }); it('converts lua error to an error response', function (done) { + helper.serverVersionAtLeast.bind(this)(client, [2, 5, 0]); client.eval("return {err='this is an error'}", 0, helper.isError(done)); }); it('represents a lua table appropritely', function (done) { + helper.serverVersionAtLeast.bind(this)(client, [2, 5, 0]); client.eval("return {1,2,3,'ciao',{1,2}}", 0, function (err, res) { assert.strictEqual(5, res.length); assert.strictEqual(1, res[0]); @@ -69,25 +71,27 @@ describe("The 'eval' method", function () { }); it('populates keys and argv correctly', function (done) { - client.eval("return {KEYS[1],KEYS[2],ARGV[1],ARGV[2]}", 2, "a", "b", "c", "d", function (err, res) { - assert.strictEqual(4, res.length); - assert.strictEqual("a", res[0]); - assert.strictEqual("b", res[1]); - assert.strictEqual("c", res[2]); - assert.strictEqual("d", res[3]); - return done(); - }); + helper.serverVersionAtLeast.bind(this)(client, [2, 5, 0]); + client.eval("return {KEYS[1],KEYS[2],ARGV[1],ARGV[2]}", 2, "a", "b", "c", "d", function (err, res) { + assert.strictEqual(4, res.length); + assert.strictEqual("a", res[0]); + assert.strictEqual("b", res[1]); + assert.strictEqual("c", res[2]); + assert.strictEqual("d", res[3]); + return done(); + }); }); it('allows arguments to be provided in array rather than as multiple parameters', function (done) { - client.eval(["return {KEYS[1],KEYS[2],ARGV[1],ARGV[2]}", 2, "a", "b", "c", "d"], function (err, res) { - assert.strictEqual(4, res.length); - assert.strictEqual("a", res[0]); - assert.strictEqual("b", res[1]); - assert.strictEqual("c", res[2]); - assert.strictEqual("d", res[3]); - return done(); - }); + helper.serverVersionAtLeast.bind(this)(client, [2, 5, 0]); + client.eval(["return {KEYS[1],KEYS[2],ARGV[1],ARGV[2]}", 2, "a", "b", "c", "d"], function (err, res) { + assert.strictEqual(4, res.length); + assert.strictEqual("a", res[0]); + assert.strictEqual("b", res[1]); + assert.strictEqual("c", res[2]); + assert.strictEqual("d", res[3]); + return done(); + }); }); describe('evalsha', function () { @@ -101,19 +105,23 @@ describe("The 'eval' method", function () { }); it('allows a script to be executed that accesses the redis API', function (done) { + helper.serverVersionAtLeast.bind(this)(client, [2, 5, 0]); client.eval(source, 0, helper.isString('eval get sha test', done)); }); it('can execute a script if the SHA exists', function (done) { + helper.serverVersionAtLeast.bind(this)(client, [2, 5, 0]); client.evalsha(sha, 0, helper.isString('eval get sha test', done)); }); it('throws an error if SHA does not exist', function (done) { + helper.serverVersionAtLeast.bind(this)(client, [2, 5, 0]); client.evalsha('ffffffffffffffffffffffffffffffffffffffff', 0, helper.isError(done)); }); }); it('allows a key to be incremented, and performs appropriate conversion from LUA type', function (done) { + helper.serverVersionAtLeast.bind(this)(client, [2, 5, 0]); client.set("incr key", 0, function (err, reply) { if (err) return done(err); client.eval("local foo = redis.call('incr','incr key')\n" + "return {type(foo),foo}", 0, function (err, res) { @@ -126,6 +134,7 @@ describe("The 'eval' method", function () { }); it('allows a bulk operation to be performed, and performs appropriate conversion from LUA type', function (done) { + helper.serverVersionAtLeast.bind(this)(client, [2, 5, 0]); client.set("bulk reply key", "bulk reply value", function (err, res) { client.eval("local foo = redis.call('get','bulk reply key'); return {type(foo),foo}", 0, function (err, res) { assert.strictEqual(2, res.length); @@ -137,6 +146,7 @@ describe("The 'eval' method", function () { }); it('allows a multi mulk operation to be performed, with the appropriate type conversion', function (done) { + helper.serverVersionAtLeast.bind(this)(client, [2, 5, 0]); client.multi() .del("mylist") .rpush("mylist", "a") @@ -157,6 +167,7 @@ describe("The 'eval' method", function () { }); it('returns an appropriate representation of Lua status reply', function (done) { + helper.serverVersionAtLeast.bind(this)(client, [2, 5, 0]); client.eval("local foo = redis.call('set','mykey','myval'); return {type(foo),foo['ok']}", 0, function (err, res) { assert.strictEqual(2, res.length); assert.strictEqual("table", res[0]); @@ -166,6 +177,7 @@ describe("The 'eval' method", function () { }); it('returns an appropriate representation of a Lua error reply', function (done) { + helper.serverVersionAtLeast.bind(this)(client, [2, 5, 0]); client.set("error reply key", "error reply value", function (err, res) { if (err) return done(err); client.eval("local foo = redis.pcall('incr','error reply key'); return {type(foo),foo['err']}", 0, function (err, res) { @@ -178,6 +190,7 @@ describe("The 'eval' method", function () { }); it('returns an appropriate representation of a Lua nil reply', function (done) { + helper.serverVersionAtLeast.bind(this)(client, [2, 5, 0]); client.del("nil reply key", function (err, res) { if (err) return done(err); client.eval("local foo = redis.call('get','nil reply key'); return {type(foo),foo == false}", 0, function (err, res) { diff --git a/test/commands/expire.spec.js b/test/commands/expire.spec.js index 4173a3a4bd..5d5ca2d2dc 100644 --- a/test/commands/expire.spec.js +++ b/test/commands/expire.spec.js @@ -24,7 +24,7 @@ describe("The 'expire' method", function () { client.EXPIRE(["expiry key", "1"], helper.isNumber(1)); setTimeout(function () { client.exists(["expiry key"], helper.isNumber(0, done)); - }, 1100); + }, 2000); }); afterEach(function () { diff --git a/test/commands/multi.spec.js b/test/commands/multi.spec.js index 10b50f7c50..119c2c4a90 100644 --- a/test/commands/multi.spec.js +++ b/test/commands/multi.spec.js @@ -64,9 +64,9 @@ describe("The 'multi' method", function () { // Provoke an error at queue time multi1 = client.MULTI(); multi1.mset("multifoo", "10", "multibar", "20", helper.isString("OK")); - multi1.set("foo2", helper.isError()); - multi1.incr("multifoo", helper.isNumber(11)); - multi1.incr("multibar", helper.isNumber(21)); + multi1.set("foo2"); + multi1.incr("multifoo"); + multi1.incr("multibar"); multi1.exec(function () { // Redis 2.6.5+ will abort transactions with errors // see: http://redis.io/topics/transactions @@ -89,6 +89,7 @@ describe("The 'multi' method", function () { }); }); +<<<<<<< HEAD // I'm unclear as to the difference between this test in the test above, // perhaps @mranney can clarify? it('roles back a transaction when an error was provoked at queue time', function (done) { @@ -137,8 +138,8 @@ describe("The 'multi' method", function () { assert.equal(replies, undefined); } else { assert.strictEqual(2, replies[0].length); - assert.strictEqual("0", replies[0][0].toString()); - assert.strictEqual("0", replies[0][1].toString()); + assert.strictEqual(null, replies[0][0]); + assert.strictEqual(null, replies[0][1]); assert.strictEqual("1", replies[1].toString()); assert.strictEqual("1", replies[2].toString()); @@ -226,7 +227,7 @@ describe("The 'multi' method", function () { }); it('reports multiple exceptions when they occur', function (done) { - if (!helper.serverVersionAtLeast(client, [2, 6, 5])) return done(); + helper.serverVersionAtLeast.bind(this)(client, [2, 6, 5]) client.multi().set("foo").exec(function (err, reply) { assert(Array.isArray(err), "err should be an array"); diff --git a/test/commands/script.spec.js b/test/commands/script.spec.js index 663bbc5d9d..2ecfc8af66 100644 --- a/test/commands/script.spec.js +++ b/test/commands/script.spec.js @@ -19,12 +19,7 @@ describe("The 'script' method", function () { client = redis.createClient.apply(redis.createClient, args); client.once("error", done); client.once("connect", function () { - client.flushdb(function (err) { - if (!helper.serverVersionAtLeast(client, [2, 6, 0])) { - err = Error('script not supported in redis <= 2.6.0'); - } - return done(err); - }); + client.flushdb(done); }); }); @@ -33,17 +28,20 @@ describe("The 'script' method", function () { }); it("loads script with client.script('load')", function (done) { - client.SCRIPT("load", command, function(err, result) { + helper.serverVersionAtLeast.bind(this)(client, [2, 6, 0]); + client.script("load", command, function(err, result) { assert.strictEqual(result, commandSha); return done(); }); }); it('allows a loaded script to be evaluated', function (done) { + helper.serverVersionAtLeast.bind(this)(client, [2, 6, 0]); client.evalsha(commandSha, 0, helper.isString('99', done)); }); it('allows a script to be loaded as part of a chained transaction', function (done) { + helper.serverVersionAtLeast.bind(this)(client, [2, 6, 0]); client.multi().script("load", command).exec(function(err, result) { assert.strictEqual(result[0], commandSha); return done(); @@ -51,6 +49,7 @@ describe("The 'script' method", function () { }); it("allows a script to be loaded using a transaction's array syntax", function (done) { + helper.serverVersionAtLeast.bind(this)(client, [2, 6, 0]); client.multi([['script', 'load', command]]).exec(function(err, result) { assert.strictEqual(result[0], commandSha); return done(); diff --git a/test/commands/watch.spec.js b/test/commands/watch.spec.js index 11cd4470f0..5354525c30 100644 --- a/test/commands/watch.spec.js +++ b/test/commands/watch.spec.js @@ -18,12 +18,7 @@ describe("The 'watch' method", function () { client = redis.createClient.apply(redis.createClient, args); client.once("error", done); client.once("connect", function () { - client.flushdb(function (err) { - if (!helper.serverVersionAtLeast(client, [2, 2, 0])) { - err = Error('some watch commands not supported in redis <= 2.2.0'); - } - return done(err); - }); + client.flushdb(done); }); }); diff --git a/test/helper.js b/test/helper.js index 0c5bf8c5bf..158e837d35 100644 --- a/test/helper.js +++ b/test/helper.js @@ -98,17 +98,26 @@ module.exports = { // Return true if the server version >= desired_version var version = connection.server_info.versions; for (var i = 0; i < 3; i++) { - if (version[i] > desired_version[i]) return true; - if (version[i] < desired_version[i]) return false; + if (version[i] < desired_version[i]) { + if (this.skip) this.skip(); + return false; + } } return true; }, allTests: function (cb) { [undefined].forEach(function (options) { // add buffer option at some point describe(options && options.return_buffers ? "returning buffers" : "returning strings", function () { - ['hiredis', 'javascript'].forEach(function (parser) { - cb(parser, "/tmp/redis.sock", config.configureClient(parser, "/tmp/redis.sock", options)); - ['IPv4', 'IPv6'].forEach(function (ip) { + var parsers = ['javascript']; + var protocols = ['IPv4']; + if (process.platform !== 'win32') { + parsers.push('hiredis'); + protocols.push('IPv6') + } + + parsers.forEach(function (parser) { + if (process.platform !== 'win32') cb(parser, "/tmp/redis.sock", config.configureClient(parser, "/tmp/redis.sock", options)); + protocols.forEach(function (ip) { cb(parser, ip, config.configureClient(parser, ip, options)); }); }); diff --git a/test/node_redis.spec.js b/test/node_redis.spec.js index b579a61a49..e10c9ce32a 100644 --- a/test/node_redis.spec.js +++ b/test/node_redis.spec.js @@ -219,7 +219,7 @@ describe("The node_redis client", function () { describe('monitor', function () { it('monitors commands on all other redis clients', function (done) { - if (!helper.serverVersionAtLeast(client, [2, 6, 0])) return done(); + helper.serverVersionAtLeast.bind(this)(client, [2, 6, 0]); var monitorClient = redis.createClient.apply(redis.createClient, args); var responses = []; diff --git a/test/pubsub.spec.js b/test/pubsub.spec.js index 99c75987c7..09cdac4f7f 100644 --- a/test/pubsub.spec.js +++ b/test/pubsub.spec.js @@ -69,7 +69,7 @@ describe("publish/subscribe", function () { }); it('receives messages if subscribe is called after unsubscribe', function (done) { - if (!helper.serverVersionAtLeast(pub, [2, 6, 11])) return done(); + helper.serverVersionAtLeast.bind(this)(sub, [2, 6, 11]); sub.once("subscribe", function (chnl, count) { pub.publish(channel, message, helper.isNumber(1)); @@ -87,7 +87,7 @@ describe("publish/subscribe", function () { }); it('handles SUB_UNSUB_MSG_SUB', function (done) { - if (!helper.serverVersionAtLeast(pub, [2, 6, 11])) return done(); + helper.serverVersionAtLeast.bind(this)(sub, [2, 6, 11]); sub.subscribe('chan8'); sub.subscribe('chan9'); @@ -99,7 +99,7 @@ describe("publish/subscribe", function () { }); it('handles SUB_UNSUB_MSG_SUB', function (done) { - if (!helper.serverVersionAtLeast(pub, [2, 6, 11])) return done(); + helper.serverVersionAtLeast.bind(this)(sub, [2, 6, 11]); sub.psubscribe('abc*'); sub.subscribe('xyz'); @@ -198,8 +198,7 @@ describe("publish/subscribe", function () { }); it('executes callback when unsubscribe is called and there are no subscriptions', function (done) { - // test hangs on older versions of redis, so skip - if (!helper.serverVersionAtLeast(pub, [2, 6, 11])) return done(); + helper.serverVersionAtLeast.bind(this)(sub, [2, 6, 11]); pub.unsubscribe(function (err, results) { assert.strictEqual(null, results); @@ -228,8 +227,7 @@ describe("publish/subscribe", function () { }); it('executes callback when punsubscribe is called and there are no subscriptions', function (done) { - // test hangs on older versions of redis, so skip - if (!helper.serverVersionAtLeast(pub, [2, 6, 11])) return done(); + helper.serverVersionAtLeast.bind(this)(sub, [2, 6, 11]); pub.punsubscribe(function (err, results) { assert.strictEqual(null, results);