From 56f88fff3c7cab67e2e1999cb262db386e5556c8 Mon Sep 17 00:00:00 2001 From: "David K. Bainbridge" Date: Wed, 19 Mar 2014 11:04:51 -0700 Subject: [PATCH] Use a random port in test server This patch updates the test server to bind to a random port number and expose this port number via a Future can be fetched by the test client so that it knows to which port to connect. Version 2: Modified the code to use the guava SettableFuture as opposed to a custom built future, as well as cleaned up a few other things, including makding sure that the message was received from the server before considering the test passed. was seeing different behavior on different platforms without this (i.e. some times the message was display, sometimes not). Also, failed the test case wh exceptions were caught. Change-Id: Ia11c374bfbf206a6214d2afe3ba328b1231d6fad Signed-off-by: David K. Bainbridge Signed-off-by: Robert Varga --- websocket/websocket-client/pom.xml | 4 ++ .../websocket/WebSocketClientTest.java | 53 +++++++++++++--- .../websocket/server/WebSocketServer.java | 62 ++++++++++++++----- 3 files changed, 93 insertions(+), 26 deletions(-) diff --git a/websocket/websocket-client/pom.xml b/websocket/websocket-client/pom.xml index a930950360..9a1c8df5ae 100644 --- a/websocket/websocket-client/pom.xml +++ b/websocket/websocket-client/pom.xml @@ -21,6 +21,10 @@ jar + + com.google.guava + guava + io.netty netty-codec-http diff --git a/websocket/websocket-client/src/test/java/org/opendaylight/yangtools/websocket/WebSocketClientTest.java b/websocket/websocket-client/src/test/java/org/opendaylight/yangtools/websocket/WebSocketClientTest.java index 9f94887f9a..a5bbb87b49 100644 --- a/websocket/websocket-client/src/test/java/org/opendaylight/yangtools/websocket/WebSocketClientTest.java +++ b/websocket/websocket-client/src/test/java/org/opendaylight/yangtools/websocket/WebSocketClientTest.java @@ -7,60 +7,95 @@ */ package org.opendaylight.yangtools.websocket; -import io.netty.handler.codec.http.websocketx.CloseWebSocketFrame; import java.net.URI; import java.net.URISyntaxException; + import org.junit.Before; import org.junit.Test; -import org.opendaylight.yangtools.websocket.client.WebSocketIClient; -import org.opendaylight.yangtools.websocket.server.WebSocketServer; +import org.junit.Assert; + import org.slf4j.Logger; import org.slf4j.LoggerFactory; +import java.util.concurrent.ExecutionException; +import java.util.concurrent.TimeUnit; +import java.util.concurrent.TimeoutException; + +import org.opendaylight.yangtools.websocket.client.WebSocketIClient; +import org.opendaylight.yangtools.websocket.server.WebSocketServer; + +import io.netty.handler.codec.http.websocketx.CloseWebSocketFrame; + +import com.google.common.util.concurrent.SettableFuture; + public class WebSocketClientTest { private static final Logger logger = LoggerFactory.getLogger(WebSocketClientTest.class.toString()); private static final String MESSAGE = "Take me to your leader!"; - private static final int port = 8080; private Thread webSocketServerThread; + /** + * Tracks if the message from the server has been received + */ + private SettableFuture messageReceived = SettableFuture.create(); + + /** + * Tracks the port on which the server is listening + */ + private int port = 0; @Before public void startWebSocketServer(){ try { - WebSocketServer webSocketServer = new WebSocketServer(port); + WebSocketServer webSocketServer = new WebSocketServer(0); webSocketServerThread = new Thread(webSocketServer); webSocketServerThread.setDaemon(false); webSocketServerThread.start(); + port = webSocketServer.getPort().get(); } catch (Exception e) { logger.trace("Error starting websocket server"); } } + @Test public void connectAndSendData(){ URI uri = null; try { - uri = new URI("ws://localhost:8080/websocket"); + uri = new URI(String.format("ws://localhost:%d/websocket", port)); + logger.info("CLIENT: " + uri); ClientMessageCallback messageCallback = new ClientMessageCallback(); WebSocketIClient wsClient = new WebSocketIClient(uri,messageCallback); try { wsClient.connect(); wsClient.writeAndFlush(MESSAGE); wsClient.writeAndFlush(new CloseWebSocketFrame()); + + /* + * Wait for up to 5 seconds for the message to be received. If + * after that time, the message has not been received then + * consider this a failed test. + */ + messageReceived.get(5, TimeUnit.SECONDS); + webSocketServerThread.interrupt(); } catch (InterruptedException e) { - logger.info("WebSocket client couldn't connect to : "+uri); + logger.info("WebSocket client couldn't connect to : " + uri); + Assert.fail("WebSocker client could not connect to : " + uri); + } catch (ExecutionException | TimeoutException toe) { + logger.info("Message not received"); + Assert.fail(toe.toString()); } } catch (URISyntaxException e) { logger.info("There is an error in URL sytnax {}",e); + Assert.fail("There is an error in URL sytnax"); } } private class ClientMessageCallback implements org.opendaylight.yangtools.websocket.client.callback.ClientMessageCallback { @Override public void onMessageReceived(Object message) { - logger.info("received message {}",message); - System.out.println("received message : " + message); + logger.info("received message {}",message); + messageReceived.set(true); } } } diff --git a/websocket/websocket-client/src/test/java/org/opendaylight/yangtools/websocket/server/WebSocketServer.java b/websocket/websocket-client/src/test/java/org/opendaylight/yangtools/websocket/server/WebSocketServer.java index 08d51b3f68..8fb379cb79 100644 --- a/websocket/websocket-client/src/test/java/org/opendaylight/yangtools/websocket/server/WebSocketServer.java +++ b/websocket/websocket-client/src/test/java/org/opendaylight/yangtools/websocket/server/WebSocketServer.java @@ -20,9 +20,20 @@ import io.netty.channel.Channel; import io.netty.channel.EventLoopGroup; import io.netty.channel.nio.NioEventLoopGroup; import io.netty.channel.socket.nio.NioServerSocketChannel; + import org.slf4j.Logger; import org.slf4j.LoggerFactory; +import java.net.SocketAddress; +import java.net.InetSocketAddress; + +import java.util.concurrent.Future; +import java.util.concurrent.TimeUnit; +import java.util.concurrent.ExecutionException; +import java.util.concurrent.TimeoutException; + +import com.google.common.util.concurrent.SettableFuture; + /** * A HTTP server which serves Web Socket requests at: * @@ -44,19 +55,28 @@ import org.slf4j.LoggerFactory; */ public class WebSocketServer implements Runnable { - private final int port; + /** + * Utilized to get the port on which the server listens. This is a future as + * the port is selected dynamically from available ports, thus until the + * server is started the value will not be established. + */ + private final SettableFuture port; + + /** + * Maintains the port number with which the class was initialized. + */ + private final int inPort; private final ServerBootstrap bootstrap = new ServerBootstrap(); private final EventLoopGroup bossGroup = new NioEventLoopGroup(); private final EventLoopGroup workerGroup = new NioEventLoopGroup(); private static final Logger logger = LoggerFactory.getLogger(WebSocketServer.class.toString()); - public WebSocketServer(int port) { - this.port = port; + + public WebSocketServer(int inPort) { + this.inPort = inPort; + port = SettableFuture.create(); } - /** - * Tries to start web socket server. - */ public void run(){ try { startServer(); @@ -64,27 +84,35 @@ public class WebSocketServer implements Runnable { logger.info("Exception occured while starting webSocket server {}",e); } } - - /** - * Start web socket server at {@link #port}. - * @throws Exception - */ + + public Future getPort() { + return port; + } + public void startServer() throws Exception { try { bootstrap.group(bossGroup, workerGroup) .channel(NioServerSocketChannel.class) .childHandler(new WebSocketServerInitializer()); - Channel ch = bootstrap.bind(port).sync().channel(); - logger.info("Web socket server started at port " + port + '.'); - logger.info("Open your browser and navigate to http://localhost:" + port + '/'); + Channel ch = bootstrap.bind(inPort).sync().channel(); + SocketAddress localSocket = ch.localAddress(); + try { + port.set(((InetSocketAddress) localSocket).getPort()); + } catch (ClassCastException cce) { + throw new ExecutionException("Unknown socket address type", cce); + } + logger.info("Web socket server started at port " + port.get() + '.'); + logger.info("Open your browser and navigate to http://localhost:" + port.get() + '/'); - ch.closeFuture().sync(); + try { + ch.closeFuture().sync(); + } catch (InterruptedException ie) { + // No op, sometimes the server is shutdown hard + } } finally { bossGroup.shutdownGracefully(); workerGroup.shutdownGracefully(); } } - - } -- 2.36.6