I am using JUnit 5, running test with simple mvn clean test. I have a few services/utilities that require some waiting in test, in order to test their functionality. One of them is a simple circuit breaker.
public class DefaultHttpCircuitBreaker implements CircuitBreaker<HttpResponse> {
    private enum State {
        CLOSED,
        OPEN,
        HALF_OPEN
    }
    private final int failureThreshold;
    private final long retryPeriod;
    private State state;
    private int failureCount;
    private long lastFailureTime;
    private String lastFailureMessage;
    public DefaultHttpCircuitBreaker(int failureThreshold, long retryPeriod) {
        this.retryPeriod = retryPeriod;
        this.state = State.CLOSED;
        this.failureCount = 0;
        this.failureThreshold = failureThreshold;
    }
    @Override
    public RemoteServiceResponse<HttpResponse> attemptCall(Caller<HttpResponse> caller) {
        evaluateState();
        if (this.state == State.OPEN) {
            return RemoteServiceResponse.failure(lastFailureMessage);
        } else {
            try {
                HttpResponse response = caller.call();
                int result = response.getStatusLine().getStatusCode();
                if (result < 200 || result >= 300) {
                    recordFailure(response.getStatusLine().getReasonPhrase());
                    return RemoteServiceResponse.failure(lastFailureMessage);
                }
                resetCount();
                return RemoteServiceResponse.success(response);
            } catch (Exception e) {
                recordFailure(e.getMessage());
                return RemoteServiceResponse.communicationError(lastFailureMessage);
            }
        }
    }
    @Override
    public long getLastFailureTime() {
        return lastFailureTime;
    }
    @Override
    public int getFailureCount(){
        return failureCount;
    }
    private void recordFailure(String message) {
        failureCount++;
        this.lastFailureMessage = message;
        this.lastFailureTime = System.currentTimeMillis();
    }
    private void evaluateState() {
        if (failureCount >= failureThreshold) {
            if ((System.currentTimeMillis() - lastFailureTime) > retryPeriod) {
                this.state = State.HALF_OPEN;
            } else {
                this.state = State.OPEN;
            }
        } else {
            this.state = State.CLOSED;
        }
    }
    private void resetCount() {
        this.failureCount = 0;
        this.state = State.CLOSED;
        lastFailureTime = 0;
    }
}
As you can see, when the CircuitBreaker is open, and certain time has passed, it become half open, so it can attempt to do call once more.
And the test:
void testHalfOpenSuccess() throws InterruptedException {
    int failureThreshold = 5;
    String reasonPhrase = "testPhrase";
    long retryPeriod = 10000;
    StatusLine line = new BasicStatusLine(new ProtocolVersion("version", 1, 1), 300, reasonPhrase);
    Mockito.when(response.getStatusLine()).thenReturn(line);
    CircuitBreaker<HttpResponse> circuitBreaker = new DefaultHttpCircuitBreaker(failureThreshold, retryPeriod);
    long lastFailureTime = 0;
    for (int i = 0; i < failureThreshold; i++) {
        RemoteServiceResponse<HttpResponse> res = circuitBreaker.attemptCall(() -> client.execute(new HttpGet("testUrl")));
        lastFailureTime = circuitBreaker.getLastFailureTime();
        Assertions.assertTrue(res.isFail());
        Assertions.assertEquals(reasonPhrase, res.getErrMessage());
    }
    RemoteServiceResponse<HttpResponse> res = circuitBreaker.attemptCall(() -> client.execute(new HttpGet("testUrl")));
    Assertions.assertTrue(res.isFail());
    Assertions.assertEquals(reasonPhrase, res.getErrMessage());
    Assertions.assertEquals(lastFailureTime, circuitBreaker.getLastFailureTime());
    Thread.sleep(2 *retryPeriod); //NOSONAR
    Mockito.when(response.getStatusLine()).thenReturn(new BasicStatusLine(new ProtocolVersion("version", 1, 1), 200, reasonPhrase));
    RemoteServiceResponse<HttpResponse> resSuccess = circuitBreaker.attemptCall(() -> client.execute(new HttpGet("testUrl")));
    Assertions.assertTrue(resSuccess.isSuccess());
    Assertions.assertEquals(0, circuitBreaker.getFailureCount());
    Assertions.assertEquals(0, circuitBreaker.getLastFailureTime());
}
This test attempts to call service threshold times, all should fail. Then it tries to call it instantly one more time just it to fail. However, then i sleep the thread so the retryPeriod has passed and the CircuitBreaker can attempt to call once more.
This test works. However, when I run it with mvn clean test it randomly fails 1 out of 10 times. What is reason for this? If I run this test using IntelliJ, it never fails. What is the reason maven fails test using Thread.sleep()? Same thing happens when I run test that uses wait() and notify(). However only the last defined test in class fails like this.
What fails is last Assertions.assertTrue(resSuccess.isSuccess());
What is the reason?
