Java WireMock, определяющий заглушки, терпит неудачу в многопоточных тестах с параллельным выполнением Cucumber

У меня есть приложение Spring-Boot и интеграционные тесты с использованием Cucumber и WireMock. Выполнение тестов в обычном непараллельном режиме выполнения работает нормально и без каких-либо проблем, но при переключении на параллельный режим с помощью cucumber.execution.parallel.enabled as true начались сбои. Исключение:

com.github.tomakehurst.wiremock.common.JsonException: 
{
  "errors" : [ {
    "code" : 10,
    "source" : {
      "pointer" : "/code"
    },
    "title" : "Error parsing JSON",
    "detail" : "Unrecognized field \"code\" (class com.github.tomakehurst.wiremock.common.Errors), not marked as ignorable"
  } ]
}
    at com.github.tomakehurst.wiremock.common.JsonException.fromJackson(JsonException.java:53)
    at com.github.tomakehurst.wiremock.common.Json.read(Json.java:60)
    at com.github.tomakehurst.wiremock.client.HttpAdminClient.safelyExecuteRequest(HttpAdminClient.java:519)
    at com.github.tomakehurst.wiremock.client.HttpAdminClient.executeRequest(HttpAdminClient.java:489)
    at com.github.tomakehurst.wiremock.client.HttpAdminClient.executeRequest(HttpAdminClient.java:466)
    at com.github.tomakehurst.wiremock.client.HttpAdminClient.addStubMapping(HttpAdminClient.java:146)
    at com.github.tomakehurst.wiremock.client.WireMock.register(WireMock.java:414)
    at com.github.tomakehurst.wiremock.client.WireMock.register(WireMock.java:409)
    at com.github.tomakehurst.wiremock.client.WireMock.givenThat(WireMock.java:115)
    at com.github.tomakehurst.wiremock.client.WireMock.stubFor(WireMock.java:119)

Должна ли WireMock.stubFor быть потокобезопасной операцией? Судя по исключению, похоже, нет. Если нет потокобезопасности, какие обходные пути возможны (синхронизировать/заблокировать все выполнения stubFor)?

Пример инициализации заглушки:

WireMock.stubFor(post(urlPathMatching("/test"))
    .withRequestBody(equalToJson(..))
    .willReturn(aResponse()
        .withStatus(200)
        .withHeader("Content-Type", "application/json")
        .withBody(..)));

WireMock создается следующим образом:

WireMockServer wireMock = new WireMockServer(options()
    .port(8000)
    .extensions(new ResponseTemplateTransformer(true))
    .notifier(new ConsoleNotifier(true)));
wireMock.start();
configureFor(8000);

версия: com.github.tomakehurst:wiremock-jre8-standalone:2.33.0

У вас есть две проблемы. Во-первых, ваши зависимости Wiremock несовместимы друг с другом. В результате ваш клиент Wiremock не распознает ошибку сервера Wiremock. Это вызывает ошибку, которую вы видите сейчас. Во-вторых, что вообще заставило сервер Wiremock отправить вам сообщение об ошибке. Вы хотите решить вторую задачу, но не сможете увидеть детали этой проблемы, пока не решите первую задачу.

M.P. Korstanje 25.03.2024 10:03

Клиент и сервер Wiremock - в каких зависимостях maven они присутствуют? потому что теперь у меня есть только транзитивная зависимость от com.github.tomakehurst:wiremock-jre8-standalone

Vasyl Sarzhynskyi 25.03.2024 10:13

Не могу сказать, что вы не предоставили достаточно информации, чтобы воспроизвести вашу проблему. В какой-то момент Wiremock действительно переехал с com.github.tomakehurst на com.wiremock. Возможно, это и есть причина, но это всего лишь предположение.

M.P. Korstanje 25.03.2024 10:31

Если вы начнете отладку с HttpAdminClient.safelyExecuteRequest, вы, вероятно, сможете увидеть, что сервер на самом деле отправляет обратно.

