diff --git a/test/common.js b/test/common.js index c9de00c7..d45b85b2 100644 --- a/test/common.js +++ b/test/common.js @@ -33,6 +33,17 @@ function timedFunction (ms) { }); } +function timedFailingFunction (ms) { + return new Promise((resolve, reject) => { + const timer = setTimeout(() => { + reject(`Failed after ${ms}`); + }, ms); + if (typeof timer.unref === 'function') { + timer.unref(); + } + }); +} + function nonPromise () { return 'foo'; } @@ -49,6 +60,7 @@ module.exports = exports = { passFail, slowFunction, timedFunction, + timedFailingFunction, callbackFunction, failedCallbackFunction, nonPromise diff --git a/test/half-open-test.js b/test/half-open-test.js new file mode 100644 index 00000000..b4dc0f70 --- /dev/null +++ b/test/half-open-test.js @@ -0,0 +1,42 @@ +'use strict'; + +const test = require('tape'); +const opossum = require('../'); +const { timedFailingFunction } = require('./common'); + +test('When half-open, the circuit only allows one request through', t => { + t.plan(12); + const options = { + errorThresholdPercentage: 1, + resetTimeout: 500 + }; + + const breaker = opossum(timedFailingFunction, options); + breaker.fire(1) + .catch((e) => t.equals(e, 'Failed after 1')) + .then(() => { + t.ok(breaker.opened, 'breaker should be open'); + t.notOk(breaker.pendingClose, 'breaker should not be pending close'); + }) + .then(() => { + setTimeout(() => { + t.ok(breaker.halfOpen, 'breaker should be halfOpen'); + t.ok(breaker.pendingClose, 'breaker should be pending close'); + breaker + .fire(500) // fail after a long time, letting possibly other fire()s to occur + .catch((e) => t.equals(e, 'Failed after 500', 'function should fail again')) + .then(() => { + t.ok(breaker.opened, 'breaker should be open again'); + t.notOk(breaker.halfOpen, 'breaker should not be halfOpen'); + t.notOk(breaker.pendingClose, 'breaker should not be pending close'); + }); + }, options.resetTimeout * 1.1); + }); + // fire the breaker again, and be sure it fails as expected + breaker.fire(1) + .catch((e) => t.equals(e, 'Failed after 1')) + .then(() => { + t.ok(breaker.opened, 'breaker should be open'); + t.notOk(breaker.pendingClose, 'breaker should not be pending close'); + }); +});