Simulator first commit

This commit is contained in:
2019-09-18 11:11:16 +03:00
commit 6e1686be67
5028 changed files with 985331 additions and 0 deletions

68
node_modules/backoff/tests/api.js generated vendored Normal file
View File

@ -0,0 +1,68 @@
/*
* Copyright (c) 2012 Mathieu Turcotte
* Licensed under the MIT license.
*/
var sinon = require('sinon');
var backoff = require('../index');
exports["API"] = {
"backoff.fibonnaci should be a function that returns a backoff instance": function(test) {
test.ok(backoff.fibonacci, 'backoff.fibonacci should be defined.');
test.equal(typeof backoff.fibonacci, 'function',
'backoff.fibonacci should be a function.');
test.equal(backoff.fibonacci().constructor.name, 'Backoff');
test.done();
},
"backoff.exponential should be a function that returns a backoff instance": function(test) {
test.ok(backoff.exponential, 'backoff.exponential should be defined.');
test.equal(typeof backoff.exponential, 'function',
'backoff.exponential should be a function.');
test.equal(backoff.exponential().constructor.name, 'Backoff');
test.done();
},
"backoff.call should be a function that returns a FunctionCall instance": function(test) {
var fn = function() {};
var callback = function() {};
test.ok(backoff.Backoff, 'backoff.call should be defined.');
test.equal(typeof backoff.call, 'function',
'backoff.call should be a function.');
test.equal(backoff.call(fn, 1, 2, 3, callback).constructor.name,
'FunctionCall');
test.done();
},
"backoff.Backoff should be defined and a function": function(test) {
test.ok(backoff.Backoff, 'backoff.Backoff should be defined.');
test.equal(typeof backoff.Backoff, 'function',
'backoff.Backoff should be a function.');
test.done();
},
"backoff.FunctionCall should be defined and a function": function(test) {
test.ok(backoff.FunctionCall,
'backoff.FunctionCall should be defined.');
test.equal(typeof backoff.FunctionCall, 'function',
'backoff.FunctionCall should be a function.');
test.done();
},
"backoff.FibonacciStrategy should be defined and a function": function(test) {
test.ok(backoff.FibonacciStrategy,
'backoff.FibonacciStrategy should be defined.');
test.equal(typeof backoff.FibonacciStrategy, 'function',
'backoff.FibonacciStrategy should be a function.');
test.done();
},
"backoff.ExponentialStrategy should be defined and a function": function(test) {
test.ok(backoff.ExponentialStrategy,
'backoff.ExponentialStrategy should be defined.');
test.equal(typeof backoff.ExponentialStrategy, 'function',
'backoff.ExponentialStrategy should be a function.');
test.done();
}
};

166
node_modules/backoff/tests/backoff.js generated vendored Normal file
View File

@ -0,0 +1,166 @@
/*
* 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();
}
};

123
node_modules/backoff/tests/backoff_strategy.js generated vendored Normal file
View File

@ -0,0 +1,123 @@
/*
* Copyright (c) 2012 Mathieu Turcotte
* Licensed under the MIT license.
*/
var sinon = require('sinon');
var util = require('util');
var BackoffStrategy = require('../lib/strategy/strategy');
function SampleBackoffStrategy(options) {
BackoffStrategy.call(this, options);
}
util.inherits(SampleBackoffStrategy, BackoffStrategy);
SampleBackoffStrategy.prototype.next_ = function() {
return this.getInitialDelay();
};
SampleBackoffStrategy.prototype.reset_ = function() {};
exports["BackoffStrategy"] = {
setUp: function(callback) {
this.random = sinon.stub(Math, 'random');
callback();
},
tearDown: function(callback) {
this.random.restore();
callback();
},
"the randomisation factor should be between 0 and 1": function(test) {
test.throws(function() {
new BackoffStrategy({
randomisationFactor: -0.1
});
});
test.throws(function() {
new BackoffStrategy({
randomisationFactor: 1.1
});
});
test.doesNotThrow(function() {
new BackoffStrategy({
randomisationFactor: 0.5
});
});
test.done();
},
"the raw delay should be randomized based on the randomisation factor": function(test) {
var strategy = new SampleBackoffStrategy({
randomisationFactor: 0.5,
initialDelay: 1000
});
this.random.returns(0.5);
var backoffDelay = strategy.next();
test.equals(backoffDelay, 1000 + (1000 * 0.5 * 0.5));
test.done();
},
"the initial backoff delay should be greater than 0": function(test) {
test.throws(function() {
new BackoffStrategy({
initialDelay: -1
});
});
test.throws(function() {
new BackoffStrategy({
initialDelay: 0
});
});
test.doesNotThrow(function() {
new BackoffStrategy({
initialDelay: 1
});
});
test.done();
},
"the maximal backoff delay should be greater than 0": function(test) {
test.throws(function() {
new BackoffStrategy({
maxDelay: -1
});
});
test.throws(function() {
new BackoffStrategy({
maxDelay: 0
});
});
test.done();
},
"the maximal backoff delay should be greater than the initial backoff delay": function(test) {
test.throws(function() {
new BackoffStrategy({
initialDelay: 10,
maxDelay: 10
});
});
test.doesNotThrow(function() {
new BackoffStrategy({
initialDelay: 10,
maxDelay: 11
});
});
test.done();
}
};

