Index: node_modules/retry/test/common.js
===================================================================
--- node_modules/retry/test/common.js	(revision 81bc7da776d8cda42939ef4ab350c88d13b4941f)
+++ node_modules/retry/test/common.js	(revision 81bc7da776d8cda42939ef4ab350c88d13b4941f)
@@ -0,0 +1,10 @@
+var common = module.exports;
+var path = require('path');
+
+var rootDir = path.join(__dirname, '..');
+common.dir = {
+  lib: rootDir + '/lib'
+};
+
+common.assert = require('assert');
+common.fake = require('fake');
Index: node_modules/retry/test/integration/test-forever.js
===================================================================
--- node_modules/retry/test/integration/test-forever.js	(revision 81bc7da776d8cda42939ef4ab350c88d13b4941f)
+++ node_modules/retry/test/integration/test-forever.js	(revision 81bc7da776d8cda42939ef4ab350c88d13b4941f)
@@ -0,0 +1,24 @@
+var common = require('../common');
+var assert = common.assert;
+var retry = require(common.dir.lib + '/retry');
+
+(function testForeverUsesFirstTimeout() {
+  var operation = retry.operation({
+    retries: 0,
+    minTimeout: 100,
+    maxTimeout: 100,
+    forever: true
+  });
+
+  operation.attempt(function(numAttempt) {
+    console.log('>numAttempt', numAttempt);
+    var err = new Error("foo");
+    if (numAttempt == 10) {
+      operation.stop();
+    }
+
+    if (operation.retry(err)) {
+      return;
+    }
+  });
+})();
Index: node_modules/retry/test/integration/test-retry-operation.js
===================================================================
--- node_modules/retry/test/integration/test-retry-operation.js	(revision 81bc7da776d8cda42939ef4ab350c88d13b4941f)
+++ node_modules/retry/test/integration/test-retry-operation.js	(revision 81bc7da776d8cda42939ef4ab350c88d13b4941f)
@@ -0,0 +1,258 @@
+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();
+})();
Index: node_modules/retry/test/integration/test-retry-wrap.js
===================================================================
--- node_modules/retry/test/integration/test-retry-wrap.js	(revision 81bc7da776d8cda42939ef4ab350c88d13b4941f)
+++ node_modules/retry/test/integration/test-retry-wrap.js	(revision 81bc7da776d8cda42939ef4ab350c88d13b4941f)
@@ -0,0 +1,101 @@
+var common = require('../common');
+var assert = common.assert;
+var fake = common.fake.create();
+var retry = require(common.dir.lib + '/retry');
+
+function getLib() {
+  return {
+    fn1: function() {},
+    fn2: function() {},
+    fn3: function() {}
+  };
+}
+
+(function wrapAll() {
+  var lib = getLib();
+  retry.wrap(lib);
+  assert.equal(lib.fn1.name, 'bound retryWrapper');
+  assert.equal(lib.fn2.name, 'bound retryWrapper');
+  assert.equal(lib.fn3.name, 'bound retryWrapper');
+}());
+
+(function wrapAllPassOptions() {
+  var lib = getLib();
+  retry.wrap(lib, {retries: 2});
+  assert.equal(lib.fn1.name, 'bound retryWrapper');
+  assert.equal(lib.fn2.name, 'bound retryWrapper');
+  assert.equal(lib.fn3.name, 'bound retryWrapper');
+  assert.equal(lib.fn1.options.retries, 2);
+  assert.equal(lib.fn2.options.retries, 2);
+  assert.equal(lib.fn3.options.retries, 2);
+}());
+
+(function wrapDefined() {
+  var lib = getLib();
+  retry.wrap(lib, ['fn2', 'fn3']);
+  assert.notEqual(lib.fn1.name, 'bound retryWrapper');
+  assert.equal(lib.fn2.name, 'bound retryWrapper');
+  assert.equal(lib.fn3.name, 'bound retryWrapper');
+}());
+
+(function wrapDefinedAndPassOptions() {
+  var lib = getLib();
+  retry.wrap(lib, {retries: 2}, ['fn2', 'fn3']);
+  assert.notEqual(lib.fn1.name, 'bound retryWrapper');
+  assert.equal(lib.fn2.name, 'bound retryWrapper');
+  assert.equal(lib.fn3.name, 'bound retryWrapper');
+  assert.equal(lib.fn2.options.retries, 2);
+  assert.equal(lib.fn3.options.retries, 2);
+}());
+
+(function runWrappedWithoutError() {
+  var callbackCalled;
+  var lib = {method: function(a, b, callback) {
+    assert.equal(a, 1);
+    assert.equal(b, 2);
+    assert.equal(typeof callback, 'function');
+    callback();
+  }};
+  retry.wrap(lib);
+  lib.method(1, 2, function() {
+    callbackCalled = true;
+  });
+  assert.ok(callbackCalled);
+}());
+
+(function runWrappedSeveralWithoutError() {
+  var callbacksCalled = 0;
+  var lib = {
+    fn1: function (a, callback) {
+      assert.equal(a, 1);
+      assert.equal(typeof callback, 'function');
+      callback();
+    },
+    fn2: function (a, callback) {
+      assert.equal(a, 2);
+      assert.equal(typeof callback, 'function');
+      callback();
+    }
+  };
+  retry.wrap(lib, {}, ['fn1', 'fn2']);
+  lib.fn1(1, function() {
+    callbacksCalled++;
+  });
+  lib.fn2(2, function() {
+    callbacksCalled++;
+  });
+  assert.equal(callbacksCalled, 2);
+}());
+
+(function runWrappedWithError() {
+  var callbackCalled;
+  var lib = {method: function(callback) {
+    callback(new Error('Some error'));
+  }};
+  retry.wrap(lib, {retries: 1});
+  lib.method(function(err) {
+    callbackCalled = true;
+    assert.ok(err instanceof Error);
+  });
+  assert.ok(!callbackCalled);
+}());
Index: node_modules/retry/test/integration/test-timeouts.js
===================================================================
--- node_modules/retry/test/integration/test-timeouts.js	(revision 81bc7da776d8cda42939ef4ab350c88d13b4941f)
+++ node_modules/retry/test/integration/test-timeouts.js	(revision 81bc7da776d8cda42939ef4ab350c88d13b4941f)
@@ -0,0 +1,69 @@
+var common = require('../common');
+var assert = common.assert;
+var retry = require(common.dir.lib + '/retry');
+
+(function testDefaultValues() {
+  var timeouts = retry.timeouts();
+
+  assert.equal(timeouts.length, 10);
+  assert.equal(timeouts[0], 1000);
+  assert.equal(timeouts[1], 2000);
+  assert.equal(timeouts[2], 4000);
+})();
+
+(function testDefaultValuesWithRandomize() {
+  var minTimeout = 5000;
+  var timeouts = retry.timeouts({
+    minTimeout: minTimeout,
+    randomize: true
+  });
+
+  assert.equal(timeouts.length, 10);
+  assert.ok(timeouts[0] > minTimeout);
+  assert.ok(timeouts[1] > timeouts[0]);
+  assert.ok(timeouts[2] > timeouts[1]);
+})();
+
+(function testPassedTimeoutsAreUsed() {
+  var timeoutsArray = [1000, 2000, 3000];
+  var timeouts = retry.timeouts(timeoutsArray);
+  assert.deepEqual(timeouts, timeoutsArray);
+  assert.notStrictEqual(timeouts, timeoutsArray);
+})();
+
+(function testTimeoutsAreWithinBoundaries() {
+  var minTimeout = 1000;
+  var maxTimeout = 10000;
+  var timeouts = retry.timeouts({
+    minTimeout: minTimeout,
+    maxTimeout: maxTimeout
+  });
+  for (var i = 0; i < timeouts; i++) {
+    assert.ok(timeouts[i] >= minTimeout);
+    assert.ok(timeouts[i] <= maxTimeout);
+  }
+})();
+
+(function testTimeoutsAreIncremental() {
+  var timeouts = retry.timeouts();
+  var lastTimeout = timeouts[0];
+  for (var i = 0; i < timeouts; i++) {
+    assert.ok(timeouts[i] > lastTimeout);
+    lastTimeout = timeouts[i];
+  }
+})();
+
+(function testTimeoutsAreIncrementalForFactorsLessThanOne() {
+  var timeouts = retry.timeouts({
+    retries: 3,
+    factor: 0.5
+  });
+
+  var expected = [250, 500, 1000];
+  assert.deepEqual(expected, timeouts);
+})();
+
+(function testRetries() {
+  var timeouts = retry.timeouts({retries: 2});
+  assert.strictEqual(timeouts.length, 2);
+})();
