Skip to content

Commit 2b44245

Browse files
Erin SpicelandBenjamin Coe
authored andcommitted
Add example test with grunt and mocha.
Add test for reconnect. Run each test for both parsers and both IP versions. Don't save a reference to this nodified assertion function. Add DEBUG env var which enables extra debug logging in node_redis. Remove Grunt, run Redis on 6378 for non-interference. Remove the tests already ported to Mocha. Port reconnect after pubsub test; add subscribed after reconnect test. Reconnet after pubsub test confused me. I don't think it tested anything, and it didn't pass for me after I ported it. I've disabled it and added a note. In its place, I've added a test to make sure we are still subscribed and can receive pubsub messages after a reconnect. Move test suite config-like stuff into a library. Move test suite createClient args generation into the config library. WIP. Some select tests, most disabled and still WIP.
1 parent 6cae0b8 commit 2b44245

File tree

9 files changed

+444
-45
lines changed

9 files changed

+444
-45
lines changed

package.json

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,10 +14,12 @@
1414
"test": "nyc ./test/run.sh"
1515
},
1616
"devDependencies": {
17+
"async": "^1.3.0",
1718
"colors": "~0.6.0-1",
1819
"coveralls": "^2.11.2",
1920
"hiredis": "^0.4.0",
2021
"metrics": ">=0.1.5",
22+
"mocha": "^2.2.5",
2123
"nyc": "^3.0.0",
2224
"underscore": "~1.4.4"
2325
},

run-bootstrapped-mocha.js

Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,28 @@
1+
var pm = require('./test/lib/redis-process');
2+
var cp = require('child_process');
3+
var testSets = 'test/mocha/**/*.spec.js';
4+
var async = require('async');
5+
var redis;
6+
7+
process.on("exit", function () {
8+
if (redis) {
9+
redis.stop();
10+
}
11+
});
12+
13+
async.series([function startRedis(next) {
14+
redis = pm.start(function (err) {
15+
next(err);
16+
});
17+
}, function runMocha(next) {
18+
var mocha = cp.spawn('mocha', [testSets], {
19+
stdio: "inherit"
20+
});
21+
mocha.on("exit", function (code) {
22+
next();
23+
});
24+
}, function stopRedis(next) {
25+
redis.stop(next);
26+
}], function (err) {
27+
// done;
28+
});

test/conf/redis.conf

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
daemonize yes
2+
port 6378
3+
bind ::1
4+
unixsocket /tmp/redis.sock
5+
unixsocketperm 755

test/lib/config.js

Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,30 @@
1+
module.exports = (function () {
2+
var redis = require('../../index');
3+
redis.debug_mode = process.env.DEBUG ? JSON.parse(process.env.DEBUG) : false;
4+
5+
var config = {
6+
redis: redis,
7+
PORT: 6378,
8+
HOST: {
9+
IPv4: "127.0.0.1",
10+
IPv6: "::1"
11+
}
12+
};
13+
14+
config.configureClient = function (parser, ip, isSocket) {
15+
var args = [];
16+
17+
if (!isSocket) {
18+
args.push(config.PORT);
19+
args.push(config.HOST[ip]);
20+
args.push({ family: ip, parser: parser });
21+
} else {
22+
args.push(ip);
23+
args.push({ parser: parser });
24+
}
25+
26+
return args;
27+
};
28+
29+
return config;
30+
})();

test/lib/nodeify-assertions.js

Lines changed: 60 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,60 @@
1+
var assert = require('assert');
2+
3+
module.exports = {
4+
isNumber: function (expected) {
5+
return function (err, results) {
6+
assert.strictEqual(null, err, "expected " + expected + ", got error: " + err);
7+
assert.strictEqual(expected, results, expected + " !== " + results);
8+
assert.strictEqual(typeof results, "number", "expected a number, got " + typeof results);
9+
return true;
10+
};
11+
},
12+
13+
isString: function (str) {
14+
return function (err, results) {
15+
assert.strictEqual(null, err, "expected string '" + str + "', got error: " + err);
16+
assert.equal(str, results, str + " does not match " + results);
17+
return true;
18+
};
19+
},
20+
21+
isNull: function () {
22+
return function (err, results) {
23+
assert.strictEqual(null, err, "expected null, got error: " + err);
24+
assert.strictEqual(null, results, results + " is not null");
25+
return true;
26+
};
27+
},
28+
29+
isError: function () {
30+
return function (err, results) {
31+
assert.notEqual(err, null, "err is null, but an error is expected here.");
32+
return true;
33+
};
34+
},
35+
36+
isNotError: function () {
37+
return function (err, results) {
38+
assert.strictEqual(err, null, "expected success, got an error: " + err);
39+
return true;
40+
};
41+
},
42+
43+
isType: {
44+
number: function () {
45+
return function (err, results) {
46+
assert.strictEqual(null, err, "expected any number, got error: " + err);
47+
assert.strictEqual(typeof results, "number", results + " is not a number");
48+
return true;
49+
};
50+
},
51+
52+
positiveNumber: function () {
53+
return function (err, results) {
54+
assert.strictEqual(null, err, "expected positive number, got error: " + err);
55+
assert.strictEqual(true, (results > 0), results + " is not a positive number");
56+
return true;
57+
};
58+
}
59+
}
60+
};

test/lib/redis-process.js

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
1+
var cp = require('child_process');
2+
3+
module.exports = {
4+
start: function (done, isSocket) {
5+
var confFile = isSocket ? "test/conf/redis-socket.conf" : "test/conf/redis.conf";
6+
var redis = cp.spawn("redis-server", [confFile]);
7+
8+
redis.once('err', done);
9+
setTimeout(function (data) {
10+
redis.removeListener('err', done);
11+
done();
12+
}, 1000);
13+
14+
return {
15+
stop: function (done) {
16+
redis.once("exit", function () {
17+
done();
18+
});
19+
redis.kill("SIGINT");
20+
}
21+
};
22+
}
23+
};

