/* * Copyright (c) 2014 Brocade Communications Systems, Inc. and others. All rights reserved. * * This program and the accompanying materials are made available under the * terms of the Eclipse Public License v1.0 which accompanies this distribution, * and is available at http://www.eclipse.org/legal/epl-v10.html */ package org.opendaylight.openflowjava.protocol.impl.core; import static org.junit.Assert.assertEquals; import io.netty.channel.ChannelHandlerContext; import java.io.IOException; import java.net.BindException; import java.net.InetAddress; import java.net.InetSocketAddress; import java.net.Socket; import java.util.concurrent.ExecutionException; import io.netty.channel.unix.Errors; import org.junit.Assert; import org.junit.Test; import org.mockito.Mock; import org.mockito.MockitoAnnotations; import org.opendaylight.openflowjava.protocol.api.connection.SwitchConnectionHandler; import org.opendaylight.openflowjava.protocol.impl.deserialization.DeserializationFactory; import org.opendaylight.openflowjava.protocol.impl.serialization.SerializationFactory; import com.google.common.util.concurrent.ListenableFuture; /** * * @author jameshall */ public class TcpHandlerTest { private InetAddress serverAddress = InetAddress.getLoopbackAddress() ; @Mock ChannelHandlerContext mockChHndlrCtx ; @Mock TcpChannelInitializer mockChannelInitializer; @Mock SwitchConnectionHandler mockSwitchConnHndler ; @Mock SerializationFactory mockSerializationFactory ; @Mock DeserializationFactory mockDeserializationFactory ; TcpHandler tcpHandler ; /** * Initialize mocks */ public TcpHandlerTest() { MockitoAnnotations.initMocks(this); } /** * Test run with null address set * @throws IOException * @throws InterruptedException * @throws ExecutionException */ @Test public void testRunWithNullAddress() throws IOException, InterruptedException, ExecutionException { tcpHandler = new TcpHandler(null, 0); tcpHandler.setChannelInitializer(mockChannelInitializer); assertEquals("failed to start server", true, startupServer(false)) ; assertEquals("failed to connect client", true, clientConnection(tcpHandler.getPort())) ; shutdownServer(); } /** * Test run with null address set on Epoll native transport * @throws IOException * @throws InterruptedException * @throws ExecutionException */ @Test public void testRunWithNullAddressOnEpoll() throws IOException, InterruptedException, ExecutionException { tcpHandler = new TcpHandler(null, 0); tcpHandler.setChannelInitializer(mockChannelInitializer); //Use Epoll native transport assertEquals("failed to start server", true, startupServer(true)) ; assertEquals("failed to connect client", true, clientConnection(tcpHandler.getPort())) ; shutdownServer(); } /** * Test run with address set * @throws IOException * @throws InterruptedException * @throws ExecutionException */ @Test public void testRunWithAddress() throws IOException, InterruptedException, ExecutionException { tcpHandler = new TcpHandler(serverAddress, 0); tcpHandler.setChannelInitializer(mockChannelInitializer); assertEquals("failed to start server", true, startupServer(false)) ; assertEquals("failed to connect client", true, clientConnection(tcpHandler.getPort())) ; shutdownServer(); } /** * Test run with address set on Epoll native transport * @throws IOException * @throws InterruptedException * @throws ExecutionException */ @Test public void testRunWithAddressOnEpoll() throws IOException, InterruptedException, ExecutionException { tcpHandler = new TcpHandler(serverAddress, 0); tcpHandler.setChannelInitializer(mockChannelInitializer); //Use Epoll native transport assertEquals("failed to start server", true, startupServer(true)); assertEquals("failed to connect client", true, clientConnection(tcpHandler.getPort())); shutdownServer(); } /** * Test run with encryption * @throws InterruptedException * @throws IOException * @throws ExecutionException */ @Test public void testRunWithEncryption() throws InterruptedException, IOException, ExecutionException { int serverPort = 28001; tcpHandler = new TcpHandler(serverAddress, serverPort); tcpHandler.setChannelInitializer(mockChannelInitializer); assertEquals( "failed to start server", true, startupServer(false)); assertEquals( "wrong connection count", 0, tcpHandler.getNumberOfConnections()); assertEquals( "wrong port", serverPort, tcpHandler.getPort()); assertEquals( "wrong address", serverAddress.getHostAddress(), tcpHandler.getAddress()); assertEquals("failed to connect client", true, clientConnection(tcpHandler.getPort())); shutdownServer(); } /** * Test run with encryption on Epoll native transport * @throws InterruptedException * @throws IOException * @throws ExecutionException */ @Test public void testRunWithEncryptionOnEpoll() throws InterruptedException, IOException, ExecutionException { int serverPort = 28001; tcpHandler = new TcpHandler(serverAddress, serverPort); tcpHandler.setChannelInitializer(mockChannelInitializer); //Use Epoll native transport assertEquals( "failed to start server", true, startupServer(true)); assertEquals( "wrong connection count", 0, tcpHandler.getNumberOfConnections()); assertEquals( "wrong port", serverPort, tcpHandler.getPort()); assertEquals( "wrong address", serverAddress.getHostAddress(), tcpHandler.getAddress()); assertEquals("failed to connect client", true, clientConnection(tcpHandler.getPort())); shutdownServer(); } /** * Test run on already used port * @throws IOException */ @Test public void testSocketAlreadyInUse() throws IOException { int serverPort = 28001; Socket firstBinder = new Socket(); boolean exceptionThrown = false; try { firstBinder.bind(new InetSocketAddress(serverAddress, serverPort)); } catch (Exception e) { Assert.fail("Test precondition failed - not able to bind socket to port " + serverPort); } try { tcpHandler = new TcpHandler(serverAddress, serverPort); tcpHandler.setChannelInitializer(mockChannelInitializer); tcpHandler.initiateEventLoopGroups(null, false); tcpHandler.run(); } catch (Exception e) { if (e instanceof BindException) { exceptionThrown = true; } } firstBinder.close(); Assert.assertTrue("Expected BindException has not been thrown", exceptionThrown == true); } /** * Test run on already used port * @throws IOException */ @Test public void testSocketAlreadyInUseOnEpoll() throws IOException { int serverPort = 28001; Socket firstBinder = new Socket(); boolean exceptionThrown = false; try { firstBinder.bind(new InetSocketAddress(serverAddress, serverPort)); } catch (Exception e) { Assert.fail("Test precondition failed - not able to bind socket to port " + serverPort); } try { tcpHandler = new TcpHandler(serverAddress, serverPort); tcpHandler.setChannelInitializer(mockChannelInitializer); //Use Epoll native transport tcpHandler.initiateEventLoopGroups(null, true); tcpHandler.run(); } catch (Exception e) { if (e instanceof BindException || e instanceof Errors.NativeIoException) { exceptionThrown = true; } } firstBinder.close(); Assert.assertTrue("Expected BindException has not been thrown", exceptionThrown == true); } /** * Trigger the server shutdown and wait 2 seconds for completion */ private void shutdownServer() throws InterruptedException, ExecutionException { ListenableFuture<Boolean> shutdownRet = tcpHandler.shutdown() ; while ( shutdownRet.isDone() != true ) Thread.sleep(100) ; assertEquals("shutdown failed", true, shutdownRet.get()); } /** * @throws InterruptedException * @throws IOException * @throws ExecutionException */ private Boolean startupServer(boolean isEpollEnabled) throws InterruptedException, IOException, ExecutionException { ListenableFuture<Boolean> online = tcpHandler.getIsOnlineFuture(); /** * Test EPoll based native transport if isEpollEnabled is true. * Else use Nio based transport. */ tcpHandler.initiateEventLoopGroups(null, isEpollEnabled); (new Thread(tcpHandler)).start(); int retry = 0; while (online.isDone() != true && retry++ < 20) { Thread.sleep(100); } return online.isDone() ; } /** * @throws IOException */ private static Boolean clientConnection(int port) throws IOException { // Connect, and disconnect Socket socket = new Socket(InetAddress.getLoopbackAddress(), port ); Boolean result = socket.isConnected(); socket.close() ; return result ; } }