Skip to content
Snippets Groups Projects
Commit 8aeb2fdf authored by Andrew Newdigate's avatar Andrew Newdigate
Browse files

Failover tests for ioredis

parent 4b16f5d9
No related branches found
No related tags found
No related merge requests found
/*jslint node: true */
"use strict";
var ioredis = require('../lib/env-ioredis');
var mockConfig = require('./mock-config');
var redisSpec = require('./redis-spec');
describe('gitter-redis', function() {
var logger, factory;
before(function() {
logger = require('../lib/logger').create({ config: mockConfig({}) });
factory = ioredis.create({config: mockConfig({}), logger: logger });
});
redisSpec(function(options) {
return factory.createClient(options, logger);
}, function(client) {
factory.quitClient(client);
});
});
'use strict';
var assert = require('assert');
var spawn = require('child_process').spawn;
var fs = require('fs');
var temp = require('temp').track();
function RedisController() {
this.processes = {};
this.dir = temp.mkdirSync('redistests');
this.writeSentinelConfigs();
this.options = {
redisDb: 1,
sentinel: {
"master-name": "test-master",
hosts: [
"localhost:46379",
"localhost:46380",
"localhost:46381",
]
}
};
}
RedisController.prototype = {
listenToProcess: function(name, process) {
var processes = this.processes;
process.once('close', function() {
delete processes[name];
});
return process;
},
startRedisPrimary: function() {
var processes = this.processes;
assert(!processes.redis1);
processes.redis1 = this.listenToProcess('redis1', spawn('redis-server', [
'--port', '36379',
'--save', '',
'--dir', this.dir
]));
return processes.redis1;
},
startRedisSecondary: function() {
var processes = this.processes;
assert(!processes.redis2);
processes.redis2 = this.listenToProcess('redis2', spawn('redis-server', [
'--port', '36380',
'--slaveof', 'localhost', '36379',
'--save', '',
'--dir', this.dir
]));
return processes.redis2;
},
writeSentinelConfigs: function() {
var dir = this.dir;
fs.writeFileSync(dir + '/sentinel-1.conf', 'sentinel monitor test-master 127.0.0.1 36379 2\n' +
'sentinel down-after-milliseconds test-master 500\n' +
'sentinel failover-timeout test-master 1000\n' +
'sentinel config-epoch test-master 5');
fs.writeFileSync(dir + '/sentinel-2.conf', 'sentinel monitor test-master 127.0.0.1 36379 2\n' +
'sentinel down-after-milliseconds test-master 500\n' +
'sentinel failover-timeout test-master 1000\n' +
'sentinel config-epoch test-master 5');
fs.writeFileSync(dir + '/sentinel-3.conf', 'sentinel monitor test-master 127.0.0.1 36379 2\n' +
'sentinel down-after-milliseconds test-master 500\n' +
'sentinel failover-timeout test-master 1000\n' +
'sentinel config-epoch test-master 5');
},
startSentinel: function(number) {
var dir = this.dir;
var processes = this.processes;
assert(!processes['sentinel' + number]);
var filename = dir + '/sentinel-' + number + '.conf';
var port = 46378 + number;
var p = processes['sentinel' + number] = this.listenToProcess('sentinel' + number, spawn('redis-server', [
filename,
'--sentinel',
'--port', port,
'--save', '',
'--dir', dir]));
return p;
},
stop: function(name, signal) {
var processes = this.processes;
if(!processes[name]) return;
processes[name].kill(signal);
delete processes[name];
},
ensureAllStarted: function() {
var processes = this.processes;
if (!processes.redis1) this.startRedisPrimary();
if (!processes.redis2) this.startRedisSecondary();
if (!processes.sentinel1) this.startSentinel(1);
if (!processes.sentinel2) this.startSentinel(2);
if (!processes.sentinel3) this.startSentinel(3);
},
stopAll: function() {
Object.keys(this.processes).forEach(function(name) {
this.stop(name);
}, this);
},
cleanup: function() {
this.stopAll();
temp.cleanupSync();
}
};
module.exports = RedisController;
"use strict";
var assert = require('assert');
var RedisController = require('./redis-controller');
module.exports = function redisSpec(create, quit) {
var redisController;
before(function(done) {
redisController = new RedisController();
done();
});
beforeEach(function() {
redisController.ensureAllStarted();
});
after(function(done) {
redisController.cleanup();
done();
});
describe('failover', function() {
this.timeout(15000);
var mainRedisClient;
beforeEach(function() {
mainRedisClient = create(redisController.options);
});
afterEach(function() {
quit(mainRedisClient);
});
it('should obtain a handle failover correctly', function(done) {
var setValue = String(Math.random());
mainRedisClient.set('moo', setValue, function(err) {
if(err) return done(err);
redisController.stop('redis1');
mainRedisClient.get('moo', function(err, value) {
redisController.ensureAllStarted();
if(err) return done(err);
assert.strictEqual(value, setValue);
done();
});
});
});
it('should handle mega failure correctly', function(done) {
var setValue = String(Math.random());
mainRedisClient.set('s', setValue, function(err) {
if(err) return done(err);
// Kill the sentinel and the redis
redisController.stop('sentinel1');
redisController.stop('redis1');
setTimeout(function() {
redisController.ensureAllStarted();
function next() {
mainRedisClient.get('s', function(err) {
if (err) {
setTimeout(next, 500);
return;
}
done();
});
}
next();
}, 1000);
});
});
it('should handle sentinel failure correctly', function(done) {
var setValue = String(Math.random());
mainRedisClient.set('s', setValue, function(err) {
if(err) return done(err);
redisController.stop('sentinel1');
setTimeout(function() {
mainRedisClient.get('s', function(err, value) {
if(err) return done(err);
assert.strictEqual(value, setValue);
done();
});
}, 500);
});
});
it('should handle sentinel failure prior to initial connection', function(done) {
redisController.stop('sentinel1');
redisController.stop('sentinel2');
redisController.stop('sentinel3');
setTimeout(function() {
redisController.ensureAllStarted();
var setValue = String(Math.random());
mainRedisClient.set('s', setValue, function(err) {
if(err) return done(err);
mainRedisClient.get('s', function(err, value) {
if(err) return done(err);
assert.strictEqual(value, setValue);
done();
});
});
}, 1000);
});
});
};
Loading
Loading
@@ -3,299 +3,84 @@
"use strict";
 
