Example #1
0
def test_exception_whitelist(error_func):
    breaker = CircuitBreaker(error_threshold=1,
                             exception_whitelist=[IOError],
                             recovery_timeout=1)
    breaker.call(error_func)

    assert breaker.state == CircuitBreakerState.CLOSED
Example #2
0
def test_exception_whitelist_supports_inheritance(error_func):
    breaker = CircuitBreaker(error_threshold=1,
                             exception_whitelist=[Exception],
                             recovery_timeout=1)
    breaker.call(error_func)

    assert breaker.state == CircuitBreakerState.CLOSED
Example #3
0
def test_exception_blacklist_filters_errors(error_func):
    # When the blacklist is specified, only those errors are caught
    breaker = CircuitBreaker(error_threshold=1,
                             exception_blacklist=[ValueError],
                             recovery_timeout=1)
    breaker.call(error_func)

    assert breaker.state == CircuitBreakerState.CLOSED
Example #4
0
def test_breaker_recloses_after_recovery_time(error_func):
    breaker = CircuitBreaker(error_threshold=1, recovery_timeout=1)

    with pytest.raises(IOError):
        breaker.call(error_func)

    assert breaker.state == CircuitBreakerState.OPEN

    sleep(1)
    assert breaker.state == CircuitBreakerState.HALF_OPEN
Example #5
0
def test_exception_blacklist_supports_inheritance(error_func):
    # When the blacklist is specified, only those errors are caught
    breaker = CircuitBreaker(error_threshold=1,
                             exception_blacklist=[Exception],
                             recovery_timeout=1)

    with pytest.raises(IOError):
        breaker.call(error_func)

    assert breaker.state == CircuitBreakerState.OPEN
Example #6
0
def test_notifies_on_breaker_open(error_func, io_error):
    mock_open = mock.Mock()
    breaker = CircuitBreaker(error_threshold=1, on_open=mock_open)

    assert mock_open.call_count == 0

    with pytest.raises(IOError):
        breaker.call(error_func)

    mock_open.assert_called_once()
    mock_open.assert_called_with(breaker, io_error)
Example #7
0
def half_open_breaker(error_func):
    breaker = CircuitBreaker(error_threshold=1,
                             recovery_timeout=1,
                             recovery_threshold=2)

    with pytest.raises(IOError):
        breaker.call(error_func)

    sleep(1)

    return breaker
Example #8
0
def test_get_circuits_not_empty():
    registry = CircuitBreakerRegistry()
    db_circuit = CircuitBreaker(breaker_id="db")
    service_circuit = CircuitBreaker(breaker_id="service")

    registry.register(db_circuit)
    registry.register(service_circuit)

    registered = registry.get_circuits()
    assert len(registered) == 2
    assert db_circuit in registered
    assert service_circuit in registered
Example #9
0
def test_can_detect_errors_that_are_not_exceptions(error_val, expected_state):
    breaker = CircuitBreaker(
        detect_error=lambda ret_val: ret_val is False,
        error_threshold=1,
    )

    def return_code_error():
        return error_val

    result = breaker.call(return_code_error)
    assert result is error_val
    assert breaker.state is expected_state
Example #10
0
def test_get_open_circuits_when_one_circuit_is_open(error_func):
    registry = CircuitBreakerRegistry()
    open_circuit = CircuitBreaker(breaker_id="open_breaker", error_threshold=1)
    closed_circuit = CircuitBreaker(breaker_id="closed_breaker")
    registry.register(open_circuit)
    registry.register(closed_circuit)

    with pytest.raises(IOError):
        open_circuit.call(error_func)

    opened = registry.get_open_circuits()

    assert len(opened) == 1
    assert open_circuit in opened
    assert closed_circuit not in opened
Example #11
0
def test_get_open_circuits_when_all_circuits_are_closed():
    registry = CircuitBreakerRegistry()
    circuit = CircuitBreaker(breaker_id="closed_breaker", error_threshold=1)
    registry.register(circuit)

    opened = registry.get_open_circuits()

    assert len(opened) == 0