test/mocha/connecting.spec.js

Lines changed: 165 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,165 @@
1+
var nodeAssert = require("../lib/nodeify-assertions");
2+
var config = require("../lib/config");
3+
var redis = config.redis;
4+
var async = require("async");
5+
6+
describe("A node_redis client", function () {
7+
function allTests(parser, ip, isSocket) {
8+
var args = config.configureClient(parser, ip, isSocket);
9+
10+
describe("using " + parser + " and " + ip, function () {
11+
var client;
12+
13+
after(function () {
14+
client.end();
15+
});
16+
17+
it("connects correctly", function (done) {
18+
client = redis.createClient.apply(redis.createClient, args);
19+
client.on("error", done);
20+
21+
client.once("ready", function () {
22+
client.removeListener("error", done);
23+
client.get("recon 1", function (err, res) {
24+
done(err);
25+
});
26+
});
27+
});
28+
});
29+
30+
describe("when connected", function () {
31+
var client;
32+
33+
beforeEach(function (done) {
34+
client = redis.createClient.apply(redis.createClient, args);
35+
client.once("error", function onError(err) {
36+
done(err);
37+
});
38+
client.once("ready", function onReady() {
39+
done();
40+
});
41+
});
42+
43+
afterEach(function () {
44+
client.end();
45+
});
46+
47+
describe("when redis closes unexpectedly", function () {
48+
it("reconnects and can retrieve the pre-existing data", function (done) {
49+
client.on("reconnecting", function on_recon(params) {
50+
client.on("connect", function on_connect() {
51+
async.parallel([function (cb) {
52+
client.get("recon 1", function (err, res) {
53+
nodeAssert.isString("one")(err, res);
54+
cb();
55+
});
56+
}, function (cb) {
57+
client.get("recon 1", function (err, res) {
58+
nodeAssert.isString("one")(err, res);
59+
cb();
60+
});
61+
}, function (cb) {
62+
client.get("recon 2", function (err, res) {
63+
nodeAssert.isString("two")(err, res);
64+
cb();
65+
});
66+
}, function (cb) {
67+
client.get("recon 2", function (err, res) {
68+
nodeAssert.isString("two")(err, res);
69+
cb();
70+
});
71+
}], function (err, results) {
72+
client.removeListener("connect", on_connect);
73+
client.removeListener("reconnecting", on_recon);
74+
done(err);
75+
});
76+
});
77+
});
78+
79+
client.set("recon 1", "one");
80+
client.set("recon 2", "two", function (err, res) {
81+
// Do not do this in normal programs. This is to simulate the server closing on us.
82+
// For orderly shutdown in normal programs, do client.quit()
83+
client.stream.destroy();
84+
});
85+
});
86+
87+
describe("and it's subscribed to a channel", function () {
88+
// reconnect_select_db_after_pubsub
89+
// Does not pass.
90+
// "Connection in subscriber mode, only subscriber commands may be used"
91+
xit("reconnects, unsubscribes, and can retrieve the pre-existing data", function (done) {
92+
client.on("reconnecting", function on_recon(params) {
93+
client.on("ready", function on_connect() {
94+
async.parallel([function (cb) {
95+
client.unsubscribe("recon channel", function (err, res) {
96+
nodeAssert.isNotError()(err, res);
97+
cb();
98+
});
99+
}, function (cb) {
100+
client.get("recon 1", function (err, res) {
101+
nodeAssert.isString("one")(err, res);
102+
cb();
103+
});
104+
}], function (err, results) {
105+
client.removeListener("connect", on_connect);
106+
client.removeListener("reconnecting", on_recon);
107+
done(err);
108+
});
109+
});
110+
});
111+
112+
client.set("recon 1", "one");
113+
client.subscribe("recon channel", function (err, res) {
114+
// Do not do this in normal programs. This is to simulate the server closing on us.
115+
// For orderly shutdown in normal programs, do client.quit()
116+
client.stream.destroy();
117+
});
118+
});
119+
120+
it("remains subscribed", function () {
121+
var client2 = redis.createClient.apply(redis.createClient, args);
122+
123+
client.on("reconnecting", function on_recon(params) {
124+
client.on("ready", function on_connect() {
125+
async.parallel([function (cb) {
126+
client.on("message", function (channel, message) {
127+
try {
128+
nodeAssert.isString("recon channel")(null, channel);
129+
nodeAssert.isString("a test message")(null, message);
130+
} catch (err) {
131+
cb(err);
132+
}
133+
});
134+
135+
client2.subscribe("recon channel", function (err, res) {
136+
if (err) {
137+
cb(err);
138+
return;
139+
}
140+
client2.publish("recon channel", "a test message");
141+
});
142+
}], function (err, results) {
143+
done(err);
144+
});
145+
});
146+
});
147+
148+
client.subscribe("recon channel", function (err, res) {
149+
// Do not do this in normal programs. This is to simulate the server closing on us.
150+
// For orderly shutdown in normal programs, do client.quit()
151+
client.stream.destroy();
152+
});
153+
});
154+
});
155+
});
156+
});
157+
}
158+
159+
['javascript', 'hiredis'].forEach(function (parser) {
160+
allTests(parser, "/tmp/redis.sock", true);
161+
['IPv4', 'IPv6'].forEach(function (ip) {
162+
allTests(parser, ip);
163+
})
164+
});
165+
});

0 commit comments

Comments
 (0)