var assert = require('assert');
var spawn = require('child_process').spawn;
var fs = require('fs');
var redisClient = require('../lib/redis-client');
var mockConfig = require('./mock-config');
var temp = require('temp').track();
var RedisController = require('./redis-controller');
var redisSpec = require('./redis-spec');
 
describe('gitter-redis', function() {
var options, logger, dir;
var processes;
function listenToProcess(name, process) {
process.once('close', function(code, signal) {
delete processes[name];
});
return process;
}
function startRedisPrimary() {
assert(!processes.redis1);
processes.redis1 = listenToProcess('redis1', spawn('redis-server', [
'--port', '36379',
'--save', '',
'--dir', dir
]));
return processes.redis1;
}
function startRedisSecondary() {
assert(!processes.redis2);
processes.redis2 = listenToProcess('redis2', spawn('redis-server', [
'--port', '36380',
'--slaveof', 'localhost', '36379',
'--save', '',
'--dir', dir
]));
return processes.redis2;
}
function writeSentinelConfigs() {
fs.writeFileSync(dir + '/sentinel-1.conf', 'sentinel monitor test-master 127.0.0.1 36379 2\n' +
'sentinel down-after-milliseconds test-master 500\n' +
'sentinel failover-timeout test-master 1000\n' +
'sentinel config-epoch test-master 5');
fs.writeFileSync(dir + '/sentinel-2.conf', 'sentinel monitor test-master 127.0.0.1 36379 2\n' +
'sentinel down-after-milliseconds test-master 500\n' +
'sentinel failover-timeout test-master 1000\n' +
'sentinel config-epoch test-master 5');
fs.writeFileSync(dir + '/sentinel-3.conf', 'sentinel monitor test-master 127.0.0.1 36379 2\n' +
'sentinel down-after-milliseconds test-master 500\n' +
'sentinel failover-timeout test-master 1000\n' +
'sentinel config-epoch test-master 5');
}
function startSentinel(number) {
assert(!processes['sentinel' + number]);
var filename = dir + '/sentinel-' + number + '.conf';
var port = 46378 + number;
var p = processes['sentinel' + number] = listenToProcess('sentinel' + number, spawn('redis-server', [
filename,
'--sentinel',
'--port', port,
'--save', '',
'--dir', dir]));
return p;
}
function stop(name, signal) {
if(!processes[name]) return;
processes[name].kill(signal);
delete processes[name];
}
function ensureAllStarted() {
if (!processes.redis1) startRedisPrimary();
if (!processes.redis2) startRedisSecondary();
if (!processes.sentinel1) startSentinel(1);
if (!processes.sentinel2) startSentinel(2);
if (!processes.sentinel3) startSentinel(3);
}
function stopAll() {
if (!processes) return;
Object.keys(processes).forEach(function(name) {
stop(name);
});
}
before(function(done) {
dir = temp.mkdirSync('redistests');
writeSentinelConfigs();
processes = {};
options = {
redisDb: 1,
sentinel: {
"master-name": "test-master",
hosts: [
"localhost:46379",
"localhost:46380",
"localhost:46381",
]
}
};
var logger;
 
before(function() {
logger = require('../lib/logger').create({ config: mockConfig({}) });
done();
});
 
beforeEach(function() {
ensureAllStarted();
});
describe('node_redis tests', function() {
var redisController;
 
after(function(done) {
stopAll();
temp.cleanupSync();
done();
});
it('should obtain a connection and release it', function(done) {
var mainRedisClient = redisClient.create(options, logger);
assert.strictEqual(redisClient.testOnly.getClients().length, 1);
assert(mainRedisClient);
mainRedisClient.on('reconnected', function() {
redisClient.quit(mainRedisClient);
assert.strictEqual(redisClient.testOnly.getClients().length, 0);
setImmediate(function() {
// Don't cause problems for other tests after we shut down redis
mainRedisClient.on('error', function() { });
done();
});
before(function(done) {
redisController = new RedisController();
done();
});
});
it('should obtain a transient connection and release it', function(done) {
var mainRedisClient = redisClient.create(options, logger);
redisClient.createTransientClient(mainRedisClient, options, logger, function(err, temporaryClient) {
assert.strictEqual(redisClient.testOnly.getClients().length, 2);
assert(temporaryClient);
redisClient.quit(temporaryClient);
redisClient.quit(mainRedisClient);
assert.strictEqual(redisClient.testOnly.getClients().length, 0);
setImmediate(function() {
// Don't cause problems for other tests after we shut down redis
temporaryClient.on('error', function() { });
mainRedisClient.on('error', function() { });
done();
});
});
});
it('should obtain a handle failover correctly', function(done) {
this.timeout(15000);
var mainRedisClient = redisClient.create(options, logger);
var setValue = String(Math.random());
mainRedisClient.on('reconnected', function() {
mainRedisClient.set('moo', setValue, function(err) {
if(err) return done(err);
stop('redis1');
mainRedisClient.get('moo', function(err, value) {
startRedisPrimary();
if(err) return done(err);
assert.strictEqual(value, setValue);
setImmediate(function() {
mainRedisClient.on('error', function() { });
redisClient.quit(mainRedisClient);
done();
});
});
 
});
beforeEach(function() {
redisController.ensureAllStarted();
});
 
});
it('should handle mega failure correctly', function(done) {
this.timeout(15000);
var mainRedisClient = redisClient.create(options, logger);
var setValue = String(Math.random());
mainRedisClient.set('s', setValue, function(err) {
if(err) return done(err);
// Kill the sentinel and the redis
stop('sentinel1');
stop('redis1');
setTimeout(function() {
ensureAllStarted();
function next() {
console.log('trying get...')
mainRedisClient.get('s', function(err) {
if (err) {
console.log('FAILED', err);
setTimeout(next, 500);
return;
}
mainRedisClient.on('error', function() { });
redisClient.quit(mainRedisClient);
done();
});
}
next();
}, 1000);
after(function(done) {
redisController.cleanup();
done();
});
 
});
it('should handle sentinel failure correctly', function(done) {
this.timeout(15000);
var mainRedisClient = redisClient.create(options, logger);
var setValue = String(Math.random());
mainRedisClient.set('s', setValue, function(err) {
if(err) return done(err);
it('should obtain a connection and release it', function(done) {
 
stop('sentinel1');
var mainRedisClient = redisClient.create(redisController.options, logger);
assert.strictEqual(redisClient.testOnly.getClients().length, 1);
assert(mainRedisClient);
 
setTimeout(function() {
mainRedisClient.get('s', function(err, value) {
if(err) return done(err);
mainRedisClient.on('reconnected', function() {
redisClient.quit(mainRedisClient);
 
assert.strictEqual(value, setValue);
assert.strictEqual(redisClient.testOnly.getClients().length, 0);
 
setImmediate(function() {
// Don't cause problems for other tests after we shut down redis
mainRedisClient.on('error', function() { });
redisClient.quit(mainRedisClient);
done();
});
}, 500);
});
});
 
});
it('should handle sentinel failure prior to initial connection', function(done) {
this.timeout(15000);
stop('sentinel1');
stop('sentinel2');
stop('sentinel3');
setTimeout(function() {
ensureAllStarted();
var mainRedisClient = redisClient.create(options, logger);
it('should obtain a transient connection and release it', function(done) {
var mainRedisClient = redisClient.create(redisController.options, logger);
 
var setValue = String(Math.random());
redisClient.createTransientClient(mainRedisClient, redisController.options, logger, function(err, temporaryClient) {
assert.strictEqual(redisClient.testOnly.getClients().length, 2);
 
mainRedisClient.set('s', setValue, function(err) {
if(err) return done(err);
assert(temporaryClient);
 
mainRedisClient.get('s', function(err, value) {
if(err) return done(err);
redisClient.quit(temporaryClient);
redisClient.quit(mainRedisClient);
 
assert.strictEqual(value, setValue);
assert.strictEqual(redisClient.testOnly.getClients().length, 0);
 
setImmediate(function() {
// Don't cause problems for other tests after we shut down redis
temporaryClient.on('error', function() { });
mainRedisClient.on('error', function() { });
redisClient.quit(mainRedisClient);
done();
});
 
});
 
}, 1000);
});
});
 
redisSpec(function(options) {
return redisClient.create(options, logger);
}, function(client) {
client.on('error', function() { });
redisClient.quit(client);
});
 
 
Loading
Loading
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment