1
0
mirror of https://gitee.com/mirrors/Spring-Cloud-Alibaba.git synced 2021-06-26 13:25:11 +08:00

upgrade to Spring Cloud Hoxton, close #917

This commit is contained in:
fangjian0423
2019-09-06 16:33:11 +08:00
parent 1b8973d874
commit e8ee68998e
89 changed files with 1260 additions and 85 deletions

View File

@@ -0,0 +1,207 @@
/*
* Copyright 2013-2018 the original author or authors.
*
* 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
*
* https://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 com.alibaba.cloud.circuitbreaker.sentinel;
import java.time.Duration;
import java.util.Collections;
import com.alibaba.csp.sentinel.slots.block.RuleConstant;
import com.alibaba.csp.sentinel.slots.block.degrade.DegradeRule;
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
import reactor.core.publisher.Flux;
import reactor.core.publisher.Mono;
import reactor.test.StepVerifier;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.autoconfigure.EnableAutoConfiguration;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.boot.web.server.LocalServerPort;
import org.springframework.cloud.client.circuitbreaker.Customizer;
import org.springframework.cloud.client.circuitbreaker.ReactiveCircuitBreakerFactory;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.core.ParameterizedTypeReference;
import org.springframework.stereotype.Service;
import org.springframework.test.annotation.DirtiesContext;
import org.springframework.test.context.junit4.SpringRunner;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.reactive.function.client.WebClient;
import static org.springframework.boot.test.context.SpringBootTest.WebEnvironment.RANDOM_PORT;
/**
* @author Ryan Baxter
*/
@RunWith(SpringRunner.class)
@SpringBootTest(webEnvironment = RANDOM_PORT, classes = ReactiveSentinelCircuitBreakerIntegrationTest.Application.class)
@DirtiesContext
public class ReactiveSentinelCircuitBreakerIntegrationTest {
@LocalServerPort
private int port = 0;
@Autowired
private ReactiveSentinelCircuitBreakerIntegrationTest.Application.DemoControllerService service;
@Before
public void setup() {
service.setPort(port);
}
@Test
public void test() throws Exception {
StepVerifier.create(service.normal()).expectNext("normal").verifyComplete();
StepVerifier.create(service.slow()).expectNext("slow").verifyComplete();
StepVerifier.create(service.slow()).expectNext("slow").verifyComplete();
StepVerifier.create(service.slow()).expectNext("slow").verifyComplete();
StepVerifier.create(service.slow()).expectNext("slow").verifyComplete();
StepVerifier.create(service.slow()).expectNext("slow").verifyComplete();
// Then in the next 5s, the fallback method should be called.
for (int i = 0; i < 5; i++) {
StepVerifier.create(service.slow()).expectNext("fallback").verifyComplete();
Thread.sleep(1000);
}
// Recovered.
StepVerifier.create(service.slow()).expectNext("slow").verifyComplete();
StepVerifier.create(service.normalFlux()).expectNext("normalflux")
.verifyComplete();
StepVerifier.create(service.slowFlux()).expectNext("slowflux").verifyComplete();
StepVerifier.create(service.slowFlux()).expectNext("slowflux").verifyComplete();
StepVerifier.create(service.slowFlux()).expectNext("slowflux").verifyComplete();
StepVerifier.create(service.slowFlux()).expectNext("slowflux").verifyComplete();
StepVerifier.create(service.slowFlux()).expectNext("slowflux").verifyComplete();
// Then in the next 5s, the fallback method should be called.
for (int i = 0; i < 5; i++) {
StepVerifier.create(service.slowFlux()).expectNext("flux_fallback")
.verifyComplete();
Thread.sleep(1000);
}
// Recovered.
StepVerifier.create(service.slowFlux()).expectNext("slowflux").verifyComplete();
}
@Configuration
@EnableAutoConfiguration
@RestController
protected static class Application {
@GetMapping("/slow")
public Mono<String> slow() {
return Mono.just("slow").delayElement(Duration.ofMillis(500));
}
@GetMapping("/normal")
public Mono<String> normal() {
return Mono.just("normal");
}
@GetMapping("/slow_flux")
public Flux<String> slowFlux() {
return Flux.just("slow", "flux").delayElements(Duration.ofMillis(500));
}
@GetMapping("normal_flux")
public Flux<String> normalFlux() {
return Flux.just("normal", "flux");
}
@Bean
public Customizer<ReactiveSentinelCircuitBreakerFactory> slowCustomizer() {
return factory -> {
factory.configure(builder -> builder
.rules(Collections.singletonList(new DegradeRule("slow_mono")
.setGrade(RuleConstant.DEGRADE_GRADE_RT).setCount(100)
.setTimeWindow(5))),
"slow_mono");
factory.configure(builder -> builder
.rules(Collections.singletonList(new DegradeRule("slow_flux")
.setGrade(RuleConstant.DEGRADE_GRADE_RT).setCount(100)
.setTimeWindow(5))),
"slow_flux");
factory.configureDefault(id -> new SentinelConfigBuilder()
.resourceName(id)
.rules(Collections.singletonList(new DegradeRule(id)
.setGrade(RuleConstant.DEGRADE_GRADE_EXCEPTION_COUNT)
.setCount(0.5).setTimeWindow(10)))
.build());
};
}
@Service
public static class DemoControllerService {
private int port = 0;
private ReactiveCircuitBreakerFactory cbFactory;
DemoControllerService(ReactiveCircuitBreakerFactory cbFactory) {
this.cbFactory = cbFactory;
}
public Mono<String> slow() {
return WebClient.builder().baseUrl("http://localhost:" + port).build()
.get().uri("/slow").retrieve().bodyToMono(String.class)
.transform(it -> cbFactory.create("slow_mono").run(it, t -> {
t.printStackTrace();
return Mono.just("fallback");
}));
}
public Mono<String> normal() {
return WebClient.builder().baseUrl("http://localhost:" + port).build()
.get().uri("/normal").retrieve().bodyToMono(String.class)
.transform(it -> cbFactory.create("normal_mono").run(it, t -> {
t.printStackTrace();
return Mono.just("fallback");
}));
}
public Flux<String> slowFlux() {
return WebClient.builder().baseUrl("http://localhost:" + port).build()
.get().uri("/slow_flux").retrieve()
.bodyToFlux(new ParameterizedTypeReference<String>() {
}).transform(it -> cbFactory.create("slow_flux").run(it, t -> {
t.printStackTrace();
return Flux.just("flux_fallback");
}));
}
public Flux<String> normalFlux() {
return WebClient.builder().baseUrl("http://localhost:" + port).build()
.get().uri("/normal_flux").retrieve().bodyToFlux(String.class)
.transform(it -> cbFactory.create("normal_flux").run(it, t -> {
t.printStackTrace();
return Flux.just("flux_fallback");
}));
}
public void setPort(int port) {
this.port = port;
}
}
}
}

