167 lines
4.9 KiB
JavaScript
167 lines
4.9 KiB
JavaScript
|
/*
|
||
|
* Copyright (c) 2012 Mathieu Turcotte
|
||
|
* Licensed under the MIT license.
|
||
|
*/
|
||
|
|
||
|
var sinon = require('sinon');
|
||
|
|
||
|
var Backoff = require('../lib/backoff');
|
||
|
var BackoffStrategy = require('../lib/strategy/strategy');
|
||
|
|
||
|
exports["Backoff"] = {
|
||
|
setUp: function(callback) {
|
||
|
this.backoffStrategy = sinon.stub(new BackoffStrategy());
|
||
|
this.backoff = new Backoff(this.backoffStrategy);
|
||
|
this.clock = sinon.useFakeTimers();
|
||
|
this.spy = new sinon.spy();
|
||
|
callback();
|
||
|
},
|
||
|
|
||
|
tearDown: function(callback) {
|
||
|
this.clock.restore();
|
||
|
callback();
|
||
|
},
|
||
|
|
||
|
"the backoff event should be emitted when backoff starts": function(test) {
|
||
|
this.backoffStrategy.next.returns(10);
|
||
|
this.backoff.on('backoff', this.spy);
|
||
|
|
||
|
this.backoff.backoff();
|
||
|
|
||
|
test.ok(this.spy.calledOnce,
|
||
|
'Backoff event should be emitted when backoff starts.');
|
||
|
test.done();
|
||
|
},
|
||
|
|
||
|
"the ready event should be emitted on backoff completion": function(test) {
|
||
|
this.backoffStrategy.next.returns(10);
|
||
|
this.backoff.on('ready', this.spy);
|
||
|
|
||
|
this.backoff.backoff();
|
||
|
this.clock.tick(10);
|
||
|
|
||
|
test.ok(this.spy.calledOnce,
|
||
|
'Ready event should be emitted when backoff ends.');
|
||
|
test.done();
|
||
|
},
|
||
|
|
||
|
"the backoff event should be passed the backoff delay": function(test) {
|
||
|
this.backoffStrategy.next.returns(989);
|
||
|
this.backoff.on('backoff', this.spy);
|
||
|
|
||
|
this.backoff.backoff();
|
||
|
|
||
|
test.equal(this.spy.getCall(0).args[1], 989, 'Backoff event should ' +
|
||
|
'carry the backoff delay as its second argument.');
|
||
|
test.done();
|
||
|
},
|
||
|
|
||
|
"the ready event should be passed the backoff delay": function(test) {
|
||
|
this.backoffStrategy.next.returns(989);
|
||
|
this.backoff.on('ready', this.spy);
|
||
|
|
||
|
this.backoff.backoff();
|
||
|
this.clock.tick(989);
|
||
|
|
||
|
test.equal(this.spy.getCall(0).args[1], 989, 'Ready event should ' +
|
||
|
'carry the backoff delay as its second argument.');
|
||
|
test.done();
|
||
|
},
|
||
|
|
||
|
"the fail event should be emitted when backoff limit is reached": function(test) {
|
||
|
var err = new Error('Fail');
|
||
|
|
||
|
this.backoffStrategy.next.returns(10);
|
||
|
this.backoff.on('fail', this.spy);
|
||
|
|
||
|
this.backoff.failAfter(2);
|
||
|
|
||
|
// Consume first 2 backoffs.
|
||
|
for (var i = 0; i < 2; i++) {
|
||
|
this.backoff.backoff();
|
||
|
this.clock.tick(10);
|
||
|
}
|
||
|
|
||
|
// Failure should occur on the third call, and not before.
|
||
|
test.ok(!this.spy.calledOnce, 'Fail event shouldn\'t have been emitted.');
|
||
|
this.backoff.backoff(err);
|
||
|
test.ok(this.spy.calledOnce, 'Fail event should have been emitted.');
|
||
|
test.equal(this.spy.getCall(0).args[0], err, 'Error should be passed');
|
||
|
|
||
|
test.done();
|
||
|
},
|
||
|
|
||
|
"calling backoff while a backoff is in progress should throw an error": function(test) {
|
||
|
this.backoffStrategy.next.returns(10);
|
||
|
var backoff = this.backoff;
|
||
|
|
||
|
backoff.backoff();
|
||
|
|
||
|
test.throws(function() {
|
||
|
backoff.backoff();
|
||
|
}, /in progress/);
|
||
|
|
||
|
test.done();
|
||
|
},
|
||
|
|
||
|
"backoff limit should be greater than 0": function(test) {
|
||
|
var backoff = this.backoff;
|
||
|
test.throws(function() {
|
||
|
backoff.failAfter(0);
|
||
|
}, /greater than 0 but got 0/);
|
||
|
test.done();
|
||
|
},
|
||
|
|
||
|
"reset should cancel any backoff in progress": function(test) {
|
||
|
this.backoffStrategy.next.returns(10);
|
||
|
this.backoff.on('ready', this.spy);
|
||
|
|
||
|
this.backoff.backoff();
|
||
|
|
||
|
this.backoff.reset();
|
||
|
this.clock.tick(100); // 'ready' should not be emitted.
|
||
|
|
||
|
test.equals(this.spy.callCount, 0, 'Reset should have aborted the backoff.');
|
||
|
test.done();
|
||
|
},
|
||
|
|
||
|
"reset should reset the backoff strategy": function(test) {
|
||
|
this.backoff.reset();
|
||
|
test.ok(this.backoffStrategy.reset.calledOnce,
|
||
|
'The backoff strategy should have been resetted.');
|
||
|
test.done();
|
||
|
},
|
||
|
|
||
|
"backoff should be reset after fail": function(test) {
|
||
|
this.backoffStrategy.next.returns(10);
|
||
|
|
||
|
this.backoff.failAfter(1);
|
||
|
|
||
|
this.backoff.backoff();
|
||
|
this.clock.tick(10);
|
||
|
this.backoff.backoff();
|
||
|
|
||
|
test.ok(this.backoffStrategy.reset.calledOnce,
|
||
|
'Backoff should have been resetted after failure.');
|
||
|
test.done();
|
||
|
},
|
||
|
|
||
|
"the backoff number should increase from 0 to N - 1": function(test) {
|
||
|
this.backoffStrategy.next.returns(10);
|
||
|
this.backoff.on('backoff', this.spy);
|
||
|
|
||
|
var expectedNumbers = [0, 1, 2, 3, 4];
|
||
|
var actualNumbers = [];
|
||
|
|
||
|
for (var i = 0; i < expectedNumbers.length; i++) {
|
||
|
this.backoff.backoff();
|
||
|
this.clock.tick(10);
|
||
|
actualNumbers.push(this.spy.getCall(i).args[0]);
|
||
|
}
|
||
|
|
||
|
test.deepEqual(expectedNumbers, actualNumbers,
|
||
|
'Backoff number should increase from 0 to N - 1.');
|
||
|
test.done();
|
||
|
}
|
||
|
};
|