package org.distributeme.core.routing.blacklisting;
import java.util.Collections;
import java.util.concurrent.ScheduledExecutorService;
import org.distributeme.core.ClientSideCallContext;
import org.distributeme.core.routing.GenericRouterConfiguration;
import org.distributeme.core.util.TestTimeProvider;
import org.junit.Before;
import org.junit.Test;
import org.slf4j.Logger;
import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertTrue;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.verify;
public class ErrorsPerIntervalBlacklistingStrategyTest {
private static final String SERVICE_ID_0 = "serviceId_0";
private static final String SERVICE_ID_1 = "serviceId_1";
private static final int INTERVAL_DURATION = 10;
private static final int INTERVAL_DURATION_MINUS_ONE = INTERVAL_DURATION - 1;
private TestTimeProvider timeProvider = new TestTimeProvider();
private ClientSideCallContext clientSideCallContext = new ClientSideCallContext(SERVICE_ID_0, "someMethod", Collections.emptyList());
private ScheduledExecutorService dummyScheduledExecutorService = mock(ScheduledExecutorService.class);
private GenericRouterConfiguration routerConfiguration = new GenericRouterConfiguration();
private Logger logger = mock(Logger.class);
private ErrorsPerIntervalBlacklistingStrategy strategy = new ErrorsPerIntervalBlacklistingStrategy(dummyScheduledExecutorService, timeProvider, logger);
@Before
public void setUp() throws Exception {
timeProvider.setCurrentMillis(0);
givenConfigWith("epbs_2RequiredNumberOfIntervalsWithErrors_2ErrorsPerIntervalThreshold");
assertFalse("ServiceId should not be blacklisted before failure call", strategy.isBlacklisted(SERVICE_ID_0));
}
@Test
public void isBlacklisted_IfErrorsPerIntervalExceedsThreshold_ForOneRequiredInterval_WithinInterval() {
givenConfigWith("epbs_1RequiredNumberOfIntervalsWithErrors_1ErrorsPerIntervalThreshold");
whenNotifiyCallFailed(SERVICE_ID_0, 2);
whenJumpInTimePlusSeconds(INTERVAL_DURATION_MINUS_ONE);
thenServiceIsBlacklisted(SERVICE_ID_0);
}
@Test
public void isBlacklistedIfErrorsPerIntervalExceedsThreshold_ForOneRequiredInterval_OnIntervalBorder() {
givenConfigWith("epbs_1RequiredNumberOfIntervalsWithErrors_1ErrorsPerIntervalThreshold");
whenNotifiyCallFailed(SERVICE_ID_0, 1);
whenJumpInTimePlusSeconds(INTERVAL_DURATION);
thenServiceIsBlacklisted(SERVICE_ID_0);
}
@Test
public void isBlacklistedIfErrorsPerIntervalExceedsThreshold_InFirstInterval_AndCurrentInterval() {
givenConfigWith("epbs_2RequiredNumberOfIntervalsWithErrors_1ErrorsPerIntervalThreshold");
whenNotifiyCallFailed(SERVICE_ID_0, 2);
whenJumpInTimePlusSeconds(INTERVAL_DURATION);
whenNotifiyCallFailed(SERVICE_ID_0, 2);
whenJumpInTimePlusSeconds(INTERVAL_DURATION_MINUS_ONE);
thenServiceIsBlacklisted(SERVICE_ID_0);
}
@Test
public void isNotBlacklistedIfErrorsExceedThreshold_InFirstInterval_ButZeroInCurrent() {
givenConfigWith("epbs_2RequiredNumberOfIntervalsWithErrors_1ErrorsPerIntervalThreshold");
whenNotifiyCallFailed(SERVICE_ID_0, 2);
whenJumpInTimePlusSeconds(INTERVAL_DURATION);
thenServiceIsNotBlacklisted(SERVICE_ID_0);
whenNotifiyCallFailed(SERVICE_ID_0, 0);
whenJumpInTimePlusSeconds(INTERVAL_DURATION_MINUS_ONE);
thenServiceIsNotBlacklisted(SERVICE_ID_0);
}
@Test
public void isNotBlacklistedIfErrorsPerIntervalDoNotExceedThreshold_WithinTwoLastIntervals() {
givenConfigWith("epbs_2RequiredNumberOfIntervalsWithErrors_2ErrorsPerIntervalThreshold");
whenNotifiyCallFailed(SERVICE_ID_0, 2);
whenJumpInTimePlusSeconds(INTERVAL_DURATION);
thenServiceIsNotBlacklisted(SERVICE_ID_0);
whenNotifiyCallFailed(SERVICE_ID_0, 1);
whenJumpInTimePlusSeconds(INTERVAL_DURATION);
thenServiceIsNotBlacklisted(SERVICE_ID_0);
}
@Test
public void isNotBlacklisted_IfFirstAndThirdIntervalHaveErrors_ButSecondIntervalHasNot() {
givenConfigWith("epbs_2RequiredNumberOfIntervalsWithErrors_1ErrorsPerIntervalThreshold");
whenNotifiyCallFailed(SERVICE_ID_0, 1);
whenJumpInTimePlusSeconds(INTERVAL_DURATION);
thenServiceIsNotBlacklisted(SERVICE_ID_0);
whenNotifiyCallFailed(SERVICE_ID_0, 0);
whenJumpInTimePlusSeconds(INTERVAL_DURATION);
thenServiceIsNotBlacklisted(SERVICE_ID_0);
whenNotifiyCallFailed(SERVICE_ID_0, 1);
whenJumpInTimePlusSeconds(INTERVAL_DURATION);
thenServiceIsNotBlacklisted(SERVICE_ID_0);
}
@Test
public void isNotBlacklisted_IfFirstAndSecondIntervalHaveErrorsButThirdHasNot() {
givenConfigWith("epbs_3RequiredNumberOfIntervalsWithErrors_3ErrorsPerIntervalThreshold");
whenNotifiyCallFailed(SERVICE_ID_0, 3);
whenJumpInTimePlusSeconds(INTERVAL_DURATION);
thenServiceIsNotBlacklisted(SERVICE_ID_0);
whenNotifiyCallFailed(SERVICE_ID_0, 4);
whenJumpInTimePlusSeconds(INTERVAL_DURATION);
thenServiceIsNotBlacklisted(SERVICE_ID_0);
whenNotifiyCallFailed(SERVICE_ID_0, 1);
whenJumpInTimePlusSeconds(INTERVAL_DURATION_MINUS_ONE);
thenServiceIsNotBlacklisted(SERVICE_ID_0);
}
@Test
public void isBlacklisted_IfThreeRequiredIntervalsHaveErrors_ThirdIntervalNotOnBorder() {
givenConfigWith("epbs_3RequiredNumberOfIntervalsWithErrors_3ErrorsPerIntervalThreshold");
whenNotifiyCallFailed(SERVICE_ID_0, 3);
whenJumpInTimePlusSeconds(INTERVAL_DURATION);
thenServiceIsNotBlacklisted(SERVICE_ID_0);
whenNotifiyCallFailed(SERVICE_ID_0, 4);
whenJumpInTimePlusSeconds(INTERVAL_DURATION);
thenServiceIsNotBlacklisted(SERVICE_ID_0);
whenNotifiyCallFailed(SERVICE_ID_0, 3);
whenJumpInTimePlusSeconds(INTERVAL_DURATION_MINUS_ONE);
thenServiceIsBlacklisted(SERVICE_ID_0);
}
@Test
public void isBlacklisted_IfThreeRequiredIntervalsHaveErrors_ThirdIntervalOnBorder() {
givenConfigWith("epbs_3RequiredNumberOfIntervalsWithErrors_3ErrorsPerIntervalThreshold");
whenNotifiyCallFailed(SERVICE_ID_0, 3);
whenJumpInTimePlusSeconds(INTERVAL_DURATION);
thenServiceIsNotBlacklisted(SERVICE_ID_0);
whenNotifiyCallFailed(SERVICE_ID_0, 4);
whenJumpInTimePlusSeconds(INTERVAL_DURATION);
thenServiceIsNotBlacklisted(SERVICE_ID_0);
whenNotifiyCallFailed(SERVICE_ID_0, 3);
whenJumpInTimePlusSeconds(INTERVAL_DURATION);
thenServiceIsBlacklisted(SERVICE_ID_0);
}
@Test
public void isNotBlackListedIfAllThresholdsAreSetToZero() {
givenConfigWith("epbs_0RequiredNumberOfIntervalsWithErrors_0ErrorsPerIntervalThreshold");
whenNotifiyCallFailed(SERVICE_ID_0, 0);
thenServiceIsNotBlacklisted(SERVICE_ID_0);
}
@Test
public void isNotBlacklistedIfStrategyConfigurationIsFaulty() {
givenConfigWith("epbs_Miuns1RequiredNumberOfIntervalsWithErrors_Minus1ErrorsPerIntervalThreshold");
whenNotifiyCallFailed(SERVICE_ID_0, 0);
thenServiceIsNotBlacklisted(SERVICE_ID_0);
thenConfigurationErrorIsLoggedAsError("Invalid configuration epbs_Miuns1RequiredNumberOfIntervalsWithErrors_Minus1ErrorsPerIntervalThreshold ErrorsPerIntervalBlacklistingStrategyConfig{errorsPerIntervalThreshold=-1, intervalDurationInSeconds=-1, requiredNumberOfIntervalsWithErrors=-1}");
}
@Test
public void isNotBlacklistedIfStrategyIfConfigurationIsNotExistend() {
givenConfigWith("notExists");
whenNotifiyCallFailed(SERVICE_ID_0, 0);
thenServiceIsNotBlacklisted(SERVICE_ID_0);
thenConfigurationErrorIsLoggedAsWarning("Could not load configuration notExists");
}
private void thenConfigurationErrorIsLoggedAsWarning(String message) {
verify(logger).warn(message);
}
private void thenConfigurationErrorIsLoggedAsError(String message) {
verify(logger).error(message);
}
@Test
public void whenOneServiceInstanceIsBlacklistedThenOtherHealthyInstanceIsNotBlacklisted() {
givenConfigWith("epbs_1RequiredNumberOfIntervalsWithErrors_1ErrorsPerIntervalThreshold");
whenNotifiyCallFailed(SERVICE_ID_0, 1);
whenJumpInTimePlusSeconds(INTERVAL_DURATION);
thenServiceIsBlacklisted(SERVICE_ID_0);
thenServiceIsNotBlacklisted(SERVICE_ID_1);
}
private void thenServiceIsBlacklisted(String serviceID) {
assertTrue(serviceID + " should be blacklisted", strategy.isBlacklisted(serviceID));
}
private void thenServiceIsNotBlacklisted(String serviceID) {
assertFalse(serviceID + " should not be blacklisted", strategy.isBlacklisted(serviceID));
}
private void whenJumpInTimePlusSeconds(int seconds) {
timeProvider.increaseBySeconds(seconds);
strategy.timerTick();
}
private void whenNotifiyCallFailed(String serviceID, int times) {
for (int i = 0; i < times; i++) {
strategy.notifyCallFailed(clientSideCallContext);
}
}
private void givenConfigWith(String configName) {
routerConfiguration.setBlacklistStrategyConfigurationName(configName);
strategy.setConfiguration(routerConfiguration);
}
}