View File

@@ -0,0 +1,80 @@
/*
* Copyright 2013-2019 the original author or authors.
*
* 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
*
* https://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 com.alibaba.cloud.circuitbreaker.sentinel;
import java.util.Arrays;
import java.util.Collections;
import com.alibaba.csp.sentinel.slots.block.degrade.DegradeRuleManager;
import org.junit.Test;
import reactor.core.publisher.Flux;
import reactor.core.publisher.Mono;
import org.springframework.cloud.client.circuitbreaker.ReactiveCircuitBreaker;
import static org.assertj.core.api.Assertions.assertThat;
/**
* @author Eric Zhao
*/
public class ReactiveSentinelCircuitBreakerTest {
@Test
public void testCreateWithNullRule() {
String id = "testCreateReactiveCbWithNullRule";
ReactiveSentinelCircuitBreaker cb = new ReactiveSentinelCircuitBreaker(id,
Collections.singletonList(null));
assertThat(Mono.just("foobar").transform(it -> cb.run(it)).block())
.isEqualTo("foobar");
assertThat(DegradeRuleManager.hasConfig(id)).isFalse();
}
@Test
public void runMono() {
ReactiveCircuitBreaker cb = new ReactiveSentinelCircuitBreakerFactory()
.create("foo");
assertThat(Mono.just("foobar").transform(it -> cb.run(it)).block())
.isEqualTo("foobar");
}
@Test
public void runMonoWithFallback() {
ReactiveCircuitBreaker cb = new ReactiveSentinelCircuitBreakerFactory()
.create("foo");
assertThat(Mono.error(new RuntimeException("boom"))
.transform(it -> cb.run(it, t -> Mono.just("fallback"))).block())
.isEqualTo("fallback");
}
@Test
public void runFlux() {
ReactiveCircuitBreaker cb = new ReactiveSentinelCircuitBreakerFactory()
.create("foo");
assertThat(Flux.just("foobar", "hello world").transform(it -> cb.run(it))
.collectList().block()).isEqualTo(Arrays.asList("foobar", "hello world"));
}
@Test
public void runFluxWithFallback() {
ReactiveCircuitBreaker cb = new ReactiveSentinelCircuitBreakerFactory()
.create("foo");
assertThat(Flux.error(new RuntimeException("boom"))
.transform(it -> cb.run(it, t -> Flux.just("fallback"))).collectList()
.block()).isEqualTo(Arrays.asList("fallback"));
}
}

