Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 2 additions & 2 deletions build.gradle
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
buildscript {
ext {
springBootVersion = '2.5.2'
springBootVersion = '2.5.3'
}
repositories {
mavenCentral()
Expand All @@ -15,7 +15,7 @@ apply plugin: 'eclipse'
apply plugin: 'org.springframework.boot'
apply plugin: 'io.spring.dependency-management'

sourceCompatibility = 1.8
sourceCompatibility = 11

repositories {
mavenCentral()
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -96,21 +96,21 @@ public Mono<String> monoFailure() {
return execute(businessBService.monoFailure());
}

@GetMapping("monoTimeout")
public Mono<String> monoTimeout(){
return executeWithFallback(businessBService.monoTimeout(), this::monoFallback);
}

@GetMapping("fluxSuccess")
public Flux<String> fluxSuccess(){
return execute(businessBService.fluxFailure());
return execute(businessBService.fluxSuccess());
}

@GetMapping("fluxFailure")
public Flux<String> fluxFailure(){
return execute(businessBService.fluxFailure());
}

@GetMapping("monoTimeout")
public Mono<String> monoTimeout(){
return executeWithFallback(businessBService.monoTimeout(), this::monoFallback);
}

@GetMapping("fluxTimeout")
public Flux<String> fluxTimeout(){
return executeWithFallback(businessBService.fluxTimeout(), this::fluxFallback);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -50,6 +50,11 @@ public Mono<String> monoFailure(){
return businessCService.monoFailure();
}

@GetMapping("monoTimeout")
public Mono<String> monoTimeout(){
return businessCService.monoTimeout();
}

@GetMapping("fluxSuccess")
public Flux<String> fluxSuccess(){
return businessCService.fluxSuccess();
Expand All @@ -60,11 +65,6 @@ public Flux<String> fluxFailure(){
return businessCService.fluxFailure();
}

@GetMapping("monoTimeout")
public Mono<String> monoTimeout(){
return businessCService.monoTimeout();
}

@GetMapping("fluxTimeout")
public Flux<String> fluxTimeout(){
return businessCService.fluxTimeout();
Expand Down
56 changes: 27 additions & 29 deletions src/test/java/io/github/robwin/AbstractIntegrationTest.java
Original file line number Diff line number Diff line change
@@ -1,49 +1,47 @@
package io.github.robwin;

import org.junit.Before;
import org.junit.runner.RunWith;

import io.github.resilience4j.circuitbreaker.CircuitBreaker;
import io.github.resilience4j.circuitbreaker.CircuitBreakerRegistry;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.autoconfigure.web.reactive.AutoConfigureWebTestClient;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.boot.test.web.client.TestRestTemplate;
import org.springframework.test.context.junit4.SpringRunner;
import org.springframework.test.web.reactive.server.WebTestClient;

import io.github.resilience4j.circuitbreaker.CircuitBreaker;
import io.github.resilience4j.circuitbreaker.CircuitBreakerRegistry;
import org.junit.jupiter.api.BeforeAll;


@RunWith(SpringRunner.class)
@AutoConfigureWebTestClient
@SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT,
classes = Application.class)
@SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT, classes = Application.class)
public abstract class AbstractIntegrationTest {

protected static final String BACKEND_A = "backendA";
protected static final String BACKEND_B = "backendB";
protected static final String BACKEND_A = "backendA";
protected static final String BACKEND_B = "backendB";

@Autowired
protected CircuitBreakerRegistry circuitBreakerRegistry;
@Autowired
protected CircuitBreakerRegistry circuitBreakerRegistry;

@Autowired
protected TestRestTemplate restTemplate;
@Autowired
protected TestRestTemplate restTemplate;

@Autowired
protected WebTestClient webClient;
@Autowired
protected WebTestClient webClient;

@Before
public void setup() {
transitionToClosedState(BACKEND_A);
transitionToClosedState(BACKEND_B);
}
@BeforeAll
public void setup() {
transitionToClosedState(BACKEND_A);
transitionToClosedState(BACKEND_B);
}

protected void transitionToOpenState(String circuitBreakerName) {
CircuitBreaker circuitBreaker = circuitBreakerRegistry.circuitBreaker(circuitBreakerName);
circuitBreaker.transitionToOpenState();
}
protected void transitionToOpenState(String circuitBreakerName) {
CircuitBreaker circuitBreaker = circuitBreakerRegistry.circuitBreaker(circuitBreakerName);
circuitBreaker.transitionToOpenState();
}

protected void transitionToClosedState(String circuitBreakerName) {
CircuitBreaker circuitBreaker = circuitBreakerRegistry.circuitBreaker(circuitBreakerName);
circuitBreaker.transitionToClosedState();
}
protected void transitionToClosedState(String circuitBreakerName) {
CircuitBreaker circuitBreaker = circuitBreakerRegistry.circuitBreaker(circuitBreakerName);
circuitBreaker.transitionToClosedState();
}

}
108 changes: 53 additions & 55 deletions src/test/java/io/github/robwin/CircuitBreakerTest.java
Original file line number Diff line number Diff line change
Expand Up @@ -2,64 +2,62 @@

import static io.github.resilience4j.circuitbreaker.CircuitBreaker.State;
import static org.assertj.core.api.Assertions.assertThat;

import org.junit.Test;
import static org.assertj.core.api.Assertions.fail;
import io.vavr.collection.Stream;
import org.junit.jupiter.api.Test;
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;

import io.vavr.collection.Stream;

public class CircuitBreakerTest extends AbstractCircuitBreakerTest {

@Test
public void shouldOpenBackendACircuitBreaker() {
// When
Stream.rangeClosed(1,2).forEach((count) -> produceFailure(BACKEND_A));

// Then
checkHealthStatus(BACKEND_A, State.OPEN);
}

@Test
public void shouldCloseBackendACircuitBreaker() {
transitionToOpenState(BACKEND_A);
circuitBreakerRegistry.circuitBreaker(BACKEND_A).transitionToHalfOpenState();

// When
Stream.rangeClosed(1,3).forEach((count) -> produceSuccess(BACKEND_A));

// Then
checkHealthStatus(BACKEND_A, State.CLOSED);
}

@Test
public void shouldOpenBackendBCircuitBreaker() {
// When
Stream.rangeClosed(1,4).forEach((count) -> produceFailure(BACKEND_B));

// Then
checkHealthStatus(BACKEND_B, State.OPEN);
}

@Test
public void shouldCloseBackendBCircuitBreaker() {
transitionToOpenState(BACKEND_B);
circuitBreakerRegistry.circuitBreaker(BACKEND_B).transitionToHalfOpenState();

// When
Stream.rangeClosed(1,3).forEach((count) -> produceSuccess(BACKEND_B));

// Then
checkHealthStatus(BACKEND_B, State.CLOSED);
}

private void produceFailure(String backend) {
ResponseEntity<String> response = restTemplate.getForEntity("/" + backend + "/failure", String.class);
assertThat(response.getStatusCode()).isEqualTo(HttpStatus.INTERNAL_SERVER_ERROR);
}

private void produceSuccess(String backend) {
ResponseEntity<String> response = restTemplate.getForEntity("/" + backend + "/success", String.class);
assertThat(response.getStatusCode()).isEqualTo(HttpStatus.OK);
}
@Test
public void shouldOpenBackendACircuitBreaker() {
// When
Stream.rangeClosed(1, 2).forEach((count) -> produceFailure(BACKEND_A));
// Then
checkHealthStatus(BACKEND_A, State.OPEN);
}

@Test
public void shouldCloseBackendACircuitBreaker() {
transitionToOpenState(BACKEND_A);
circuitBreakerRegistry.circuitBreaker(BACKEND_A).transitionToHalfOpenState();

// When
Stream.rangeClosed(1, 3).forEach((count) -> produceSuccess(BACKEND_A));

// Then
checkHealthStatus(BACKEND_A, State.CLOSED);
}

@Test
public void shouldOpenBackendBCircuitBreaker() {
// When
Stream.rangeClosed(1, 4).forEach((count) -> produceFailure(BACKEND_B));

// Then
checkHealthStatus(BACKEND_B, State.OPEN);
}

@Test
public void shouldCloseBackendBCircuitBreaker() {
transitionToOpenState(BACKEND_B);
circuitBreakerRegistry.circuitBreaker(BACKEND_B).transitionToHalfOpenState();

// When
Stream.rangeClosed(1, 3).forEach((count) -> produceSuccess(BACKEND_B));

// Then
checkHealthStatus(BACKEND_B, State.CLOSED);
}

private void produceFailure(String backend) {
ResponseEntity<String> response = restTemplate.getForEntity("/" + backend + "/failure", String.class);
assertThat(response.getStatusCode()).isEqualTo(HttpStatus.INTERNAL_SERVER_ERROR);
}

private void produceSuccess(String backend) {
ResponseEntity<String> response = restTemplate.getForEntity("/" + backend + "/success", String.class);
assertThat(response.getStatusCode()).isEqualTo(HttpStatus.OK);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
import static io.github.resilience4j.circuitbreaker.CircuitBreaker.State;
import static org.assertj.core.api.Assertions.assertThat;

import org.junit.Test;
import org.junit.jupiter.api.Test;
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;

Expand Down
4 changes: 1 addition & 3 deletions src/test/java/io/github/robwin/FutureRetryTest.java
Original file line number Diff line number Diff line change
Expand Up @@ -2,9 +2,7 @@

import static org.assertj.core.api.Assertions.assertThat;

import java.util.Arrays;

import org.junit.Test;
import org.junit.jupiter.api.Test;
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,9 +2,8 @@

import static io.github.resilience4j.circuitbreaker.CircuitBreaker.State;

import org.junit.Test;

import io.vavr.collection.Stream;
import org.junit.jupiter.api.Test;

public class ReactiveCircuitBreakerTest extends AbstractCircuitBreakerTest {

Expand Down
Loading