refactor tests to use fake timers
This commit is contained in:
parent
34790ec2e2
commit
59996ef073
|
@ -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);
|
||||
};
|
||||
|
||||
|
|
|
@ -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)
|
||||
});
|
||||
|
||||
});
|
||||
|
|
Loading…
Reference in New Issue