/*
*
* Copyright 2016 Robert Winkler
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
*
*/
package io.github.resilience4j.consumer;
import io.github.resilience4j.circuitbreaker.CircuitBreaker;
import io.github.resilience4j.circuitbreaker.CircuitBreakerConfig;
import io.github.resilience4j.circuitbreaker.event.CircuitBreakerEvent;
import io.github.resilience4j.circuitbreaker.event.CircuitBreakerOnErrorEvent;
import io.vavr.API;
import org.junit.Test;
import javax.xml.ws.WebServiceException;
import java.io.IOException;
import static io.github.resilience4j.circuitbreaker.event.CircuitBreakerEvent.Type;
import static io.vavr.API.$;
import static io.vavr.API.Case;
import static io.vavr.Predicates.instanceOf;
import static org.assertj.core.api.Assertions.assertThat;
public class CircularEventConsumerTest {
@Test
public void shouldBufferErrorEvents() {
// Given
// tag::shouldBufferEvents[]
CircuitBreaker circuitBreaker = CircuitBreaker.ofDefaults("testName");
CircularEventConsumer<CircuitBreakerOnErrorEvent> ringBuffer = new CircularEventConsumer<>(2);
circuitBreaker.getEventStream()
.filter(event -> event.getEventType() == Type.ERROR)
.cast(CircuitBreakerOnErrorEvent.class)
.subscribe(ringBuffer);
// end::shouldBufferEvents[]
assertThat(ringBuffer.getBufferedEvents()).isEmpty();
//When
circuitBreaker.onError(0, new RuntimeException("Bla"));
circuitBreaker.onError(0, new RuntimeException("Bla"));
circuitBreaker.onError(0, new RuntimeException("Bla"));
//Then
CircuitBreaker.Metrics metrics = circuitBreaker.getMetrics();
assertThat(metrics.getNumberOfBufferedCalls()).isEqualTo(3);
assertThat(metrics.getNumberOfFailedCalls()).isEqualTo(3);
//Should only store 2 events, because capacity is 2
assertThat(ringBuffer.getBufferedEvents()).hasSize(2);
//ringBuffer.getBufferedEvents().forEach(event -> LOG.info(event.toString()));
}
@Test
public void shouldBufferAllEvents() {
// Given
CircuitBreakerConfig circuitBreakerConfig = CircuitBreakerConfig.custom()
.ringBufferSizeInClosedState(3)
.recordFailure(throwable -> API.Match(throwable).of(
Case($(instanceOf(WebServiceException.class)), true),
Case($(), false)))
.build();
CircuitBreaker circuitBreaker = CircuitBreaker.of("testName", circuitBreakerConfig);
CircularEventConsumer<CircuitBreakerEvent> ringBuffer = new CircularEventConsumer<>(10);
circuitBreaker.getEventStream()
.subscribe(ringBuffer);
assertThat(ringBuffer.getBufferedEvents()).isEmpty();
//When
circuitBreaker.onSuccess(0);
circuitBreaker.onError(0, new WebServiceException("Bla"));
circuitBreaker.onError(0, new IOException("Bla"));
circuitBreaker.onError(0, new WebServiceException("Bla"));
//Then
CircuitBreaker.Metrics metrics = circuitBreaker.getMetrics();
assertThat(metrics.getNumberOfBufferedCalls()).isEqualTo(3);
assertThat(metrics.getNumberOfFailedCalls()).isEqualTo(2);
//Should store 3 events, because circuit emits 2 error events and one state transition event
assertThat(ringBuffer.getBufferedEvents()).hasSize(5);
assertThat(ringBuffer.getBufferedEvents()).extracting("eventType")
.containsExactly(Type.SUCCESS, Type.ERROR, Type.IGNORED_ERROR, Type.ERROR, Type.STATE_TRANSITION);
//ringBuffer.getBufferedEvents().forEach(event -> LOG.info(event.toString()));
}
@Test
public void shouldNotBufferEvents() {
// Given
CircuitBreaker circuitBreaker = CircuitBreaker.ofDefaults("testName");
CircularEventConsumer<CircuitBreakerOnErrorEvent> ringBuffer = new CircularEventConsumer<>(2);
assertThat(ringBuffer.getBufferedEvents()).isEmpty();
circuitBreaker.onError(0, new RuntimeException("Bla"));
circuitBreaker.onError(0, new RuntimeException("Bla"));
circuitBreaker.onError(0, new RuntimeException("Bla"));
//Subscription is too late
circuitBreaker.getEventStream()
.filter(event -> event.getEventType() == Type.ERROR)
.cast(CircuitBreakerOnErrorEvent.class)
.subscribe(ringBuffer);
//Then
CircuitBreaker.Metrics metrics = circuitBreaker.getMetrics();
assertThat(metrics.getNumberOfBufferedCalls()).isEqualTo(3);
assertThat(metrics.getNumberOfFailedCalls()).isEqualTo(3);
//Should store 0 events, because Subscription was too late
assertThat(ringBuffer.getBufferedEvents()).hasSize(0);
}
}