M.P. Korstanje 25.03.2024 10:33

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

Vasyl Sarzhynskyi 25.03.2024 10:45

Да, но сейчас вы не можете понять, что вызывает эту проблему. Иногда сначала нужно побрить Яка.

M.P. Korstanje 25.03.2024 11:01

Проблема @M.P.Korstanje возникла из-за неправильного выбора порта сервера WireMock, выполненного из другого потока, и ответ не был получен с кодом ошибки 404. Поскольку этот ответ не от сервера WireMock, полезная нагрузка не была десериализована в класс Errors из библиотеки WireMock. Спасибо за попытку помочь и дать несколько полезных советов!

Vasyl Sarzhynskyi 27.03.2024 21:12

Поздравляем! Это было не то, чего я ожидал.

M.P. Korstanje 27.03.2024 21:44
Пользовательский скаляр GraphQL
Пользовательский скаляр GraphQL
Листовые узлы системы типов GraphQL называются скалярами. Достигнув скалярного типа, невозможно спуститься дальше по иерархии типов. Скалярный тип...
Как вычислять биты и понимать побитовые операторы в Java - объяснение с примерами
Как вычислять биты и понимать побитовые операторы в Java - объяснение с примерами
В компьютерном программировании биты играют важнейшую роль в представлении и манипулировании данными на двоичном уровне. Побитовые операции...
Поднятие тревоги для долго выполняющихся методов в Spring Boot
Поднятие тревоги для долго выполняющихся методов в Spring Boot
Приходилось ли вам сталкиваться с требованиями, в которых вас могли попросить поднять тревогу или выдать ошибку, когда метод Java занимает больше...
Полный курс Java для разработчиков веб-сайтов и приложений
Полный курс Java для разработчиков веб-сайтов и приложений
Получите сертификат Java Web и Application Developer, используя наш курс.
1
8
295
1
Перейти к ответу Данный вопрос помечен как решенный

Ответы 1

Ответ принят как подходящий

После замены класса com.github.tomakehurst.wiremock.client.HttpAdminClient в моем репозитории и добавления дополнительных журналов было обнаружено, что телом ответа во время выполнения определения заглушки является {"code":"404.null.55","message":"Not Found"}. Проблема заключалась в том, что запрос был нацелен на неверный порт, он использовал порт по умолчанию 8080 вместо настроенного 8000. В моем случае порт 8000 был настроен для сервера WireMock и 8080 для Tomcat из теста Spring Boot.

Первоначально при запуске контекста Spring код настраивает сервер WireMock с портом 8000 из потока main следующим образом:

WireMockServer wireMock = new WireMockServer(options()
    .port(8000)
    .extensions(new ResponseTemplateTransformer(true))
    .notifier(new ConsoleNotifier(true)));
wireMock.start();
configureFor(8000);

а позже WireMock.stubFor(..) вызывается из другого потока (из-за режима параллельного выполнения Cucumber). Из-за реализации внутри WireMock у него есть локальный поток defaultInstance, который должен быть дополнительно настроен с использованием соответствующего порта из вызванного потока.

Поэтому я обновил код, чтобы он вызывал WireMock.configureFor(8000); перед каждым вызовом WireMock.stubFor(..), чтобы гарантировать, что порт настроен для каждого требуемого потока, и это устранило проблему.

Первоначальное исключение, с которым я столкнулся как JsonException Unrecognized field 'code', связано с неправильной обработкой кода ошибки клиента 404 внутри HttpAdminClient, поскольку эта ошибка не с сервера Wire Mock, а может быть с любого другого сервера (действительно, это редкий случай, но все же может случиться). Я либо открою проблему, либо внесу исправление в WireMock, чтобы иметь описательную ошибку с явным указанием используемого порта в случае кода ошибки 404, поэтому библиотека будет корректно обрабатывать такие случаи.

Обновлять:

Изменение вклада WireMock с описательным сообщением об исключении было объединено.

Другие вопросы по теме