View File

@ -0,0 +1,61 @@
/*
* Copyright (c) 2012 Mathieu Turcotte
* Licensed under the MIT license.
*/
var sinon = require('sinon');
var ExponentialBackoffStrategy = require('../lib/strategy/exponential');
exports["ExponentialBackoffStrategy"] = {
"backoff delays should follow an exponential sequence": function(test) {
var strategy = new ExponentialBackoffStrategy({
initialDelay: 10,
maxDelay: 1000
});
// Exponential sequence: x[i] = x[i-1] * 2.
var expectedDelays = [10, 20, 40, 80, 160, 320, 640, 1000, 1000];
var actualDelays = expectedDelays.map(function () {
return strategy.next();
});
test.deepEqual(expectedDelays, actualDelays,
'Generated delays should follow an exponential sequence.');
test.done();
},
"backoff delay factor should be configurable": function (test) {
var strategy = new ExponentialBackoffStrategy({
initialDelay: 10,
maxDelay: 270,
factor: 3
});
// Exponential sequence: x[i] = x[i-1] * 3.
var expectedDelays = [10, 30, 90, 270, 270];
var actualDelays = expectedDelays.map(function () {
return strategy.next();
});
test.deepEqual(expectedDelays, actualDelays,
'Generated delays should follow a configurable exponential sequence.');
test.done();
},
"backoff delays should restart from the initial delay after reset": function(test) {
var strategy = new ExponentialBackoffStrategy({
initialDelay: 10,
maxDelay: 1000
});
strategy.next();
strategy.reset();
var backoffDelay = strategy.next();
test.equals(backoffDelay, 10,
'Strategy should return the initial delay after reset.');
test.done();
}
};

View File

@ -0,0 +1,47 @@
/*
* Copyright (c) 2012 Mathieu Turcotte
* Licensed under the MIT license.
*/
var sinon = require('sinon');
var FibonacciBackoffStrategy = require('../lib/strategy/fibonacci');
exports["FibonacciBackoffStrategy"] = {
setUp: function(callback) {
this.strategy = new FibonacciBackoffStrategy({
initialDelay: 10,
maxDelay: 1000
});
callback();
},
"backoff delays should follow a Fibonacci sequence": function(test) {
// Fibonacci sequence: x[i] = x[i-1] + x[i-2].
var expectedDelays = [10, 10, 20, 30, 50, 80, 130, 210, 340, 550, 890, 1000];
var actualDelays = [];
for (var i = 0; i < expectedDelays.length; i++) {
actualDelays.push(this.strategy.next());
}
test.deepEqual(expectedDelays, actualDelays,
'Generated delays should follow a Fibonacci sequence.');
test.done();
},
"backoff delays should restart from the initial delay after reset": function(test) {
var strategy = new FibonacciBackoffStrategy({
initialDelay: 10,
maxDelay: 1000
});
strategy.next();
strategy.reset();
var backoffDelay = strategy.next();
test.equals(backoffDelay, 10,
'Strategy should return the initial delay after reset.');
test.done();
}
};