Example #12
0
def test_register_new_circuit_breaker():
    registry = CircuitBreakerRegistry()
    circuit_breaker = CircuitBreaker()

    registry.register(circuit_breaker)

    registered = registry.get_circuits()
    assert len(registered) == 1
    assert registered[0] == circuit_breaker
Example #13
0
def test_register_existing_circuit_breaker():
    registry = CircuitBreakerRegistry()
    circuit_breaker = CircuitBreaker()

    registry.register(circuit_breaker)

    with pytest.raises(CircuitBreakerRegistryException):
        registry.register(circuit_breaker)

    registered = registry.get_circuits()
    assert len(registered) == 1
    assert registered[0] == circuit_breaker
Example #14
0
def test_calling_an_open_breaker_raises_an_error(error_func):
    breaker = CircuitBreaker(error_threshold=1,
                             recovery_timeout=1,
                             recovery_threshold=2)

    with pytest.raises(IOError):
        breaker.call(error_func)

    with pytest.raises(CircuitBreakerException):
        breaker.call(error_func)
Example #15
0
def test_breaker_opens_after_specified_number_of_errors(error_func):
    breaker = CircuitBreaker(error_threshold=2)

    with pytest.raises(IOError):
        breaker.call(error_func)
    assert breaker.state == CircuitBreakerState.CLOSED

    with pytest.raises(IOError):
        breaker.call(error_func)

    assert breaker.state == CircuitBreakerState.OPEN
Example #16
0
def test_net_error_strategy_half_open_to_closed(error_func, success_func):
    breaker = CircuitBreaker(
        strategy=CircuitBreakerStrategy.NET_ERROR,
        error_threshold=1,
        recovery_timeout=1,
    )

    with pytest.raises(IOError):
        breaker.call(error_func)

    assert breaker.state == CircuitBreakerState.OPEN

    sleep(1)
    assert breaker.state == CircuitBreakerState.HALF_OPEN

    breaker.call(success_func)
    assert breaker.state == CircuitBreakerState.CLOSED
Example #17
0
def test_notifies_on_breaker_close(error_func, success_func):
    mock_close = mock.Mock()
    breaker = CircuitBreaker(
        error_threshold=1,
        on_close=mock_close,
        recovery_timeout=1,
    )

    assert mock_close.call_count == 0

    with pytest.raises(IOError):
        breaker.call(error_func)

    assert mock_close.call_count == 0

    sleep(1)
    breaker.call(success_func)

    assert mock_close.call_count == 1
Example #18
0
def test_breaker_starts_closed():
    breaker = CircuitBreaker()
    assert breaker.state == CircuitBreakerState.CLOSED
Example #19
0
def test_unknown_strategy_causes_error():
    with pytest.raises(ValueError):
        CircuitBreaker(strategy="foo")
Example #20
0
def test_net_error_strategy_count_never_negative(success_func):
    breaker = CircuitBreaker(strategy=CircuitBreakerStrategy.NET_ERROR, )
    breaker.call(success_func)

    assert breaker._strategy._net_error_count == 0
Example #21
0
def test_net_error_strategy(error_func, success_func):
    breaker = CircuitBreaker(
        strategy=CircuitBreakerStrategy.NET_ERROR,
        error_threshold=3,
    )

    with pytest.raises(IOError):
        breaker.call(error_func)

    assert breaker.state == CircuitBreakerState.CLOSED

    with pytest.raises(IOError):
        breaker.call(error_func)

    assert breaker.state == CircuitBreakerState.CLOSED

    breaker.call(success_func)

    with pytest.raises(IOError):
        breaker.call(error_func)

    assert breaker.state == CircuitBreakerState.CLOSED

    with pytest.raises(IOError):
        breaker.call(error_func)

    assert breaker.state == CircuitBreakerState.OPEN
Example #22
0
def test_circuit_breaker_exception_serialization():
    breaker = CircuitBreaker(breaker_id="FOO")
    exception = CircuitBreakerException(breaker)
    exception_str = str(exception)
    assert "Circuit FOO OPEN until" in exception_str