fix flaky test ClientCloseTest.testWriteException

Signed-off-by: Lachlan Roberts <lachlan@webtide.com>
This commit is contained in:
Lachlan Roberts 2019-05-01 10:15:30 +10:00 committed by Greg Wilkins
parent c33f3a75ed
commit bb8e5557d2
2 changed files with 47 additions and 21 deletions

View File

@ -19,11 +19,11 @@
package org.eclipse.jetty.websocket.tests.client; package org.eclipse.jetty.websocket.tests.client;
import java.io.IOException;
import java.net.URI; import java.net.URI;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.Arrays; import java.util.Arrays;
import java.util.List; import java.util.List;
import java.util.concurrent.CountDownLatch;
import java.util.concurrent.Future; import java.util.concurrent.Future;
import java.util.concurrent.TimeUnit; import java.util.concurrent.TimeUnit;
import java.util.concurrent.TimeoutException; import java.util.concurrent.TimeoutException;
@ -36,6 +36,7 @@ import org.eclipse.jetty.server.handler.DefaultHandler;
import org.eclipse.jetty.server.handler.HandlerList; import org.eclipse.jetty.server.handler.HandlerList;
import org.eclipse.jetty.servlet.ServletContextHandler; import org.eclipse.jetty.servlet.ServletContextHandler;
import org.eclipse.jetty.servlet.ServletHolder; import org.eclipse.jetty.servlet.ServletHolder;
import org.eclipse.jetty.util.BlockingArrayQueue;
import org.eclipse.jetty.util.log.Log; import org.eclipse.jetty.util.log.Log;
import org.eclipse.jetty.util.log.Logger; import org.eclipse.jetty.util.log.Logger;
import org.eclipse.jetty.websocket.api.CloseException; import org.eclipse.jetty.websocket.api.CloseException;
@ -66,11 +67,13 @@ import static org.hamcrest.Matchers.instanceOf;
import static org.hamcrest.Matchers.is; import static org.hamcrest.Matchers.is;
import static org.hamcrest.Matchers.nullValue; import static org.hamcrest.Matchers.nullValue;
import static org.junit.jupiter.api.Assertions.assertTimeoutPreemptively; import static org.junit.jupiter.api.Assertions.assertTimeoutPreemptively;
import static org.junit.jupiter.api.Assertions.assertTrue;
public class ClientCloseTest public class ClientCloseTest
{ {
private Server server; private Server server;
private WebSocketClient client; private WebSocketClient client;
private BlockingArrayQueue<ServerEndpoint> serverEndpoints = new BlockingArrayQueue<>();
private Session confirmConnection(CloseTrackingEndpoint clientSocket, Future<Session> clientFuture) throws Exception private Session confirmConnection(CloseTrackingEndpoint clientSocket, Future<Session> clientFuture) throws Exception
{ {
@ -128,7 +131,12 @@ public class ClientCloseTest
{ {
factory.getPolicy().setIdleTimeout(10000); factory.getPolicy().setIdleTimeout(10000);
factory.getPolicy().setMaxTextMessageSize(1024 * 1024 * 2); factory.getPolicy().setMaxTextMessageSize(1024 * 1024 * 2);
factory.register(ServerEndpoint.class); factory.setCreator((req,resp)->
{
ServerEndpoint endpoint = new ServerEndpoint();
serverEndpoints.offer(endpoint);
return endpoint;
});
} }
}); });
context.addServlet(holder, "/ws"); context.addServlet(holder, "/ws");
@ -353,6 +361,11 @@ public class ClientCloseTest
// client confirms connection via echo // client confirms connection via echo
confirmConnection(clientSocket, clientConnectFuture); confirmConnection(clientSocket, clientConnectFuture);
try
{
// Block on the server so that the server does not detect a read failure
clientSocket.getSession().getRemote().sendString("block");
// setup client endpoint for write failure (test only) // setup client endpoint for write failure (test only)
EndPoint endp = clientSocket.getEndPoint(); EndPoint endp = clientSocket.getEndPoint();
endp.shutdownOutput(); endp.shutdownOutput();
@ -366,16 +379,24 @@ public class ClientCloseTest
assertThat("OnError", clientSocket.error.get(), instanceOf(EofException.class)); assertThat("OnError", clientSocket.error.get(), instanceOf(EofException.class));
// client triggers close event on client ws-endpoint // client triggers close event on client ws-endpoint
// assert - close code==1006 (abnormal) or code==1001 (shutdown) // assert - close code==1006 (abnormal)
clientSocket.assertReceivedCloseEvent(timeout, anyOf(is(StatusCode.SHUTDOWN), is(StatusCode.ABNORMAL))); clientSocket.assertReceivedCloseEvent(timeout, is(StatusCode.ABNORMAL), null);
clientSessionTracker.assertClosedProperly(client); clientSessionTracker.assertClosedProperly(client);
assertThat(serverEndpoints.size(), is(1));
}
finally
{
for (ServerEndpoint endpoint : serverEndpoints)
endpoint.block.countDown();
}
} }
public static class ServerEndpoint implements WebSocketFrameListener, WebSocketListener public static class ServerEndpoint implements WebSocketFrameListener, WebSocketListener
{ {
private static final Logger LOG = Log.getLogger(ServerEndpoint.class); private static final Logger LOG = Log.getLogger(ServerEndpoint.class);
private Session session; private Session session;
CountDownLatch block = new CountDownLatch(1);
@Override @Override
public void onWebSocketBinary(byte[] payload, int offset, int len) public void onWebSocketBinary(byte[] payload, int offset, int len)
@ -395,15 +416,22 @@ public class ClientCloseTest
String bigmsg = new String(buf, UTF_8); String bigmsg = new String(buf, UTF_8);
session.getRemote().sendString(bigmsg); session.getRemote().sendString(bigmsg);
} }
else if (message.equals("block"))
{
LOG.debug("blocking");
assertTrue(block.await(5, TimeUnit.MINUTES));
LOG.debug("unblocked");
}
else else
{ {
// simple echo // simple echo
session.getRemote().sendString(message); session.getRemote().sendString(message);
} }
} }
catch (IOException ignore) catch (Throwable t)
{ {
LOG.debug(ignore); LOG.debug(t);
throw new RuntimeException(t);
} }
} }
@ -422,9 +450,7 @@ public class ClientCloseTest
public void onWebSocketError(Throwable cause) public void onWebSocketError(Throwable cause)
{ {
if (LOG.isDebugEnabled()) if (LOG.isDebugEnabled())
{ LOG.debug("onWebSocketError(): ", cause);
LOG.debug(cause);
}
} }
@Override @Override

View File

@ -94,8 +94,8 @@ public abstract class AbstractWebSocketConnection extends AbstractConnection imp
@Override @Override
public void onCompleteFailure(Throwable failure) public void onCompleteFailure(Throwable failure)
{ {
super.onCompleteFailure(failure);
AbstractWebSocketConnection.this.close(failure); AbstractWebSocketConnection.this.close(failure);
super.onCompleteFailure(failure);
} }
} }