content: /*
   * Copyright 2013-2023 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.jupiter.api.BeforeEach;
  import org.junit.jupiter.api.Test;
  
  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.web.bind.annotation.GetMapping;
  import org.springframework.web.bind.annotation.RequestParam;
  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
   */
  @SpringBootTest(webEnvironment = RANDOM_PORT,
  		classes = SentinelCircuitBreakerIntegrationTest.Application.class,
  		properties = { "spring.cloud.discovery.client.health-indicator.enabled=false" })
  public class SentinelCircuitBreakerIntegrationTest {
  
  	@Autowired
  	private Application.DemoControllerService service;
  
  	@Test
  	public void testSlow() throws Exception {
  		assertThat(service.slow(true)).isEqualTo("slow");
  		assertThat(service.slow(true)).isEqualTo("slow");
  		assertThat(service.slow(true)).isEqualTo("slow");
  		assertThat(service.slow(false)).isEqualTo("slow");
  		assertThat(service.slow(false)).isEqualTo("slow");
  		assertThat(service.slow(true)).isEqualTo("slow");
  		assertThat(service.slow(true)).isEqualTo("slow");
  
  		// Then in the next 10s, the fallback method should be called.
  		for (int i = 0; i < 5; i++) {
  			assertThat(service.slow(true)).isEqualTo("fallback");
  			Thread.sleep(1000);
  		}
  
  		// Try a normal request.
  		assertThat(service.slow(false)).isEqualTo("slow");
  		// Recovered.
  		assertThat(service.slow(true)).isEqualTo("slow");
  	}
  
  	@Test
  	public void testNormal() {
  		assertThat(service.normal()).isEqualTo("normal");
  	}
  
  	@BeforeEach
  	public void setUp() {
  		DegradeRuleManager.loadRules(new ArrayList<>());
  	}
  
  	@BeforeEach
  	public void tearDown() {
  		DegradeRuleManager.loadRules(new ArrayList<>());
  	}
  
  	@Configuration
  	@EnableAutoConfiguration
  	@RestController
  	protected static class Application {
  
  		@GetMapping("/slow")
  		public String slow(@RequestParam(required = false) Boolean slow)
  				throws InterruptedException {
  			if (slow == null || slow) {
  				Thread.sleep(80);
  			}
  			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(50)
  					.setSlowRatioThreshold(0.7).setMinRequestAmount(5)
  					.setStatIntervalMs(30000).setTimeWindow(5));
  			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(10).setStatIntervalMs(10000).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(boolean slow) {
  				return cbFactory.create("slow").run(
  						() -> rest.getForObject("/slow?slow=" + slow, String.class),
  						t -> "fallback");
  			}
  
  			public String normal() {
  				return cbFactory.create("normal").run(
  						() -> rest.getForObject("/normal", String.class),
  						t -> "fallback");
  			}
  
  		}
  
  	}
  
  }
  