Статьи

Vert.X встречает виртуализацию услуг с Hoverfly

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

Hoverfly — это инструмент виртуализации сервисов, написанный на Go, который позволяет вам эмулировать сервисы HTTP (S). Это прокси, который отвечает на запросы HTTP (S) с сохраненными ответами, притворяясь его реальным аналогом.

Hoverfly Java — это оболочка для Hoverfly , которая позволяет использовать ее в мире Java. Он предоставляет собственный Java DSL для написания ожиданий и правило JUnit, чтобы использовать его вместе с JUnit .

Но помимо возможности программировать ожидания, вы также можете использовать Hoverfly для захвата трафика между обоими сервисами (в обоих случаях это реальные сервисы) и сохранения его.

Затем в следующих запусках Hoverfly будет использовать эти постоянные сценарии для эмуляции трафика, а не для связи с удаленным сервисом. Таким образом, вместо программирования ожиданий, что означает, что вы программируете то, как вы понимаете систему, вы используете реальные коммуникационные данные.

Это можно обобщить на следующих рисунках:

Первый раз выходной трафик отправляется через прокси-сервер Hoverfly , он перенаправляется на реальный сервис и генерирует ответ. Затем, когда ответ поступает на прокси-сервер, сохраняются и запрос, и ответ, и реальный ответ отправляется вызывающей стороне.

Затем в следующих вызовах того же метода:

Выходной трафик службы A по-прежнему отправляется через прокси-сервер Hoverfly , но теперь ответ возвращается из предыдущих сохраненных ответов вместо перенаправления на реальную службу.

Итак, как подключиться с HTTP-клиента Сервиса A к прокси Hoverfly ? Быстрый ответ — ничто.

Hoverfly просто переопределяет свойства сетевой системы Java ( https://docs.oracle.com/javase/7/docs/api/java/net/doc-files/net-properties.html ), поэтому вам не нужно ничего делать, Все коммуникации (независимо от того, какой хост вы там разместили) от HTTP-клиента будут проходить через прокси Hoverfly .

Проблема в том, что происходит, если API, который вы используете в качестве HTTP-клиента, не учитывает эти системные свойства? Тогда очевидно, что все исходящие сообщения не будут проходить через прокси.

Одним из примеров является Vert.X и его HTTP-клиент io.vertx.rxjava.ext.web.client.WebClient . Поскольку WebClient не соблюдает эти свойства, необходимо правильно настроить клиент для использования
Журчалка

Основной шаг, который вам нужно сделать, это просто настроить WebClient с параметрами прокси, которые установлены как системные свойства.

01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
final Optional<ProxyOptions> proxyOptions = useSystemPropertiesProxyOptions();
if (proxyOptions.isPresent()) {
     final WebClientOptions webClientOptions = new WebClientOptions();
     webClientOptions.setProxyOptions(proxyOptions.get());
     client = WebClient.create(vertx, webClientOptions);
} else {
     client = WebClient.create(vertx);
}
 
private Optional<ProxyOptions> useSystemPropertiesProxyOptions() {
  final String httpsProxy = System.getProperty("https.proxyHost");
  if (httpsProxy != null) {
      return Optional.of(new ProxyOptions()
          .setHost(httpsProxy)
          .setPort(Integer.parseInt(System.getProperty("https.proxyPort", "443"))));
  } else {
       final String httpProxy = System.getProperty("http.proxyHost");
       if (httpProxy != null) {
           return Optional.of(new ProxyOptions()
               .setHost(httpsProxy)
               .setPort(Integer.parseInt(System.getProperty("http.proxyPort", "80"))));
       }
  }
  return Optional.empty();
}

Обратите внимание, что единственное, что здесь сделано, — это просто проверяете, настроены ли системные свойства сетевого прокси (с помощью Hoverfly Java), и, если это так, просто создайте объект Vert.X ProxyOptions для настройки клиента HTTP.

С этим изменением вы можете без проблем писать тесты с Hoverfly и Vert.X

01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
public class VillainsVerticleTest {
 
    private static Vertx vertx;
 
    private static String RESPONSE = "[\n"
        + "    {\n"
        + "        \"name\": \"Moon\",\n"
        + "        \"villain\": \"Gru\",\n"
        + "        \"wiki\": \"https://en.wikipedia.org/wiki/Moon\"\n"
        + "    },\n"
        + "    {\n"
        + "        \"name\": \"Times Square JumboTron\",\n"
        + "        \"villain\": \"Gru\",\n"
        + "        \"wiki\": \"https://en.wikipedia.org/wiki/One_Times_Square\"\n"
        + "    }\n"
        + "]";
 
 
    @ClassRule
    public static HoverflyRule hoverflyRule = HoverflyRule.inSimulationMode(dsl(
        service("crimes:9090")
            .get("/crimes/Gru")
            .willReturn(success(RESPONSE, "application/json"))
    ));
 
    @BeforeClass
    public static void deployVerticle() throws InterruptedException {
        final CountDownLatch waitVerticleDeployed = new CountDownLatch(1);
 
        new Thread(() -> {
            vertx = Vertx.vertx();
            DeploymentOptions deploymentOptions = new DeploymentOptions().
                setConfig(new JsonObject()
                    .put("services.crimes.host", "crimes")
                    .put("services.crimes.port", 9090));
 
            vertx.deployVerticle(VillainsVerticle.class.getName(), deploymentOptions, event -> {
                if (event.failed()) {
                    throw new IllegalStateException("Cannot deploy Villains Verticle");
                }
                waitVerticleDeployed.countDown();
            });
        }).start();
        waitVerticleDeployed.await();
    }
 
    @Test
    public void should_get_villain_information() {
       given()
            .when()
            .get("villains/{villain}", "Gru")
            .then()
            .assertThat()
            .body("name", is("Gru"))
            .body("areaOfInfluence", is("Worldwide"))
            .body("crimes.name", hasItems("Moon", "Times Square JumboTron"));
 
    }
 
}

В предыдущем примере Hoverfly используется как в режиме имитации, и определения запроса / ответа приходят в форме DSL вместо внешнего JSON-скрипта. Обратите внимание, что в этом случае вы программируете, что при выполнении запроса текущей службой ( VillainsVerticle ) для размещения преступлений и порта 9090 с использованием метода GET HTTP в / crime / Gru ответ возвращается. Для простоты текущего поста этого метода достаточно.

Вы можете посмотреть исходный код по адресу https://github.com/arquillian-testing-microservices/villains-service и прочитать о Hoverfly Java на http://hoverfly-java.readthedocs.io/en/latest/