Update test cases for circuit breaking
Signed-off-by: Eric Zhao <sczyh16@gmail.com>
This commit is contained in:
parent
c0c27c86b7
commit
07b811196b
|
|
@ -0,0 +1,213 @@
|
|||
/*
|
||||
* Copyright 1999-2018 Alibaba Group Holding Ltd.
|
||||
*
|
||||
* 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 com.alibaba.csp.sentinel.slots.block.degrade;
|
||||
|
||||
import com.alibaba.csp.sentinel.Entry;
|
||||
import com.alibaba.csp.sentinel.SphU;
|
||||
import com.alibaba.csp.sentinel.Tracer;
|
||||
import com.alibaba.csp.sentinel.slots.block.BlockException;
|
||||
import com.alibaba.csp.sentinel.slots.block.RuleConstant;
|
||||
import com.alibaba.csp.sentinel.slots.block.degrade.circuitbreaker.CircuitBreaker.State;
|
||||
import com.alibaba.csp.sentinel.slots.block.degrade.circuitbreaker.CircuitBreakerStateChangeObserver;
|
||||
import com.alibaba.csp.sentinel.slots.block.degrade.circuitbreaker.EventObserverRegistry;
|
||||
import com.alibaba.csp.sentinel.test.AbstractTimeBasedTest;
|
||||
|
||||
import org.junit.After;
|
||||
import org.junit.Before;
|
||||
import org.junit.Test;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.concurrent.ThreadLocalRandom;
|
||||
|
||||
import static org.junit.Assert.assertEquals;
|
||||
import static org.junit.Assert.assertFalse;
|
||||
import static org.junit.Assert.assertTrue;
|
||||
import static org.mockito.Mockito.*;
|
||||
|
||||
/**
|
||||
* @author jialiang.linjl
|
||||
* @author Eric Zhao
|
||||
*/
|
||||
public class CircuitBreakingIntegrationTest extends AbstractTimeBasedTest {
|
||||
|
||||
@Before
|
||||
public void setUp() {
|
||||
DegradeRuleManager.loadRules(new ArrayList<DegradeRule>());
|
||||
}
|
||||
|
||||
@After
|
||||
public void tearDown() throws Exception {
|
||||
DegradeRuleManager.loadRules(new ArrayList<DegradeRule>());
|
||||
}
|
||||
|
||||
private boolean entryAndSleepFor(String res, int sleepMs) {
|
||||
Entry entry = null;
|
||||
try {
|
||||
entry = SphU.entry(res);
|
||||
sleep(sleepMs);
|
||||
} catch (BlockException ex) {
|
||||
return false;
|
||||
} catch (Exception ex) {
|
||||
Tracer.traceEntry(ex, entry);
|
||||
} finally {
|
||||
if (entry != null) {
|
||||
entry.exit();
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
private boolean entryWithErrorIfPresent(String res, Exception ex) {
|
||||
Entry entry = null;
|
||||
try {
|
||||
entry = SphU.entry(res);
|
||||
if (ex != null) {
|
||||
Tracer.traceEntry(ex, entry);
|
||||
}
|
||||
sleep(ThreadLocalRandom.current().nextInt(5, 10));
|
||||
} catch (BlockException b) {
|
||||
return false;
|
||||
} finally {
|
||||
if (entry != null) {
|
||||
entry.exit();
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testSlowRequestMode() throws Exception {
|
||||
CircuitBreakerStateChangeObserver observer = mock(CircuitBreakerStateChangeObserver.class);
|
||||
setCurrentMillis(System.currentTimeMillis() / 1000 * 1000);
|
||||
int retryTimeoutSec = 5;
|
||||
int maxRt = 50;
|
||||
int statIntervalMs = 20000;
|
||||
int minRequestAmount = 10;
|
||||
String res = "CircuitBreakingIntegrationTest_testSlowRequestMode";
|
||||
EventObserverRegistry.getInstance().addStateChangeObserver(res, observer);
|
||||
DegradeRuleManager.loadRules(Arrays.asList(
|
||||
new DegradeRule(res).setTimeWindow(retryTimeoutSec).setCount(maxRt)
|
||||
.setStatIntervalMs(statIntervalMs).setMinRequestAmount(minRequestAmount)
|
||||
.setSlowRatioThreshold(0.8d).setGrade(0)
|
||||
));
|
||||
|
||||
// Try first N requests where N = minRequestAmount.
|
||||
for (int i = 0; i < minRequestAmount; i++) {
|
||||
if (i < 7) {
|
||||
assertTrue(entryAndSleepFor(res, maxRt + ThreadLocalRandom.current().nextInt(10, 20)));
|
||||
} else {
|
||||
assertTrue(entryAndSleepFor(res, maxRt + ThreadLocalRandom.current().nextInt(-20, -10)));
|
||||
}
|
||||
}
|
||||
|
||||
// Till now slow ratio should be 70%.
|
||||
assertTrue(entryAndSleepFor(res, maxRt + ThreadLocalRandom.current().nextInt(10, 20)));
|
||||
assertTrue(entryAndSleepFor(res, maxRt + ThreadLocalRandom.current().nextInt(10, 20)));
|
||||
assertTrue(entryAndSleepFor(res, maxRt + ThreadLocalRandom.current().nextInt(10, 20)));
|
||||
assertTrue(entryAndSleepFor(res, maxRt + ThreadLocalRandom.current().nextInt(10, 20)));
|
||||
assertTrue(entryAndSleepFor(res, maxRt + ThreadLocalRandom.current().nextInt(10, 20)));
|
||||
assertTrue(entryAndSleepFor(res, maxRt + ThreadLocalRandom.current().nextInt(10, 20)));
|
||||
// Circuit breaker has transformed to OPEN since here.
|
||||
verify(observer)
|
||||
.onStateChange(eq(State.CLOSED), eq(State.OPEN), any(DegradeRule.class), anyDouble());
|
||||
assertEquals(State.OPEN, DegradeRuleManager.getCircuitBreakers(res).get(0).currentState());
|
||||
assertFalse(entryAndSleepFor(res, 1));
|
||||
|
||||
sleepSecond(1);
|
||||
assertFalse(entryAndSleepFor(res, 1));
|
||||
sleepSecond(retryTimeoutSec);
|
||||
// Test HALF-OPEN to OPEN.
|
||||
assertTrue(entryAndSleepFor(res, maxRt + ThreadLocalRandom.current().nextInt(10, 20)));
|
||||
|
||||
verify(observer)
|
||||
.onStateChange(eq(State.OPEN), eq(State.HALF_OPEN), any(DegradeRule.class), nullable(Double.class));
|
||||
verify(observer)
|
||||
.onStateChange(eq(State.HALF_OPEN), eq(State.OPEN), any(DegradeRule.class), anyDouble());
|
||||
// Wait for next retry timeout;
|
||||
reset(observer);
|
||||
sleepSecond(retryTimeoutSec + 1);
|
||||
assertTrue(entryAndSleepFor(res, maxRt - ThreadLocalRandom.current().nextInt(10, 20)));
|
||||
verify(observer)
|
||||
.onStateChange(eq(State.OPEN), eq(State.HALF_OPEN), any(DegradeRule.class), nullable(Double.class));
|
||||
verify(observer)
|
||||
.onStateChange(eq(State.HALF_OPEN), eq(State.CLOSED), any(DegradeRule.class), nullable(Double.class));
|
||||
// Now circuit breaker has been closed.
|
||||
assertTrue(entryAndSleepFor(res, maxRt + ThreadLocalRandom.current().nextInt(10, 20)));
|
||||
|
||||
EventObserverRegistry.getInstance().removeStateChangeObserver(res);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testExceptionRatioMode() throws Exception {
|
||||
CircuitBreakerStateChangeObserver observer = mock(CircuitBreakerStateChangeObserver.class);
|
||||
setCurrentMillis(System.currentTimeMillis() / 1000 * 1000);
|
||||
int retryTimeoutSec = 5;
|
||||
double maxRatio = 0.5;
|
||||
int statIntervalMs = 25000;
|
||||
final int minRequestAmount = 10;
|
||||
String res = "CircuitBreakingIntegrationTest_testExceptionRatioMode";
|
||||
EventObserverRegistry.getInstance().addStateChangeObserver(res, observer);
|
||||
DegradeRuleManager.loadRules(Arrays.asList(
|
||||
new DegradeRule(res).setTimeWindow(retryTimeoutSec).setCount(maxRatio)
|
||||
.setStatIntervalMs(statIntervalMs).setMinRequestAmount(minRequestAmount)
|
||||
.setGrade(RuleConstant.DEGRADE_GRADE_EXCEPTION_RATIO)
|
||||
));
|
||||
|
||||
// Try first N requests where N = minRequestAmount.
|
||||
for (int i = 0; i < minRequestAmount - 1; i++) {
|
||||
if (i < 6) {
|
||||
assertTrue(entryWithErrorIfPresent(res, new IllegalArgumentException()));
|
||||
} else {
|
||||
assertTrue(entryWithErrorIfPresent(res, null));
|
||||
}
|
||||
}
|
||||
|
||||
// Till now slow ratio should be 60%.
|
||||
assertTrue(entryWithErrorIfPresent(res, new IllegalArgumentException()));
|
||||
// Circuit breaker has transformed to OPEN since here.
|
||||
assertEquals(State.OPEN, DegradeRuleManager.getCircuitBreakers(res).get(0).currentState());
|
||||
assertFalse(entryWithErrorIfPresent(res, null));
|
||||
|
||||
sleepSecond(2);
|
||||
assertFalse(entryWithErrorIfPresent(res, null));
|
||||
sleepSecond(retryTimeoutSec);
|
||||
// Test HALF-OPEN to OPEN.
|
||||
assertTrue(entryWithErrorIfPresent(res, new IllegalArgumentException()));
|
||||
verify(observer)
|
||||
.onStateChange(eq(State.OPEN), eq(State.HALF_OPEN), any(DegradeRule.class), nullable(Double.class));
|
||||
verify(observer)
|
||||
.onStateChange(eq(State.HALF_OPEN), eq(State.OPEN), any(DegradeRule.class), anyDouble());
|
||||
// Wait for next retry timeout;
|
||||
reset(observer);
|
||||
sleepSecond(retryTimeoutSec + 1);
|
||||
assertTrue(entryWithErrorIfPresent(res, null));
|
||||
verify(observer)
|
||||
.onStateChange(eq(State.OPEN), eq(State.HALF_OPEN), any(DegradeRule.class), nullable(Double.class));
|
||||
verify(observer)
|
||||
.onStateChange(eq(State.HALF_OPEN), eq(State.CLOSED), any(DegradeRule.class), nullable(Double.class));
|
||||
// Now circuit breaker has been closed.
|
||||
assertTrue(entryWithErrorIfPresent(res, new IllegalArgumentException()));
|
||||
|
||||
EventObserverRegistry.getInstance().removeStateChangeObserver(res);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testExceptionCountMode() throws Throwable {
|
||||
// TODO
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -15,8 +15,14 @@
|
|||
*/
|
||||
package com.alibaba.csp.sentinel.slots.block.degrade;
|
||||
|
||||
import com.alibaba.csp.sentinel.slots.block.RuleConstant;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
|
||||
import com.alibaba.csp.sentinel.slots.block.RuleConstant;
|
||||
import com.alibaba.csp.sentinel.slots.block.degrade.circuitbreaker.CircuitBreaker;
|
||||
|
||||
import org.junit.After;
|
||||
import org.junit.Before;
|
||||
import org.junit.Test;
|
||||
|
||||
import static org.junit.Assert.*;
|
||||
|
|
@ -28,6 +34,32 @@ import static org.junit.Assert.*;
|
|||
*/
|
||||
public class DegradeRuleManagerTest {
|
||||
|
||||
@Before
|
||||
public void setUp() throws Exception {
|
||||
DegradeRuleManager.loadRules(new ArrayList<DegradeRule>());
|
||||
}
|
||||
|
||||
@After
|
||||
public void tearDown() throws Exception {
|
||||
DegradeRuleManager.loadRules(new ArrayList<DegradeRule>());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void loadSameRuleUseSameCircuitBreaker() {
|
||||
String resource = "loadSameRuleUseSameCircuitBreaker";
|
||||
DegradeRule rule = new DegradeRule(resource)
|
||||
.setCount(100)
|
||||
.setSlowRatioThreshold(0.9d)
|
||||
.setTimeWindow(20)
|
||||
.setStatIntervalMs(20000);
|
||||
DegradeRuleManager.loadRules(Arrays.asList(rule));
|
||||
CircuitBreaker cb = DegradeRuleManager.getCircuitBreakers(resource).get(0);
|
||||
|
||||
DegradeRuleManager.loadRules(Arrays.asList(rule,
|
||||
new DegradeRule("abc").setTimeWindow(20).setCount(20).setSlowRatioThreshold(0.8d)));
|
||||
assertSame(cb, DegradeRuleManager.getCircuitBreakers(resource).get(0));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testIsValidRule() {
|
||||
DegradeRule rule1 = new DegradeRule("abc");
|
||||
|
|
@ -46,13 +78,19 @@ public class DegradeRuleManagerTest {
|
|||
DegradeRule rule5 = new DegradeRule("Sentinel")
|
||||
.setCount(97)
|
||||
.setGrade(RuleConstant.DEGRADE_GRADE_RT)
|
||||
.setTimeWindow(15)
|
||||
.setRtSlowRequestAmount(0);
|
||||
.setSlowRatioThreshold(15)
|
||||
.setTimeWindow(15);
|
||||
DegradeRule rule6 = new DegradeRule("Sentinel")
|
||||
.setCount(0.93d)
|
||||
.setGrade(RuleConstant.DEGRADE_GRADE_EXCEPTION_RATIO)
|
||||
.setTimeWindow(20)
|
||||
.setMinRequestAmount(0);
|
||||
DegradeRule rule7 = new DegradeRule("Sentinel")
|
||||
.setCount(100)
|
||||
.setSlowRatioThreshold(0.8d)
|
||||
.setTimeWindow(10)
|
||||
.setStatIntervalMs(0)
|
||||
.setMinRequestAmount(20);
|
||||
assertFalse(DegradeRuleManager.isValidRule(rule1));
|
||||
assertFalse(DegradeRuleManager.isValidRule(rule2));
|
||||
assertFalse(DegradeRuleManager.isValidRule(rule3));
|
||||
|
|
@ -61,5 +99,6 @@ public class DegradeRuleManagerTest {
|
|||
assertFalse(DegradeRuleManager.isValidRule(rule4));
|
||||
assertFalse(DegradeRuleManager.isValidRule(rule5));
|
||||
assertFalse(DegradeRuleManager.isValidRule(rule6));
|
||||
assertFalse(DegradeRuleManager.isValidRule(rule7));
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,51 @@
|
|||
/*
|
||||
* Copyright 1999-2018 Alibaba Group Holding Ltd.
|
||||
*
|
||||
* 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 com.alibaba.csp.sentinel.slots.block.degrade;
|
||||
|
||||
import com.alibaba.csp.sentinel.slots.block.RuleConstant;
|
||||
|
||||
import org.junit.Test;
|
||||
|
||||
import static org.junit.Assert.*;
|
||||
|
||||
/**
|
||||
* @author Eric Zhao
|
||||
*/
|
||||
public class DegradeRuleTest {
|
||||
|
||||
@Test
|
||||
public void testRuleEquals() {
|
||||
DegradeRule degradeRule1 = new DegradeRule();
|
||||
DegradeRule degradeRule2 = new DegradeRule();
|
||||
|
||||
int minRequestAmount = 20;
|
||||
double count = 1.0;
|
||||
int timeWindow = 2;
|
||||
degradeRule1.setMinRequestAmount(minRequestAmount);
|
||||
degradeRule1.setCount(count);
|
||||
degradeRule1.setTimeWindow(timeWindow);
|
||||
degradeRule1.setGrade(RuleConstant.DEGRADE_GRADE_RT);
|
||||
|
||||
degradeRule2.setMinRequestAmount(minRequestAmount);
|
||||
degradeRule2.setCount(count);
|
||||
degradeRule2.setGrade(RuleConstant.DEGRADE_GRADE_RT);
|
||||
degradeRule2.setTimeWindow(timeWindow);
|
||||
assertEquals(degradeRule1, degradeRule2);
|
||||
|
||||
degradeRule2.setMinRequestAmount(100);
|
||||
assertNotEquals(degradeRule1, degradeRule2);
|
||||
}
|
||||
}
|
||||
|
|
@ -1,182 +0,0 @@
|
|||
/*
|
||||
* Copyright 1999-2018 Alibaba Group Holding Ltd.
|
||||
*
|
||||
* 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 com.alibaba.csp.sentinel.slots.block.degrade;
|
||||
|
||||
import com.alibaba.csp.sentinel.EntryType;
|
||||
import com.alibaba.csp.sentinel.context.Context;
|
||||
import com.alibaba.csp.sentinel.node.ClusterNode;
|
||||
import com.alibaba.csp.sentinel.node.DefaultNode;
|
||||
import com.alibaba.csp.sentinel.slotchain.StringResourceWrapper;
|
||||
import com.alibaba.csp.sentinel.slots.block.RuleConstant;
|
||||
import com.alibaba.csp.sentinel.slots.clusterbuilder.ClusterBuilderSlot;
|
||||
import org.junit.Test;
|
||||
|
||||
import java.util.concurrent.TimeUnit;
|
||||
|
||||
import static org.junit.Assert.assertFalse;
|
||||
import static org.junit.Assert.assertTrue;
|
||||
import static org.mockito.Mockito.mock;
|
||||
import static org.mockito.Mockito.when;
|
||||
|
||||
/**
|
||||
* @author jialiang.linjl
|
||||
*/
|
||||
public class DegradeTest {
|
||||
|
||||
@Test
|
||||
public void testAverageRtDegrade() throws InterruptedException {
|
||||
String key = "test_degrade_average_rt";
|
||||
ClusterNode cn = mock(ClusterNode.class);
|
||||
ClusterBuilderSlot.getClusterNodeMap().put(new StringResourceWrapper(key, EntryType.IN), cn);
|
||||
|
||||
Context context = mock(Context.class);
|
||||
DefaultNode node = mock(DefaultNode.class);
|
||||
when(node.getClusterNode()).thenReturn(cn);
|
||||
when(cn.avgRt()).thenReturn(2d);
|
||||
|
||||
int rtSlowRequestAmount = 10;
|
||||
DegradeRule rule = new DegradeRule();
|
||||
rule.setCount(1);
|
||||
rule.setResource(key);
|
||||
rule.setTimeWindow(2);
|
||||
rule.setGrade(RuleConstant.DEGRADE_GRADE_RT);
|
||||
rule.setRtSlowRequestAmount(rtSlowRequestAmount);
|
||||
|
||||
//Will true
|
||||
for (int i = 0; i < rtSlowRequestAmount - 1; i++) {
|
||||
assertTrue(rule.passCheck(context, node, 1));
|
||||
}
|
||||
|
||||
// The third time will fail.
|
||||
assertFalse(rule.passCheck(context, node, 1));
|
||||
assertFalse(rule.passCheck(context, node, 1));
|
||||
|
||||
// Restore.
|
||||
TimeUnit.MILLISECONDS.sleep(2200);
|
||||
assertTrue(rule.passCheck(context, node, 1));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testExceptionRatioModeDegrade() throws Throwable {
|
||||
String key = "test_degrade_exception_ratio";
|
||||
ClusterNode cn = mock(ClusterNode.class);
|
||||
ClusterBuilderSlot.getClusterNodeMap().put(new StringResourceWrapper(key, EntryType.IN), cn);
|
||||
|
||||
Context context = mock(Context.class);
|
||||
DefaultNode node = mock(DefaultNode.class);
|
||||
when(node.getClusterNode()).thenReturn(cn);
|
||||
|
||||
DegradeRule rule = new DegradeRule();
|
||||
rule.setCount(0.15);
|
||||
rule.setResource(key);
|
||||
rule.setTimeWindow(2);
|
||||
rule.setGrade(RuleConstant.DEGRADE_GRADE_EXCEPTION_RATIO);
|
||||
rule.setMinRequestAmount(20);
|
||||
|
||||
|
||||
// Will true. While totalQps < minRequestAmount
|
||||
when(cn.totalQps()).thenReturn(8d);
|
||||
assertTrue(rule.passCheck(context, node, 1));
|
||||
|
||||
// Will true.
|
||||
when(cn.totalQps()).thenReturn(21d);
|
||||
when(cn.successQps()).thenReturn(9d);
|
||||
when(cn.exceptionQps()).thenReturn(9d);
|
||||
assertTrue(rule.passCheck(context, node, 1));
|
||||
|
||||
|
||||
// Will true. While totalQps > minRequestAmount and exceptionRation < count
|
||||
when(cn.totalQps()).thenReturn(100d);
|
||||
when(cn.successQps()).thenReturn(90d);
|
||||
when(cn.exceptionQps()).thenReturn(10d);
|
||||
assertTrue(rule.passCheck(context, node, 1));
|
||||
|
||||
// Will fail. While totalQps > minRequestAmount and exceptionRation > count
|
||||
rule.setMinRequestAmount(5);
|
||||
when(cn.totalQps()).thenReturn(12d);
|
||||
when(cn.successQps()).thenReturn(8d);
|
||||
when(cn.exceptionQps()).thenReturn(6d);
|
||||
assertFalse(rule.passCheck(context, node, 1));
|
||||
|
||||
// Restore from the degrade timeout.
|
||||
TimeUnit.MILLISECONDS.sleep(2200);
|
||||
|
||||
// Will pass.
|
||||
when(cn.totalQps()).thenReturn(106d);
|
||||
when(cn.successQps()).thenReturn(100d);
|
||||
assertTrue(rule.passCheck(context, node, 1));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testExceptionCountModeDegrade() throws Throwable {
|
||||
String key = "test_degrade_exception_count";
|
||||
ClusterNode cn = mock(ClusterNode.class);
|
||||
when(cn.totalException()).thenReturn(10L);
|
||||
ClusterBuilderSlot.getClusterNodeMap().put(new StringResourceWrapper(key, EntryType.IN), cn);
|
||||
|
||||
Context context = mock(Context.class);
|
||||
DefaultNode node = mock(DefaultNode.class);
|
||||
when(node.getClusterNode()).thenReturn(cn);
|
||||
|
||||
DegradeRule rule = new DegradeRule();
|
||||
rule.setCount(4);
|
||||
rule.setResource(key);
|
||||
rule.setTimeWindow(2);
|
||||
rule.setGrade(RuleConstant.DEGRADE_GRADE_EXCEPTION_COUNT);
|
||||
|
||||
when(cn.totalException()).thenReturn(4L);
|
||||
|
||||
// Will fail.
|
||||
assertFalse(rule.passCheck(context, node, 1));
|
||||
|
||||
// Restore from the degrade timeout.
|
||||
TimeUnit.MILLISECONDS.sleep(2200);
|
||||
|
||||
when(cn.totalException()).thenReturn(0L);
|
||||
// Will pass.
|
||||
assertTrue(rule.passCheck(context, node, 1));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testEquals() {
|
||||
DegradeRule degradeRule1 = new DegradeRule();
|
||||
DegradeRule degradeRule2 = new DegradeRule();
|
||||
assertTrue(degradeRule1.equals(degradeRule2));
|
||||
|
||||
int rtSlowRequestAmount = 10;
|
||||
int minRequestAmount = 20;
|
||||
double count = 1.0;
|
||||
int timeWindow = 2;
|
||||
degradeRule1.setRtSlowRequestAmount(rtSlowRequestAmount);
|
||||
degradeRule1.setMinRequestAmount(minRequestAmount);
|
||||
degradeRule1.setCount(count);
|
||||
degradeRule1.setTimeWindow(timeWindow);
|
||||
degradeRule1.setGrade(RuleConstant.DEGRADE_GRADE_RT);
|
||||
|
||||
degradeRule2.setRtSlowRequestAmount(rtSlowRequestAmount);
|
||||
degradeRule2.setMinRequestAmount(minRequestAmount);
|
||||
degradeRule2.setCount(count);
|
||||
degradeRule2.setGrade(RuleConstant.DEGRADE_GRADE_RT);
|
||||
degradeRule2.setTimeWindow(timeWindow);
|
||||
assertTrue(degradeRule1.equals(degradeRule2));
|
||||
|
||||
degradeRule2.setMinRequestAmount(100);
|
||||
assertFalse(degradeRule1.equals(degradeRule2));
|
||||
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -0,0 +1,111 @@
|
|||
/*
|
||||
* Copyright 1999-2019 Alibaba Group Holding Ltd.
|
||||
*
|
||||
* 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 com.alibaba.csp.sentinel.slots.block.degrade.circuitbreaker;
|
||||
|
||||
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.circuitbreaker.CircuitBreaker.State;
|
||||
import com.alibaba.csp.sentinel.slots.block.degrade.circuitbreaker.ExceptionCircuitBreaker.SimpleErrorCounter;
|
||||
import com.alibaba.csp.sentinel.slots.statistic.base.LeapArray;
|
||||
import com.alibaba.csp.sentinel.slots.statistic.base.WindowWrap;
|
||||
import com.alibaba.csp.sentinel.test.AbstractTimeBasedTest;
|
||||
|
||||
import org.junit.Test;
|
||||
|
||||
import static org.junit.Assert.*;
|
||||
import static org.mockito.Mockito.mock;
|
||||
import static org.mockito.Mockito.when;
|
||||
|
||||
/**
|
||||
* @author Eric Zhao
|
||||
*/
|
||||
public class ExceptionCircuitBreakerTest extends AbstractTimeBasedTest {
|
||||
|
||||
@Test
|
||||
@SuppressWarnings("unchecked")
|
||||
public void testStateChangeAndTryAcquire() {
|
||||
int retryTimeout = 10;
|
||||
DegradeRule rule = new DegradeRule("abc")
|
||||
.setCount(0.5d)
|
||||
.setGrade(RuleConstant.DEGRADE_GRADE_EXCEPTION_RATIO)
|
||||
.setStatIntervalMs(20 * 1000)
|
||||
.setTimeWindow(retryTimeout)
|
||||
.setMinRequestAmount(10);
|
||||
LeapArray<SimpleErrorCounter> stat = mock(LeapArray.class);
|
||||
SimpleErrorCounter counter = new SimpleErrorCounter();
|
||||
WindowWrap<SimpleErrorCounter> bucket = new WindowWrap<>(20000, 0, counter);
|
||||
when(stat.currentWindow()).thenReturn(bucket);
|
||||
|
||||
ExceptionCircuitBreaker cb = new ExceptionCircuitBreaker(rule, stat);
|
||||
|
||||
assertTrue(cb.tryPass());
|
||||
assertTrue(cb.tryPass());
|
||||
|
||||
setCurrentMillis(System.currentTimeMillis());
|
||||
cb.fromCloseToOpen(0.52d);
|
||||
assertEquals(State.OPEN, cb.currentState());
|
||||
|
||||
assertFalse(cb.tryPass());
|
||||
assertFalse(cb.tryPass());
|
||||
|
||||
// Wait for next retry checkpoint.
|
||||
sleepSecond(retryTimeout);
|
||||
sleep(100);
|
||||
// Try a request to trigger state transformation.
|
||||
assertTrue(cb.tryPass());
|
||||
assertEquals(State.HALF_OPEN, cb.currentState());
|
||||
|
||||
// Mark this request as error
|
||||
cb.onRequestComplete(20, new IllegalArgumentException());
|
||||
assertEquals(State.OPEN, cb.currentState());
|
||||
|
||||
// Wait for next retry checkpoint.
|
||||
sleepSecond(retryTimeout);
|
||||
sleep(100);
|
||||
assertTrue(cb.tryPass());
|
||||
assertEquals(State.HALF_OPEN, cb.currentState());
|
||||
|
||||
setCurrentMillis(System.currentTimeMillis());
|
||||
// Mark this request as success.
|
||||
cb.onRequestComplete(20, null);
|
||||
assertEquals(State.CLOSED, cb.currentState());
|
||||
}
|
||||
|
||||
@Test
|
||||
@SuppressWarnings("unchecked")
|
||||
public void testRecordErrorOrSuccess() {
|
||||
DegradeRule rule = new DegradeRule("abc")
|
||||
.setCount(0.5d)
|
||||
.setGrade(RuleConstant.DEGRADE_GRADE_EXCEPTION_RATIO)
|
||||
.setStatIntervalMs(20 * 1000)
|
||||
.setTimeWindow(10)
|
||||
.setMinRequestAmount(10);
|
||||
LeapArray<SimpleErrorCounter> stat = mock(LeapArray.class);
|
||||
SimpleErrorCounter counter = new SimpleErrorCounter();
|
||||
WindowWrap<SimpleErrorCounter> bucket = new WindowWrap<>(20000, 0, counter);
|
||||
when(stat.currentWindow()).thenReturn(bucket);
|
||||
|
||||
CircuitBreaker cb = new ExceptionCircuitBreaker(rule, stat);
|
||||
cb.onRequestComplete(15, null);
|
||||
|
||||
assertEquals(1L, counter.getTotalCount().longValue());
|
||||
assertEquals(0L, counter.getErrorCount().longValue());
|
||||
|
||||
cb.onRequestComplete(15, new IllegalArgumentException());
|
||||
assertEquals(2L, counter.getTotalCount().longValue());
|
||||
assertEquals(1L, counter.getErrorCount().longValue());
|
||||
}
|
||||
}
|
||||
Loading…
Reference in New Issue