/*
*
* Copyright 2016 Robert Winkler and Bohdan Storozhuk
*
* 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.circuitbreaker.concurrent;
import static io.github.resilience4j.circuitbreaker.CircuitBreaker.StateTransition;
import static io.github.resilience4j.circuitbreaker.CircuitBreaker.of;
import static io.github.resilience4j.circuitbreaker.event.CircuitBreakerEvent.Type;
import io.github.resilience4j.circuitbreaker.CircuitBreakerConfig;
import io.github.resilience4j.circuitbreaker.event.CircuitBreakerEvent;
import io.github.resilience4j.circuitbreaker.event.CircuitBreakerOnStateTransitionEvent;
import io.github.resilience4j.circuitbreaker.internal.CircuitBreakerStateMachine;
import io.reactivex.subscribers.TestSubscriber;
import org.openjdk.jcstress.annotations.Actor;
import org.openjdk.jcstress.annotations.Arbiter;
import org.openjdk.jcstress.annotations.Expect;
import org.openjdk.jcstress.annotations.JCStressTest;
import org.openjdk.jcstress.annotations.Outcome;
import org.openjdk.jcstress.infra.results.StringResult1;
import java.text.MessageFormat;
import java.time.Duration;
@JCStressTest
@org.openjdk.jcstress.annotations.State
@Outcome(
id = "state=OPEN failed=1 buffered=1" +
" events=\\[\\[ERROR, ERROR\\], \\[\\], \\[\\]\\]" +
" transition=\\[\\[State transition from CLOSED to OPEN\\], \\[\\], \\[\\]\\]",
expect = Expect.ACCEPTABLE
)
public class ConcurrentCircuitBreakerTest {
private CircuitBreakerStateMachine circuitBreaker;
private TestSubscriber<Type> errorEventSubscriber;
private TestSubscriber<StateTransition> stateTransitionSubsriber;
public ConcurrentCircuitBreakerTest() {
CircuitBreakerConfig circuitBreakerConfig = CircuitBreakerConfig.custom()
.ringBufferSizeInClosedState(1)
.build();
circuitBreaker = (CircuitBreakerStateMachine) of("testName", circuitBreakerConfig);
errorEventSubscriber = circuitBreaker.getEventStream()
.filter(event -> event.getEventType() == Type.ERROR)
.map(CircuitBreakerEvent::getEventType)
.test();
stateTransitionSubsriber = circuitBreaker.getEventStream()
.filter(event -> event.getEventType() == Type.STATE_TRANSITION)
.cast(CircuitBreakerOnStateTransitionEvent.class)
.map(CircuitBreakerOnStateTransitionEvent::getStateTransition)
.test();
}
@Actor
public void firstActor() {
circuitBreaker.onError(0, new RuntimeException());
}
@Actor
public void secondActor() {
circuitBreaker.onError(0, new RuntimeException());
}
@Arbiter
public void arbiter(StringResult1 result1) {
String result = MessageFormat.format(
"state={0} failed={1} buffered={2} events={3} transition={4}",
circuitBreaker.getState(),
circuitBreaker.getMetrics().getNumberOfFailedCalls(),
circuitBreaker.getMetrics().getNumberOfBufferedCalls(),
errorEventSubscriber.getEvents(),
stateTransitionSubsriber.getEvents()
);
result1.r1 = result;
}
}