text: var common = require('../common');
  var assert = common.assert;
  var fake = common.fake.create();
  var retry = require(common.dir.lib + '/retry');
  
  (function testReset() {
    var error = new Error('some error');
    var operation = retry.operation([1, 2, 3]);
    var attempts = 0;
  
    var finalCallback = fake.callback('finalCallback');
    fake.expectAnytime(finalCallback);
  
    var expectedFinishes = 1;
    var finishes         = 0;
  
    var fn = function() {
      operation.attempt(function(currentAttempt) {
        attempts++;
        assert.equal(currentAttempt, attempts);
        if (operation.retry(error)) {
          return;
        }
  
        finishes++
        assert.equal(expectedFinishes, finishes);
        assert.strictEqual(attempts, 4);
        assert.strictEqual(operation.attempts(), attempts);
        assert.strictEqual(operation.mainError(), error);
  
        if (finishes < 2) {
          attempts = 0;
          expectedFinishes++;
          operation.reset();
          fn()
        } else {
          finalCallback();
        }
      });
    };
  
    fn();
  })();
  
  (function testErrors() {
    var operation = retry.operation();
  
    var error = new Error('some error');
    var error2 = new Error('some other error');
    operation._errors.push(error);
    operation._errors.push(error2);
  
    assert.deepEqual(operation.errors(), [error, error2]);
  })();
  
  (function testMainErrorReturnsMostFrequentError() {
    var operation = retry.operation();
    var error = new Error('some error');
    var error2 = new Error('some other error');
  
    operation._errors.push(error);
    operation._errors.push(error2);
    operation._errors.push(error);
  
    assert.strictEqual(operation.mainError(), error);
  })();
  
  (function testMainErrorReturnsLastErrorOnEqualCount() {
    var operation = retry.operation();
    var error = new Error('some error');
    var error2 = new Error('some other error');
  
    operation._errors.push(error);
    operation._errors.push(error2);
  
    assert.strictEqual(operation.mainError(), error2);
  })();
  
  (function testAttempt() {
    var operation = retry.operation();
    var fn = new Function();
  
    var timeoutOpts = {
      timeout: 1,
      cb: function() {}
    };
    operation.attempt(fn, timeoutOpts);
  
    assert.strictEqual(fn, operation._fn);
    assert.strictEqual(timeoutOpts.timeout, operation._operationTimeout);
    assert.strictEqual(timeoutOpts.cb, operation._operationTimeoutCb);
  })();
  
  (function testRetry() {
    var error = new Error('some error');
    var operation = retry.operation([1, 2, 3]);
    var attempts = 0;
  
    var finalCallback = fake.callback('finalCallback');
    fake.expectAnytime(finalCallback);
  
    var fn = function() {
      operation.attempt(function(currentAttempt) {
        attempts++;
        assert.equal(currentAttempt, attempts);
        if (operation.retry(error)) {
          return;
        }
  
        assert.strictEqual(attempts, 4);
        assert.strictEqual(operation.attempts(), attempts);
        assert.strictEqual(operation.mainError(), error);
        finalCallback();
      });
    };
  
    fn();
  })();
  
  (function testRetryForever() {
    var error = new Error('some error');
    var operation = retry.operation({ retries: 3, forever: true });
    var attempts = 0;
  
    var finalCallback = fake.callback('finalCallback');
    fake.expectAnytime(finalCallback);
  
    var fn = function() {
      operation.attempt(function(currentAttempt) {
        attempts++;
        assert.equal(currentAttempt, attempts);
        if (attempts !== 6 && operation.retry(error)) {
          return;
        }
  
        assert.strictEqual(attempts, 6);
        assert.strictEqual(operation.attempts(), attempts);
        assert.strictEqual(operation.mainError(), error);
        finalCallback();
      });
    };
  
    fn();
  })();
  
  (function testRetryForeverNoRetries() {
    var error = new Error('some error');
    var delay = 50
    var operation = retry.operation({
      retries: null,
      forever: true,
      minTimeout: delay,
      maxTimeout: delay
    });
  
    var attempts = 0;
    var startTime = new Date().getTime();
  
    var finalCallback = fake.callback('finalCallback');
    fake.expectAnytime(finalCallback);
  
    var fn = function() {
      operation.attempt(function(currentAttempt) {
        attempts++;
        assert.equal(currentAttempt, attempts);
        if (attempts !== 4 && operation.retry(error)) {
          return;
        }
  
        var endTime = new Date().getTime();
        var minTime = startTime + (delay * 3);
        var maxTime = minTime + 20 // add a little headroom for code execution time
        assert(endTime >= minTime)
        assert(endTime < maxTime)
        assert.strictEqual(attempts, 4);
        assert.strictEqual(operation.attempts(), attempts);
        assert.strictEqual(operation.mainError(), error);
        finalCallback();
      });
    };
  
    fn();
  })();
  
  (function testStop() {
    var error = new Error('some error');
    var operation = retry.operation([1, 2, 3]);
    var attempts = 0;
  
    var finalCallback = fake.callback('finalCallback');
    fake.expectAnytime(finalCallback);
  
    var fn = function() {
      operation.attempt(function(currentAttempt) {
        attempts++;
        assert.equal(currentAttempt, attempts);
  
        if (attempts === 2) {
          operation.stop();
  
          assert.strictEqual(attempts, 2);
          assert.strictEqual(operation.attempts(), attempts);
          assert.strictEqual(operation.mainError(), error);
          finalCallback();
        }
  
        if (operation.retry(error)) {
          return;
        }
      });
    };
  
    fn();
  })();
  
  (function testMaxRetryTime() {
    var error = new Error('some error');
    var maxRetryTime = 30;
    var operation = retry.operation({
        minTimeout: 1,
        maxRetryTime: maxRetryTime
    });
    var attempts = 0;
  
    var finalCallback = fake.callback('finalCallback');
    fake.expectAnytime(finalCallback);
  
    var longAsyncFunction = function (wait, callback){
      setTimeout(callback, wait);
    };
  
    var fn = function() {
      var startTime = new Date().getTime();
      operation.attempt(function(currentAttempt) {
        attempts++;
        assert.equal(currentAttempt, attempts);
  
        if (attempts !== 2) {
          if (operation.retry(error)) {
              return;
          }
        } else {
          var curTime = new Date().getTime();
          longAsyncFunction(maxRetryTime - (curTime - startTime - 1), function(){
            if (operation.retry(error)) {
              assert.fail('timeout should be occurred');
              return;
            }
  
            assert.strictEqual(operation.mainError(), error);
            finalCallback();
          });
        }
      });
    };
  
    fn();
  })();
  