RESTassured вызывает IOExceptions «существующее соединение было принудительно закрыто удаленным хостом» в undertow - PullRequest
0 голосов
/ 07 ноября 2018

Я настроил RESTassured для работы с undertow с моим приложением REST в памяти, используя maven, который использует фазы pre-integration-test и post-integration-test, чтобы установить его как демон и разорвать его.

Мой большой недостаток в том, что undertow выплевывает следы стека в конце фаз интеграционного теста, как будто RESTassured никогда не освобождает свои HTTP-соединения.

Итак, мой вопрос:

Что мне нужно сделать, чтобы правильно закрывать HTTP-соединения после каждого теста, в Undertow или в RESTassured?

Вот кровавые подробности.

Сервер Undertow

Я запускаю Undertow со стандартным кодом Undertow, который можно найти по всему SO:

    HttpHandler contextHandler = Handlers.path()
                .addPrefixPath("/", manager.start());
    return Undertow.builder()
            .addHttpListener(port, address,
                    new GracefulShutdownHandler(contextHandler))
            .build();

Stacktraces

Существует один для каждого вызова REST, который выполняет RESTassured. Они выглядят так:

19:07:07.569 io : Error reading request : DEBUG : XNIO-1 I/O-1 : 
    io.undertow.server.protocol.http.HttpReadListener  
        java.io.IOException: 
            An existing connection was forcibly closed by the remote host
    at sun.nio.ch.SocketDispatcher.read0(Native Method)
    at sun.nio.ch.SocketDispatcher.read(SocketDispatcher.java:43)
    at io.undertow.server.protocol.http.HttpReadListener.handleEventWithNoRunningRequest(HttpReadListener.java:158)
    [snipped - see below for full stacktraces]

RESTassured

Вот как выглядит каждый блок тестового кода:

@Test
public void test() {
    RequestSpecification requestSpecification =
            new RequestSpecBuilder()
                    .setContentType(ContentType.JSON)
                    .addFilter(new ResponseLoggingFilter())
                    .addFilter(new RequestLoggingFilter())
                    .build();
    given().spec(requestSpecification)
            .queryParam("name", "honky")
            .queryParam("description", "oh my")
            .queryParam("actualizationDate", "1999-12-31T23:59:59Z")
            .queryParam("active", "True")
            .when()
            .post("2/widget/save")
            .then()
            .statusCode(200);

Журналы

А вот журналы ниже.

Уровень ведения журнала откатов установлен на TRACE - Я бы хотел, чтобы они выводили немного больше. Все еще освежает, хотя по сравнению с Bloatosaurus spring.io :)

Если вы оказались отвлечены двумя вызовами, зарегистрированными с помощью undertow.HttpServerExchange в блоке предварительного тестирования, они будут в порядке. Это:

  1. вызов, чтобы узнать, работает ли сервер (не уверен)
  2. вызов покоя для создания тестового пользователя (также не уверен)

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

