Тест-драйв конфигурации автоматического выключателя Hystrix

Наше приложение написано с соблюдением требований безопасности за счет реализации шаблона автоматического выключателя с использованием Hystrix.

Все приложение создано с использованием практики, основанной на тестировании, но застряло в точке, где нам нужно реализовать стратегию прерывателя цепи, настроив ее в методах.

Ниже приведен образец конфигурации, используемый нами -

@HystrixCommand(commandProperties = {
        @HystrixProperty(name = "circuitBreaker.enabled", value = "true"),
        @HystrixProperty(name = "circuitBreaker.requestVolumeThreshold", value = "8"),
        @HystrixProperty(name = "circuitBreaker.errorThresholdPercentage", value = "25"),
        @HystrixProperty(name = "execution.isolation.thread.timeoutInMilliseconds", value = "2000")},
        fallbackMethod = "retrieveMapFallback")

Может ли кто-нибудь прокомментировать, есть ли доступная функция или возможность протестировать ее в моем интеграционном тесте (который загружает весь WebApplicationContext и, следовательно, знает обо всех конфигурациях, доступных в приложении)?

Или это вообще невозможно проверить в контексте моего приложения?

Любые входные данные будут иметь значение.


person Ashwin Gupta    schedule 05.08.2016    source источник


Ответы (1)


Вы можете проверить конфигурацию автоматического выключателя Hystrix.

Например, взгляните на этот пример приложения с Spring Boot 1.4:

import com.netflix.hystrix.contrib.javanica.annotation.HystrixCommand;
import com.netflix.hystrix.contrib.javanica.annotation.HystrixProperty;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.client.circuitbreaker.EnableCircuitBreaker;
import org.springframework.stereotype.Component;

@EnableCircuitBreaker
@SpringBootApplication
public class HystrixDemo {

    public static void main(String[] args) {
        SpringApplication.run(HystrixDemo.class, args);
    }

    @Component
    static class MyService {

        static final String COMMAND_KEY = "MyCommandKey";

        private final Outbound outbound;

        MyService(Outbound outbound) {
            this.outbound = outbound;
        }

        @HystrixCommand(
                commandKey = COMMAND_KEY,
                commandProperties = {
                    @HystrixProperty(name = "execution.isolation.thread.timeoutInMilliseconds", value = "2016")
                })
        void process() {
            outbound.call();
        }
    }

    interface Outbound {
        void call();
    }
}

Ваши тесты конфигурации могут выглядеть так:

import com.netflix.hystrix.HystrixCommandKey;
import com.netflix.hystrix.HystrixCommandMetrics;
import com.netflix.hystrix.HystrixCommandProperties;
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.boot.test.mock.mockito.MockBean;
import org.springframework.test.context.junit4.SpringRunner;

import static org.junit.Assert.assertTrue;

@RunWith(SpringRunner.class)
@SpringBootTest
public class MyServiceCircuitBreakerConfigurationTests {

    @Autowired
    private HystrixDemo.MyService myService;

    @MockBean
    private HystrixDemo.Outbound outbound;

    @Before
    public void setup() {
        warmUpCircuitBreaker();
    }

    @Test
    public void shouldHaveCustomTimeout() {
        assertTrue(getCircuitBreakerCommandProperties().executionTimeoutInMilliseconds().get() == 2016);
    }

    private void warmUpCircuitBreaker() {
        myService.process();
    }

    public static HystrixCommandProperties getCircuitBreakerCommandProperties() {
        return HystrixCommandMetrics.getInstance(getCommandKey()).getProperties();
    }

    private static HystrixCommandKey getCommandKey() {
        return HystrixCommandKey.Factory.asKey(HystrixDemo.MyService.COMMAND_KEY);
    }
}

Кроме того, если вы хотите проверить автоматический выключатель, вы можете взглянуть на этот тест:

import com.netflix.config.ConfigurationManager;
import com.netflix.hystrix.Hystrix;
import com.netflix.hystrix.HystrixCircuitBreaker;
import com.netflix.hystrix.HystrixCommandKey;
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.boot.test.mock.mockito.MockBean;
import org.springframework.test.context.junit4.SpringRunner;

import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertTrue;
import static org.junit.Assert.fail;
import static org.mockito.BDDMockito.willThrow;

@RunWith(SpringRunner.class)
@SpringBootTest
public class MyServiceCircuitBreakerTests {

    @Autowired
    private HystrixDemo.MyService myService;

    @MockBean
    private HystrixDemo.Outbound outbound;

    @Before
    public void setup() {
        resetHystrix();
        warmUpCircuitBreaker();
        openCircuitBreakerAfterOneFailingRequest();
    }

    @Test
    public void shouldTripCircuit() throws InterruptedException {
        willThrow(new RuntimeException()).given(outbound).call();

        HystrixCircuitBreaker circuitBreaker = getCircuitBreaker();

        // demonstrates circuit is actually closed
        assertFalse(circuitBreaker.isOpen());
        assertTrue(circuitBreaker.allowRequest());

        try {
            myService.process();
            fail("unexpected");
        } catch (RuntimeException exception) {
            waitUntilCircuitBreakerOpens();
            assertTrue(circuitBreaker.isOpen());
            assertFalse(circuitBreaker.allowRequest());
        }
    }

    private void waitUntilCircuitBreakerOpens() throws InterruptedException {
        /* one second is almost sufficient
           borrowed from https://github.com/Netflix/Hystrix/blob/v1.5.5/hystrix-core/src/test/java/com/netflix/hystrix/HystrixCircuitBreakerTest.java#L140
         */
        Thread.sleep(1000);
    }

    private void resetHystrix() {
        Hystrix.reset();
    }

    private void warmUpCircuitBreaker() {
        myService.process();
    }

    public static HystrixCircuitBreaker getCircuitBreaker() {
        return HystrixCircuitBreaker.Factory.getInstance(getCommandKey());
    }

    private static HystrixCommandKey getCommandKey() {
        return HystrixCommandKey.Factory.asKey(HystrixDemo.MyService.COMMAND_KEY);
    }

    private void openCircuitBreakerAfterOneFailingRequest() {
        ConfigurationManager.getConfigInstance().setProperty("hystrix.command." + HystrixDemo.MyService.COMMAND_KEY + ".circuitBreaker.requestVolumeThreshold", 1);
    }
}   
person ksokol    schedule 02.09.2016
comment
Это отличный ответ. Спасибо за это @ksokol. Я попробую это и поделюсь, если есть какие-либо материалы. - person Ashwin Gupta; 05.09.2016