View File

@@ -0,0 +1,153 @@
/*
* Copyright 2013-2019 the original author or authors.
*
* 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
*
* https://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 com.alibaba.cloud.circuitbreaker.sentinel;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import com.alibaba.csp.sentinel.slots.block.RuleConstant;
import com.alibaba.csp.sentinel.slots.block.degrade.DegradeRule;
import com.alibaba.csp.sentinel.slots.block.degrade.DegradeRuleManager;
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.autoconfigure.EnableAutoConfiguration;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.boot.test.web.client.TestRestTemplate;
import org.springframework.cloud.client.circuitbreaker.CircuitBreakerFactory;
import org.springframework.cloud.client.circuitbreaker.Customizer;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.stereotype.Service;
import org.springframework.test.annotation.DirtiesContext;
import org.springframework.test.context.junit4.SpringRunner;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;
import static org.assertj.core.api.Assertions.assertThat;
import static org.springframework.boot.test.context.SpringBootTest.WebEnvironment.RANDOM_PORT;
/**
* @author Eric Zhao
*/
@RunWith(SpringRunner.class)
@SpringBootTest(webEnvironment = RANDOM_PORT, classes = SentinelCircuitBreakerIntegrationTest.Application.class)
@DirtiesContext
public class SentinelCircuitBreakerIntegrationTest {
@Autowired
private Application.DemoControllerService service;
@Test
public void testSlow() throws Exception {
// The first 5 requests should pass.
assertThat(service.slow()).isEqualTo("slow");
assertThat(service.slow()).isEqualTo("slow");
assertThat(service.slow()).isEqualTo("slow");
assertThat(service.slow()).isEqualTo("slow");
assertThat(service.slow()).isEqualTo("slow");
// Then in the next 10s, the fallback method should be called.
for (int i = 0; i < 10; i++) {
assertThat(service.slow()).isEqualTo("fallback");
Thread.sleep(1000);
}
// Recovered.
assertThat(service.slow()).isEqualTo("slow");
}
@Test
public void testNormal() {
assertThat(service.normal()).isEqualTo("normal");
}
@Before
public void setUp() {
DegradeRuleManager.loadRules(new ArrayList<>());
}
@Before
public void tearDown() {
DegradeRuleManager.loadRules(new ArrayList<>());
}
@Configuration
@EnableAutoConfiguration
@RestController
protected static class Application {
@GetMapping("/slow")
public String slow() throws InterruptedException {
Thread.sleep(500);
return "slow";
}
@GetMapping("/normal")
public String normal() {
return "normal";
}
@Bean
public Customizer<SentinelCircuitBreakerFactory> slowCustomizer() {
String slowId = "slow";
List<DegradeRule> rules = Collections.singletonList(
new DegradeRule(slowId).setGrade(RuleConstant.DEGRADE_GRADE_RT)
.setCount(100).setTimeWindow(10));
return factory -> {
factory.configure(builder -> builder.rules(rules), slowId);
factory.configureDefault(id -> new SentinelConfigBuilder()
.resourceName(id)
.rules(Collections.singletonList(new DegradeRule(id)
.setGrade(RuleConstant.DEGRADE_GRADE_EXCEPTION_COUNT)
.setCount(0.5).setTimeWindow(10)))
.build());
};
}
@Service
public static class DemoControllerService {
private TestRestTemplate rest;
private CircuitBreakerFactory cbFactory;
DemoControllerService(TestRestTemplate rest,
CircuitBreakerFactory cbFactory) {
this.rest = rest;
this.cbFactory = cbFactory;
}
public String slow() {
return cbFactory.create("slow").run(
() -> rest.getForObject("/slow", String.class), t -> "fallback");
}
public String normal() {
return cbFactory.create("normal").run(
() -> rest.getForObject("/normal", String.class),
t -> "fallback");
}
}
}
}