[INFO] 
[INFO] --- exec-maven-plugin:1.6.0:java (pre-int-test) @ gem-widget ---
13:49:55.951 request : UT015007: Stack trace on error enabled for deployment integration-testing, please do not enable for production use : WARN : Thread-2 : io.undertow.servlet.core.DeploymentManagerImpl  
13:49:55.996 session : Setting default session timeout to 1800 : DEBUG : Thread-2 : org.jboss.logging.DelegatingBasicLogger  
13:49:56.026 servlet : 1 Spring WebApplicationInitializers detected on classpath : INFO : Thread-2 : io.undertow.servlet.spec.ServletContextImpl  
13:49:56.101 session : Registered session listener io.undertow.servlet.core.SessionListenerBridge@48b96dfa : DEBUG : Thread-2 : io.undertow.server.session.InMemorySessionManager  
13:49:56.105 servlet : Initializing Spring root WebApplicationContext : INFO : Thread-2 : io.undertow.servlet.spec.ServletContextImpl  
13:50:13.112 servlet : Initializing Spring FrameworkServlet 'dispatcher' : INFO : Thread-2 : io.undertow.servlet.spec.ServletContextImpl  
13:50:13.226 undertow : starting undertow server io.undertow.Undertow@5eb8dc7d : DEBUG : Thread-2 : io.undertow.Undertow  
13:50:14.378 undertow : Configuring listener with protocol HTTP for interface localhost and port 8080 : DEBUG : Thread-2 : io.undertow.Undertow  
13:50:14.424 undertow : Configuring listener with protocol HTTP for interface 0.0.0.0 and port 8090 : DEBUG : Thread-2 : io.undertow.Undertow  
13:50:14.877 request : Opened connection with /127.0.0.1:58156 : TRACE : XNIO-1 I/O-1 : io.undertow.server.protocol.http.HttpOpenListener  
13:50:15.070 HttpServerExchange : Starting to write response for HttpServerExchange{ GET / request {Accept=[text/html, image/gif, image/jpeg, *; q=.2, */*; q=.2], Connection=[keep-alive], Content-Type=[application/json], User-Agent=[Java/1.8.0_131], Host=[localhost:8080]} response {Connection=[keep-alive], Content-Type=[application/json;charset=ISO-8859-1], Content-Length=[0], Date=[Wed, 07 Nov 2018 13:50:15 GMT]}} : TRACE : XNIO-1 task-1 : io.undertow.server.HttpServerExchange  
13:50:15.387 HttpServerExchange : Starting to write response for HttpServerExchange{ POST /2/mgmt/create_user/TEST/true request {Accept=[text/html, image/gif, image/jpeg, *; q=.2, */*; q=.2], Connection=[keep-alive], Content-Type=[application/json], User-Agent=[Java/1.8.0_131], Host=[localhost:8080]} response {Connection=[keep-alive], Content-Length=[0], Date=[Wed, 07 Nov 2018 13:50:15 GMT]}} : TRACE : XNIO-1 task-2 : io.undertow.server.HttpServerExchange  
[INFO] 
[INFO] --- maven-failsafe-plugin:2.22.1:integration-test (default) @ gem-widget ---
[INFO] 
[INFO] -------------------------------------------------------
[INFO]  T E S T S
[INFO] -------------------------------------------------------
[INFO] Running com.megacorp.widget.rest.WidgetSaveTests
13:50:19.928 request : Opened connection with /127.0.0.1:58170 : TRACE : XNIO-1 I/O-3 : io.undertow.server.protocol.http.HttpOpenListener  
13:50:19.935 HttpServerExchange : Starting to write response for HttpServerExchange{ GET / request {Accept=[text/html, image/gif, image/jpeg, *; q=.2, */*; q=.2], Connection=[keep-alive], Content-Type=[application/json], User-Agent=[Java/1.8.0_131], Host=[localhost:8080]} response {Connection=[keep-alive], Content-Type=[application/json;charset=ISO-8859-1], Content-Length=[0], Date=[Wed, 07 Nov 2018 13:50:19 GMT]}} : TRACE : XNIO-1 task-3 : io.undertow.server.HttpServerExchange  
Request method: POST
Request URI:    http://localhost:8080/2/widget/save?name=THARG.YES.GOOD.IDEA.6.7.8.9&description=oh%20my&actualizationDate=1999-12-31T23%3A59%3A59Z&active=True
Proxy:          <none>
Request params: <none>
Query params:   name=THARG.YES.GOOD.IDEA.6.7.8.9
                description=oh my
                actualizationDate=1999-12-31T23:59:59Z
                active=True
Form params:    <none>
Path params:    <none>
Headers:        Accept=*/*
                Content-Type=application/json; charset=UTF-8
Cookies:        <none>
Multiparts:     <none>
Body:           <none>
13:50:22.996 request : Opened connection with /127.0.0.1:58171 : TRACE : XNIO-1 I/O-4 : io.undertow.server.protocol.http.HttpOpenListener  
13:50:23.031 transfer-encoding : No content, starting next request : TRACE : XNIO-1 I/O-4 : io.undertow.server.protocol.http.HttpTransferEncoding  
13:50:23.276 HttpServerExchange : Starting to write response for HttpServerExchange{ POST /2/widget/save request {Accept=[*/*], Connection=[Keep-Alive], Accept-Encoding=[gzip,deflate], Content-Type=[application/json; charset=UTF-8], Content-Length=[0], User-Agent=[Apache-HttpClient/4.5.3 (Java/1.8.0_131)], Host=[localhost:8080]} response {Connection=[keep-alive], Transfer-Encoding=[chunked], Content-Type=[application/json;charset=UTF-8], Date=[Wed, 07 Nov 2018 13:50:23 GMT]}} : TRACE : XNIO-1 task-4 : io.undertow.server.HttpServerExchange  
13:50:23.334 RequestSpecificationImpl$RestAssuredHttpBuilder : Parsing response as: application/json;charset=UTF-8 : DEBUG : main : io.restassured.internal.http.HTTPBuilder  
13:50:23.341 RequestSpecificationImpl$RestAssuredHttpBuilder : Parsed data to instance of: class org.apache.http.conn.EofSensorInputStream : DEBUG : main : io.restassured.internal.http.HTTPBuilder  
HTTP/1.1 200 OK
Connection: keep-alive
Transfer-Encoding: chunked
Content-Type: application/json;charset=UTF-8
Date: Wed, 07 Nov 2018 13:50:23 GMT

[

]
[INFO] Tests run: 1, Failures: 0, Errors: 0, Skipped: 0, Time elapsed: 3.974 s - in com.megacorp.widget.rest.WidgetSaveTests
13:50:24.343 io : Error reading request : DEBUG : XNIO-1 I/O-4 : io.undertow.server.protocol.http.HttpReadListener  
java.io.IOException: An existing connection was forcibly closed by the remote host
    at sun.nio.ch.SocketDispatcher.read0(Native Method)
    at sun.nio.ch.SocketDispatcher.read(SocketDispatcher.java:43)
    at sun.nio.ch.IOUtil.readIntoNativeBuffer(IOUtil.java:223)
    at sun.nio.ch.IOUtil.read(IOUtil.java:192)
    at sun.nio.ch.SocketChannelImpl.read(SocketChannelImpl.java:380)
    at org.xnio.nio.NioSocketConduit.read(NioSocketConduit.java:319)
    at org.xnio.conduits.ConduitStreamSourceChannel.read(ConduitStreamSourceChannel.java:127)
    at io.undertow.server.protocol.http.HttpReadListener.handleEventWithNoRunningRequest(HttpReadListener.java:158)
    at io.undertow.server.protocol.http.HttpReadListener.handleEvent(HttpReadListener.java:136)
    at io.undertow.server.protocol.http.HttpReadListener.handleEvent(HttpReadListener.java:59)
    at org.xnio.ChannelListeners.invokeChannelListener(ChannelListeners.java:92)
    at org.xnio.conduits.ReadReadyHandler$ChannelListenerHandler.readReady(ReadReadyHandler.java:66)
    at org.xnio.nio.NioSocketConduit.handleReady(NioSocketConduit.java:88)
    at org.xnio.nio.WorkerThread.run(WorkerThread.java:561)
13:50:24.343 io : Error reading request : DEBUG : XNIO-1 I/O-3 : io.undertow.server.protocol.http.HttpReadListener  
java.io.IOException: An existing connection was forcibly closed by the remote host
    at sun.nio.ch.SocketDispatcher.read0(Native Method)
    at sun.nio.ch.SocketDispatcher.read(SocketDispatcher.java:43)
    at sun.nio.ch.IOUtil.readIntoNativeBuffer(IOUtil.java:223)
    at sun.nio.ch.IOUtil.read(IOUtil.java:192)
    at sun.nio.ch.SocketChannelImpl.read(SocketChannelImpl.java:380)
    at org.xnio.nio.NioSocketConduit.read(NioSocketConduit.java:319)
    at org.xnio.conduits.ConduitStreamSourceChannel.read(ConduitStreamSourceChannel.java:127)
    at io.undertow.server.protocol.http.HttpReadListener.handleEventWithNoRunningRequest(HttpReadListener.java:158)
    at io.undertow.server.protocol.http.HttpReadListener.handleEvent(HttpReadListener.java:136)
    at io.undertow.server.protocol.http.HttpReadListener.handleEvent(HttpReadListener.java:59)
    at org.xnio.ChannelListeners.invokeChannelListener(ChannelListeners.java:92)
    at org.xnio.conduits.ReadReadyHandler$ChannelListenerHandler.readReady(ReadReadyHandler.java:66)
    at org.xnio.nio.NioSocketConduit.handleReady(NioSocketConduit.java:88)
    at org.xnio.nio.WorkerThread.run(WorkerThread.java:561)
[INFO] 
[INFO] Results:
[INFO] 
[INFO] Tests run: 1, Failures: 0, Errors: 0, Skipped: 0
[INFO] 
[INFO] 
[INFO] --- exec-maven-plugin:1.6.0:java (post-int-test) @ gem-widget ---
13:50:24.749 request : Opened connection with /127.0.0.1:58182 : TRACE : XNIO-1 I/O-1 : io.undertow.server.protocol.http.HttpOpenListener  
[INFO] 
[INFO] --- maven-failsafe-plugin:2.22.1:verify (default) @ gem-widget ---
[INFO] ------------------------------------------------------------------------
[INFO] BUILD SUCCESS
[INFO] ------------------------------------------------------------------------
[INFO] Total time: 55.591 s
[INFO] Finished at: 2018-11-07T13:50:24+00:00
[INFO] Final Memory: 57M/616M
[INFO] ------------------------------------------------------------------------
Disconnected from the target VM, address: '127.0.0.1:58132', transport: 'socket'
FATAL ERROR in native method: JDWP Can't allocate jvmti memory, jvmtiError=JVMTI_ERROR_INVALID_ENVIRONMENT(116)
JDWP exit error JVMTI_ERROR_WRONG_PHASE(112): on getting class status [util.c:1285]
JDWP exit error JVMTI_ERROR_INVALID_ENVIRONMENT(116): Can't allocate jvmti memory [util.c:1799]
ERROR: JDWP unable to dispose of JVMTI environment: JVMTI_ERROR_INVALID_ENVIRONMENT(116)

Process finished with exit code 1
...