406
node_modules/backoff/tests/function_call.js generated vendored Normal file
View File

@ -0,0 +1,406 @@
/*
* Copyright (c) 2012 Mathieu Turcotte
* Licensed under the MIT license.
*/
var assert = require('assert');
var events = require('events');
var sinon = require('sinon');
var util = require('util');
var FunctionCall = require('../lib/function_call');
function MockBackoff() {
events.EventEmitter.call(this);
this.reset = sinon.spy();
this.backoff = sinon.spy();
this.failAfter = sinon.spy();
}
util.inherits(MockBackoff, events.EventEmitter);
exports["FunctionCall"] = {
setUp: function(callback) {
this.wrappedFn = sinon.stub();
this.callback = sinon.stub();
this.backoff = new MockBackoff();
this.backoffFactory = sinon.stub();
this.backoffFactory.returns(this.backoff);
callback();
},
tearDown: function(callback) {
callback();
},
"constructor's first argument should be a function": function(test) {
test.throws(function() {
new FunctionCall(1, [], function() {});
}, /Expected fn to be a function./);
test.done();
},
"constructor's last argument should be a function": function(test) {
test.throws(function() {
new FunctionCall(function() {}, [], 3);
}, /Expected callback to be a function./);
test.done();
},
"isPending should return false once the call is started": function(test) {
this.wrappedFn.
onFirstCall().yields(new Error()).
onSecondCall().yields(null, 'Success!');
var call = new FunctionCall(this.wrappedFn, [], this.callback);
test.ok(call.isPending());
call.start(this.backoffFactory);
test.ok(!call.isPending());
this.backoff.emit('ready');
test.ok(!call.isPending());
test.done();
},
"isRunning should return true when call is in progress": function(test) {
this.wrappedFn.
onFirstCall().yields(new Error()).
onSecondCall().yields(null, 'Success!');
var call = new FunctionCall(this.wrappedFn, [], this.callback);
test.ok(!call.isRunning());
call.start(this.backoffFactory);
test.ok(call.isRunning());
this.backoff.emit('ready');
test.ok(!call.isRunning());
test.done();
},
"isCompleted should return true once the call completes": function(test) {
this.wrappedFn.
onFirstCall().yields(new Error()).
onSecondCall().yields(null, 'Success!');
var call = new FunctionCall(this.wrappedFn, [], this.callback);
test.ok(!call.isCompleted());
call.start(this.backoffFactory);
test.ok(!call.isCompleted());
this.backoff.emit('ready');
test.ok(call.isCompleted());
test.done();
},
"isAborted should return true once the call is aborted": function(test) {
this.wrappedFn.
onFirstCall().yields(new Error()).
onSecondCall().yields(null, 'Success!');
var call = new FunctionCall(this.wrappedFn, [], this.callback);
test.ok(!call.isAborted());
call.abort();
test.ok(call.isAborted());
test.done();
},
"setStrategy should overwrite the default strategy": function(test) {
var replacementStrategy = {};
var call = new FunctionCall(this.wrappedFn, [], this.callback);
call.setStrategy(replacementStrategy);
call.start(this.backoffFactory);
test.ok(this.backoffFactory.calledWith(replacementStrategy),
'User defined strategy should be used to instantiate ' +
'the backoff instance.');
test.done();
},
"setStrategy should throw if the call is in progress": function(test) {
var call = new FunctionCall(this.wrappedFn, [], this.callback);
call.start(this.backoffFactory);
test.throws(function() {
call.setStrategy({});
}, /in progress/);
test.done();
},
"failAfter should not be set by default": function(test) {
var call = new FunctionCall(this.wrappedFn, [], this.callback);
call.start(this.backoffFactory);
test.equal(0, this.backoff.failAfter.callCount);
test.done();
},
"failAfter should be used as the maximum number of backoffs": function(test) {
var failAfterValue = 99;
var call = new FunctionCall(this.wrappedFn, [], this.callback);
call.failAfter(failAfterValue);
call.start(this.backoffFactory);
test.ok(this.backoff.failAfter.calledWith(failAfterValue),
'User defined maximum number of backoffs shoud be ' +
'used to configure the backoff instance.');
test.done();
},
"failAfter should throw if the call is in progress": function(test) {
var call = new FunctionCall(this.wrappedFn, [], this.callback);
call.start(this.backoffFactory);
test.throws(function() {
call.failAfter(1234);
}, /in progress/);
test.done();
},
"start shouldn't allow overlapping invocation": function(test) {
var call = new FunctionCall(this.wrappedFn, [], this.callback);
var backoffFactory = this.backoffFactory;
call.start(backoffFactory);
test.throws(function() {
call.start(backoffFactory);
}, /already started/);
test.done();
},
"start shouldn't allow invocation of aborted call": function(test) {
var call = new FunctionCall(this.wrappedFn, [], this.callback);
var backoffFactory = this.backoffFactory;
call.abort();
test.throws(function() {
call.start(backoffFactory);
}, /aborted/);
test.done();
},
"call should forward its arguments to the wrapped function": function(test) {
var call = new FunctionCall(this.wrappedFn, [1, 2, 3], this.callback);
call.start(this.backoffFactory);
test.ok(this.wrappedFn.calledWith(1, 2, 3));
test.done();
},
"call should complete when the wrapped function succeeds": function(test) {
var call = new FunctionCall(this.wrappedFn, [1, 2, 3], this.callback);
this.wrappedFn.
onCall(0).yields(new Error()).
onCall(1).yields(new Error()).
onCall(2).yields(new Error()).
onCall(3).yields(null, 'Success!');
call.start(this.backoffFactory);
for (var i = 0; i < 2; i++) {
this.backoff.emit('ready');
}
test.equals(this.callback.callCount, 0);
this.backoff.emit('ready');
test.ok(this.callback.calledWith(null, 'Success!'));
test.ok(this.wrappedFn.alwaysCalledWith(1, 2, 3));
test.done();
},
"call should fail when the backoff limit is reached": function(test) {
var call = new FunctionCall(this.wrappedFn, [1, 2, 3], this.callback);
var error = new Error();
this.wrappedFn.yields(error);
call.start(this.backoffFactory);
for (var i = 0; i < 3; i++) {
this.backoff.emit('ready');
}
test.equals(this.callback.callCount, 0);
this.backoff.emit('fail');
test.ok(this.callback.calledWith(error));
test.ok(this.wrappedFn.alwaysCalledWith(1, 2, 3));
test.done();
},
"call should fail when the retry predicate returns false": function(test) {
var call = new FunctionCall(this.wrappedFn, [1, 2, 3], this.callback);
call.retryIf(function(err) { return err.retriable; });
var retriableError = new Error();
retriableError.retriable = true;
var fatalError = new Error();
fatalError.retriable = false;
this.wrappedFn.
onCall(0).yields(retriableError).
onCall(1).yields(retriableError).
onCall(2).yields(fatalError);
call.start(this.backoffFactory);
for (var i = 0; i < 2; i++) {
this.backoff.emit('ready');
}
test.equals(this.callback.callCount, 1);
test.ok(this.callback.calledWith(fatalError));
test.ok(this.wrappedFn.alwaysCalledWith(1, 2, 3));
test.done();
},
"wrapped function's callback shouldn't be called after abort": function(test) {
var call = new FunctionCall(function(callback) {
call.abort(); // Abort in middle of wrapped function's execution.
callback(null, 'ok');
}, [], this.callback);
call.start(this.backoffFactory);
test.equals(this.callback.callCount, 1,
'Wrapped function\'s callback shouldn\'t be called after abort.');
test.ok(this.callback.calledWithMatch(sinon.match(function (err) {
return !!err.message.match(/Backoff aborted/);
}, "abort error")));
test.done();
},
"abort event is emitted once when abort is called": function(test) {
var call = new FunctionCall(this.wrappedFn, [], this.callback);
this.wrappedFn.yields(new Error());
var callEventSpy = sinon.spy();
call.on('abort', callEventSpy);
call.start(this.backoffFactory);
call.abort();
call.abort();
call.abort();
test.equals(callEventSpy.callCount, 1);
test.done();
},
"getLastResult should return the last intermediary result": function(test) {
var call = new FunctionCall(this.wrappedFn, [], this.callback);
this.wrappedFn.yields(1);
call.start(this.backoffFactory);
for (var i = 2; i < 5; i++) {
this.wrappedFn.yields(i);
this.backoff.emit('ready');
test.deepEqual([i], call.getLastResult());
}
this.wrappedFn.yields(null);
this.backoff.emit('ready');
test.deepEqual([null], call.getLastResult());
test.done();
},
"getNumRetries should return the number of retries": function(test) {
var call = new FunctionCall(this.wrappedFn, [], this.callback);
this.wrappedFn.yields(1);
call.start(this.backoffFactory);
// The inital call doesn't count as a retry.
test.equals(0, call.getNumRetries());
for (var i = 2; i < 5; i++) {
this.wrappedFn.yields(i);
this.backoff.emit('ready');
test.equals(i - 1, call.getNumRetries());
}
this.wrappedFn.yields(null);
this.backoff.emit('ready');
test.equals(4, call.getNumRetries());
test.done();
},
"wrapped function's errors should be propagated": function(test) {
var call = new FunctionCall(this.wrappedFn, [1, 2, 3], this.callback);
this.wrappedFn.throws(new Error());
test.throws(function() {
call.start(this.backoffFactory);
}, Error);
test.done();
},
"wrapped callback's errors should be propagated": function(test) {
var call = new FunctionCall(this.wrappedFn, [1, 2, 3], this.callback);
this.wrappedFn.yields(null, 'Success!');
this.callback.throws(new Error());
test.throws(function() {
call.start(this.backoffFactory);
}, Error);
test.done();
},
"call event should be emitted when wrapped function gets called": function(test) {
this.wrappedFn.yields(1);
var callEventSpy = sinon.spy();
var call = new FunctionCall(this.wrappedFn, [1, 'two'], this.callback);
call.on('call', callEventSpy);
call.start(this.backoffFactory);
for (var i = 1; i < 5; i++) {
this.backoff.emit('ready');
}
test.equal(5, callEventSpy.callCount,
'The call event should have been emitted 5 times.');
test.deepEqual([1, 'two'], callEventSpy.getCall(0).args,
'The call event should carry function\'s args.');
test.done();
},
"callback event should be emitted when callback is called": function(test) {
var call = new FunctionCall(this.wrappedFn, [1, 'two'], this.callback);
var callbackSpy = sinon.spy();
call.on('callback', callbackSpy);
this.wrappedFn.yields('error');
call.start(this.backoffFactory);
this.wrappedFn.yields(null, 'done');
this.backoff.emit('ready');
test.equal(2, callbackSpy.callCount,
'Callback event should have been emitted 2 times.');
test.deepEqual(['error'], callbackSpy.firstCall.args,
'First callback event should carry first call\'s results.');
test.deepEqual([null, 'done'], callbackSpy.secondCall.args,
'Second callback event should carry second call\'s results.');
test.done();
},
"backoff event should be emitted on backoff start": function(test) {
var err = new Error('backoff event error');
var call = new FunctionCall(this.wrappedFn, [1, 'two'], this.callback);
var backoffSpy = sinon.spy();
call.on('backoff', backoffSpy);
this.wrappedFn.yields(err);
call.start(this.backoffFactory);
this.backoff.emit('backoff', 3, 1234, err);
test.ok(this.backoff.backoff.calledWith(err),
'The backoff instance should have been called with the error.');
test.equal(1, backoffSpy.callCount,
'Backoff event should have been emitted 1 time.');
test.deepEqual([3, 1234, err], backoffSpy.firstCall.args,
'Backoff event should carry the backoff number, delay and error.');
test.done();
}
};