View File

@@ -0,0 +1,86 @@
/*
* Copyright 2013-2019 the original author or authors.
*
* 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
*
* https://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 com.alibaba.cloud.circuitbreaker.sentinel;
import java.util.ArrayList;
import java.util.Collections;
import com.alibaba.csp.sentinel.slots.block.degrade.DegradeRule;
import com.alibaba.csp.sentinel.slots.block.degrade.DegradeRuleManager;
import org.junit.After;
import org.junit.Test;
import org.springframework.cloud.client.circuitbreaker.CircuitBreaker;
import static org.assertj.core.api.Assertions.assertThat;
/**
* @author Eric Zhao
*/
public class SentinelCircuitBreakerTest {
@After
public void tearDown() {
// Clear the rules.
DegradeRuleManager.loadRules(new ArrayList<>());
}
@Test
public void testCreateDirectlyThenRun() {
// Create a circuit breaker without any circuit breaking rules.
CircuitBreaker cb = new SentinelCircuitBreaker(
"testSentinelCreateDirectlyThenRunA");
assertThat(cb.run(() -> "Sentinel")).isEqualTo("Sentinel");
assertThat(DegradeRuleManager.hasConfig("testSentinelCreateDirectlyThenRunA"))
.isFalse();
CircuitBreaker cb2 = new SentinelCircuitBreaker(
"testSentinelCreateDirectlyThenRunB",
Collections.singletonList(
new DegradeRule("testSentinelCreateDirectlyThenRunB")
.setCount(100).setTimeWindow(10)));
assertThat(cb2.run(() -> "Sentinel")).isEqualTo("Sentinel");
assertThat(DegradeRuleManager.hasConfig("testSentinelCreateDirectlyThenRunB"))
.isTrue();
}
@Test
public void testCreateWithNullRule() {
String id = "testCreateCbWithNullRule";
CircuitBreaker cb = new SentinelCircuitBreaker(id,
Collections.singletonList(null));
assertThat(cb.run(() -> "Sentinel")).isEqualTo("Sentinel");
assertThat(DegradeRuleManager.hasConfig(id)).isFalse();
}
@Test
public void testCreateFromFactoryThenRun() {
CircuitBreaker cb = new SentinelCircuitBreakerFactory().create("testSentinelRun");
assertThat(cb.run(() -> "foobar")).isEqualTo("foobar");
}
@Test
public void testRunWithFallback() {
CircuitBreaker cb = new SentinelCircuitBreakerFactory()
.create("testSentinelRunWithFallback");
assertThat(cb.<String> run(() -> {
throw new RuntimeException("boom");
}, t -> "fallback")).isEqualTo("fallback");
}
}