Wiremock - 有时它会抛出“软件导致连接中止:接收失败”

Vic*_*tor 7 spring integration-testing wiremock

在使用 Spring 和 Wiremock 进行集成测试时,我遇到了一种非常奇怪的情况:突然,一个特定的测试开始间歇性失败。下面是错误的片段:

org.springframework.web.client.ResourceAccessException: I/O error on POST request for "http://localhost:10314/my/endpoint": Software caused connection abort: recv failed; nested exception is java.net.SocketException: Software caused connection abort: recv failed
    at org.springframework.web.client.RestTemplate.doExecute(RestTemplate.java:785) ~[spring-web-5.3.7.jar:5.3.7]
    at org.springframework.web.client.RestTemplate.execute(RestTemplate.java:711) ~[spring-web-5.3.7.jar:5.3.7]
    at org.springframework.web.client.RestTemplate.postForEntity(RestTemplate.java:468) ~[spring-web-5.3.7.jar:5.3.7]
... more logs here ...
Run Code Online (Sandbox Code Playgroud)

上下文如下:我添加了一个使用wiremock 来存根响应的新测试:

wireMockServer.stubFor(WireMock.post("/my/endpoint")
    .withRequestBody(containing(aJsonRequestBodyHere))
    .willReturn(aResponse()
            .withBody(aJsonResponseHere)
            .withStatus(HttpStatus.OK.value())
            .withHeader(HttpHeader.CONTENT_TYPE.toString(), CONTENT_TYPE_APPLICATION_JSON)));
Run Code Online (Sandbox Code Playgroud)

对此存根端点的调用如下:

given()
    .when()
    .get("my/endpoint")
    .then()
    .body(containsString(theExpectedJsonResponse)))
    .statusCode(200);
Run Code Online (Sandbox Code Playgroud)

奇怪的部分

  • 相同的测试在我的本地计算机上运行没有任何问题 - 如果单独运行
  • 当在我的机器上运行所有测试时,有时相同的测试会失败,有时则不会
  • 只有这个测试每次都失败;没有其他测试失败
  • 当测试在 Jenkins 上运行时,它 100% 失败

Vic*_*tor 7

经过一番深入研究后,我发现这篇文章和这篇文章几乎 100% 描述了我的情况。

根本原因似乎是测试执行得太快——也许那些没有做太多事情——而 Wiremock 没有时间为下一个测试正确设置。Thread.sleep(2000)我通过在测试开始时添加 a 来测试这个假设,然后多次运行所有测试 - 所有测试都顺利通过。

第一篇文章中介绍了解决方案:注册一个Transformer类,该类将拦截所有响应并向Connection=close其添加标头。

更详细地说:我添加了一个Transformer类,该类扩展ResponseDefinitionTransformer并在每个响应上添加Connection标头。然后我创建了@Configuration带注释的类并注册了它Transformer

Transformer 类(摘自第一篇文章):

public class NoKeepAliveTransformer extends ResponseDefinitionTransformer {

    @Override
    public ResponseDefinition transform(Request request, ResponseDefinition responseDefinition, FileSource files, Parameters parameters) {
        return ResponseDefinitionBuilder.like(responseDefinition)
                .withHeader(HttpHeaders.CONNECTION, "close")
                .build();
    }

    @Override
    public String getName() {
        return "keep-alive-disabler";
    }
}
Run Code Online (Sandbox Code Playgroud)

配置类:

@Configuration
public class WiremockConfiguration {

    @Bean
    WireMockConfigurationCustomizer optionsCustomizer() {
        return options -> options.extensions(NoKeepAliveTransformer.class);
    }
}
Run Code Online (Sandbox Code Playgroud)

  • 这里的根本原因可能不是 WireMock 没有准备好,因为它会阻塞直到完全启动。这更可能是您的 HTTP 客户端(在本例中是 RestAssured 的底层客户端)池连接方式的问题,这就是添加 Connection:close 修复此问题的原因。我建议尝试在客户端配置中修复此问题,而不是通过 WireMock 扩展,方法是禁用连接池或启用过时连接检查。 (2认同)