fabric8io / mockwebserver

An extension of okhttp's mockwebserver, that provides a DSL and is easier to use
Apache License 2.0
113 stars 38 forks source link

WebSocket only written to on close #44

Closed trickl closed 4 years ago

trickl commented 5 years ago

I've been trying to use timed websocket messages with a simple example, modified from the README.

server.expect().withPath("/websocket")    
    .andUpgradeToWebSocket()        
    .open()
        .immediately().andEmit("root - CREATED")
        .waitFor(3000).andEmit("root - CREATED")
        .waitFor(6000).andEmit("root - CREATED")
        .waitFor(9000).andEmit("root - CREATED")
        .waitFor(15000).andEmit("root - DELETED")
    .done()
    .once();

This produces the unexpected behaviour of all the messages being sent at once.

2019-09-22 15:00:18.900  INFO 11015 --- [WebServer 44153] okhttp3.mockwebserver.MockWebServer      : MockWebServer[44153] starting to accept connections
2019-09-22 15:00:18.976  INFO 11015 --- [           main] SESSION                                  : onSubscribe(MonoNext.NextSubscriber)
2019-09-22 15:00:18.977  INFO 11015 --- [           main] SESSION                                  : request(unbounded)
2019-09-22 15:00:34.112  INFO 11015 --- [or-http-epoll-4] c.t.f.websocket.SimpleWebSocketHandler   : Message ReceivedWebSocket TEXT message (14 bytes)
2019-09-22 15:00:34.116  INFO 11015 --- [or-http-epoll-4] c.t.f.websocket.SimpleWebSocketHandler   : Message ReceivedWebSocket TEXT message (14 bytes)
2019-09-22 15:00:34.117  INFO 11015 --- [or-http-epoll-4] c.t.f.websocket.SimpleWebSocketHandler   : Message ReceivedWebSocket TEXT message (14 bytes)
2019-09-22 15:00:34.118  INFO 11015 --- [or-http-epoll-4] c.t.f.websocket.SimpleWebSocketHandler   : Message ReceivedWebSocket TEXT message (14 bytes)
2019-09-22 15:00:34.121  INFO 11015 --- [or-http-epoll-4] c.t.f.websocket.SimpleWebSocketHandler   : Message ReceivedWebSocket TEXT message (14 bytes)
2019-09-22 15:00:34.126  INFO 11015 --- [or-http-epoll-4] SESSION                                  : onComplete()

From my own debugging of this problem, it seems to be because okhttp3.internal.ws.RealWebSocket implementation requires the stream writer to be in initialized before messages are sent. They provide a connect() method to do this (the normal way it would be initialized), or they have made their initReaderAndWriter method public as an alternative way. The websocket close handle also initializes the writer, prior to sending all enqueued messages. That would seem to explain the visible behaviour - that no messages are actually sent until the socket is closed, when they are all sent simultaneously.

So I suspect the current implementation of opening websockets is broken, but in a way that is only noticable if you try and make use of timed messages? Or I missing something?

trickl commented 4 years ago

I’ve since found workarounds for this problem.