refactor tests to use fake timers

This commit is contained in:
Ivan Socolsky 2015-04-08 16:38:01 -03:00
parent 34790ec2e2
commit 59996ef073
2 changed files with 78 additions and 48 deletions

View File

@ -1,55 +1,62 @@
var _ = require('lodash');
var $ = require('preconditions').singleton();
var locks = {};
function Lock() {
this.tasks = {};
};
Lock.prototype._release = function(token, task) {
if (!task.running) return;
task.running = false;
this.tasks[token] = _.without(this.tasks[token], task);
this._runOne(token);
};
Lock.prototype._runOne = function(token) {
var self = this;
var item = _.first(locks[token]);
if (!item || item.started) return;
if (_.any(self.tasks[token], {
running: true
})) return;
item.started = true;
if (item.maxRunningTime > 0) {
var task = _.first(self.tasks[token]);
if (!task) return;
task.running = true;
if (task.timeout > 0) {
setTimeout(function() {
var it = _.first(locks[token]);
if (it != item) return;
locks[token].shift();
self._runOne(token);
}, item.maxRunningTime);
self._release(token, task);
}, task.timeout);
}
item.fn(null, function() {
locks[token].shift();
self._runOne(token);
task.fn(null, function() {
self._release(token, task);
});
};
Lock.prototype.locked = function(token, wait, max, task) {
Lock.prototype.locked = function(token, wait, max, userTask) {
var self = this;
if (_.isUndefined(locks[token])) {
locks[token] = [];
if (_.isUndefined(self.tasks[token])) {
self.tasks[token] = [];
}
var item = {
maxRunningTime: max,
started: false,
fn: task,
var task = {
timeout: max,
running: false,
fn: userTask,
};
locks[token].push(item);
self.tasks[token].push(task);
if (wait > 0) {
setTimeout(function() {
var it = _.find(locks[token], item);
if (!it || it.started) return;
locks[token] = _.without(locks[token], it);
it.fn(new Error('Could not acquire lock ' + token));
if (task.running || !_.contains(self.tasks[token], task)) return;
self.tasks[token] = _.without(self.tasks[token], task);
task.fn(new Error('Could not acquire lock ' + token));
}, wait);
}
self._runOne(token);
};

View File

@ -10,9 +10,13 @@ var Lock = require('../lib/locallock');
describe('Local locks', function() {
var lock;
beforeEach(function() {
this.clock = sinon.useFakeTimers();
lock = new Lock();
});
it('should lock tasks using the same token', function(done) {
afterEach(function() {
this.clock.restore();
});
it('should lock tasks using the same token', function() {
var a = false,
b = false;
lock.locked('123', 0, 0, function(err, release) {
@ -27,17 +31,13 @@ describe('Local locks', function() {
release();
});
});
setTimeout(function() {
a.should.equal(true);
b.should.equal(false);
}, 1);
setTimeout(function() {
a.should.equal(true);
b.should.equal(true);
done();
}, 8);
a.should.equal(true);
b.should.equal(false);
this.clock.tick(10);
a.should.equal(true);
b.should.equal(true);
});
it('should not lock tasks using different tokens', function(done) {
it('should not lock tasks using different tokens', function() {
var i = 0;
lock.locked('123', 0, 0, function(err, release) {
should.not.exist(err);
@ -51,12 +51,9 @@ describe('Local locks', function() {
release();
});
});
setTimeout(function() {
i.should.equal(2);
done();
}, 1);
i.should.equal(2);
});
it('should return error if unable to acquire lock', function(done) {
it('should return error if unable to acquire lock', function() {
lock.locked('123', 0, 0, function(err, release) {
should.not.exist(err);
setTimeout(function() {
@ -65,24 +62,50 @@ describe('Local locks', function() {
lock.locked('123', 1, 0, function(err, release) {
should.exist(err);
err.toString().should.contain('Could not acquire lock 123');
done();
});
});
this.clock.tick(2);
});
it('should release lock if acquired for a long time', function(done) {
it('should release lock if acquired for a long time', function() {
var i = 0;
lock.locked('123', 0, 3, function(err, release) {
should.not.exist(err);
i++;
lock.locked('123', 15, 0, function(err, release) {
lock.locked('123', 20, 0, function(err, release) {
should.not.exist(err);
i++;
release();
});
});
setTimeout(function() {
i.should.equal(2);
done();
}, 10);
i.should.equal(1);
this.clock.tick(1);
i.should.equal(1);
this.clock.tick(10);
i.should.equal(2);
});
it('should only release one pending task on lock timeout', function() {
var i = 0;
lock.locked('123', 0, 3, function(err, release) {
should.not.exist(err);
i++;
lock.locked('123', 5, 0, function(err, release) {
should.not.exist(err);
i++;
setTimeout(function() {
release();
}, 5);
});
lock.locked('123', 20, 0, function(err, release) {
should.not.exist(err);
i++;
release();
});
});
i.should.equal(1);
this.clock.tick(4);
i.should.equal(2)
this.clock.tick(7);
i.should.equal(3)
});
});