1 /* 2 * Copyright 2016 The WebRTC Project Authors. All rights reserved. 3 * 4 * Use of this source code is governed by a BSD-style license 5 * that can be found in the LICENSE file in the root of the source 6 * tree. An additional intellectual property rights grant can be found 7 * in the file PATENTS. All contributing project authors may 8 * be found in the AUTHORS file in the root of the source tree. 9 */ 10 11 package org.appspot.apprtc; 12 13 import static org.junit.Assert.fail; 14 import static org.mockito.Mockito.timeout; 15 import static org.mockito.Mockito.verify; 16 import static org.mockito.Mockito.verifyNoMoreInteractions; 17 18 import org.chromium.testing.local.LocalRobolectricTestRunner; 19 import org.junit.After; 20 import org.junit.Before; 21 import org.junit.Test; 22 import org.junit.runner.RunWith; 23 import org.mockito.Mock; 24 import org.mockito.MockitoAnnotations; 25 import org.robolectric.annotation.Config; 26 import org.robolectric.shadows.ShadowLog; 27 28 import java.util.concurrent.ExecutorService; 29 import java.util.concurrent.Executors; 30 import java.util.concurrent.TimeUnit; 31 32 @RunWith(LocalRobolectricTestRunner.class) 33 @Config(manifest = Config.NONE) 34 public class TCPChannelClientTest { 35 private static final int PORT = 8888; 36 /** 37 * How long we wait before trying to connect to the server. Note: was 38 * previously only 10, which was too short (tests were flaky). 39 */ 40 private static final int SERVER_WAIT = 300; 41 private static final int CONNECT_TIMEOUT = 1000; 42 private static final int SEND_TIMEOUT = 1000; 43 private static final int DISCONNECT_TIMEOUT = 1000; 44 private static final int TERMINATION_TIMEOUT = 1000; 45 private static final String TEST_MESSAGE_SERVER = "Hello, Server!"; 46 private static final String TEST_MESSAGE_CLIENT = "Hello, Client!"; 47 48 @Mock TCPChannelClient.TCPChannelEvents serverEvents; 49 @Mock TCPChannelClient.TCPChannelEvents clientEvents; 50 51 private ExecutorService executor; 52 private TCPChannelClient server; 53 private TCPChannelClient client; 54 55 @Before setUp()56 public void setUp() { 57 ShadowLog.stream = System.out; 58 59 MockitoAnnotations.initMocks(this); 60 61 executor = Executors.newSingleThreadExecutor(); 62 } 63 64 @After tearDown()65 public void tearDown() { 66 verifyNoMoreEvents(); 67 68 executeAndWait(new Runnable() { 69 @Override 70 public void run() { 71 client.disconnect(); 72 server.disconnect(); 73 } 74 }); 75 76 // Stop the executor thread 77 executor.shutdown(); 78 try { 79 executor.awaitTermination(TERMINATION_TIMEOUT, TimeUnit.MILLISECONDS); 80 } catch (InterruptedException e) { 81 fail(e.getMessage()); 82 } 83 } 84 85 @Test testConnectIPv4()86 public void testConnectIPv4() { 87 setUpIPv4Server(); 88 try { 89 Thread.sleep(SERVER_WAIT); 90 } catch (InterruptedException e) { 91 fail(e.getMessage()); 92 } 93 setUpIPv4Client(); 94 95 verify(serverEvents, timeout(CONNECT_TIMEOUT)).onTCPConnected(true); 96 verify(clientEvents, timeout(CONNECT_TIMEOUT)).onTCPConnected(false); 97 } 98 99 @Test testConnectIPv6()100 public void testConnectIPv6() { 101 setUpIPv6Server(); 102 try { 103 Thread.sleep(SERVER_WAIT); 104 } catch (InterruptedException e) { 105 fail(e.getMessage()); 106 } 107 setUpIPv6Client(); 108 109 verify(serverEvents, timeout(CONNECT_TIMEOUT)).onTCPConnected(true); 110 verify(clientEvents, timeout(CONNECT_TIMEOUT)).onTCPConnected(false); 111 } 112 113 @Test testSendData()114 public void testSendData() { 115 testConnectIPv4(); 116 117 executeAndWait(new Runnable() { 118 @Override 119 public void run() { 120 client.send(TEST_MESSAGE_SERVER); 121 server.send(TEST_MESSAGE_CLIENT); 122 } 123 }); 124 125 verify(serverEvents, timeout(SEND_TIMEOUT)).onTCPMessage(TEST_MESSAGE_SERVER); 126 verify(clientEvents, timeout(SEND_TIMEOUT)).onTCPMessage(TEST_MESSAGE_CLIENT); 127 } 128 129 @Test testDisconnectServer()130 public void testDisconnectServer() { 131 testConnectIPv4(); 132 executeAndWait(new Runnable() { 133 @Override 134 public void run() { 135 server.disconnect(); 136 } 137 }); 138 139 verify(serverEvents, timeout(DISCONNECT_TIMEOUT)).onTCPClose(); 140 verify(clientEvents, timeout(DISCONNECT_TIMEOUT)).onTCPClose(); 141 } 142 143 @Test testDisconnectClient()144 public void testDisconnectClient() { 145 testConnectIPv4(); 146 executeAndWait(new Runnable() { 147 @Override 148 public void run() { 149 client.disconnect(); 150 } 151 }); 152 153 verify(serverEvents, timeout(DISCONNECT_TIMEOUT)).onTCPClose(); 154 verify(clientEvents, timeout(DISCONNECT_TIMEOUT)).onTCPClose(); 155 } 156 setUpIPv4Server()157 private void setUpIPv4Server() { 158 setUpServer("0.0.0.0", PORT); 159 } 160 setUpIPv4Client()161 private void setUpIPv4Client() { 162 setUpClient("127.0.0.1", PORT); 163 } 164 setUpIPv6Server()165 private void setUpIPv6Server() { 166 setUpServer("::", PORT); 167 } 168 setUpIPv6Client()169 private void setUpIPv6Client() { 170 setUpClient("::1", PORT); 171 } 172 setUpServer(String ip, int port)173 private void setUpServer(String ip, int port) { 174 server = new TCPChannelClient(executor, serverEvents, ip, port); 175 } 176 setUpClient(String ip, int port)177 private void setUpClient(String ip, int port) { 178 client = new TCPChannelClient(executor, clientEvents, ip, port); 179 } 180 181 /** 182 * Verifies no more server or client events have been issued 183 */ verifyNoMoreEvents()184 private void verifyNoMoreEvents() { 185 verifyNoMoreInteractions(serverEvents); 186 verifyNoMoreInteractions(clientEvents); 187 } 188 189 /** 190 * Queues runnable to be run and waits for it to be executed by the executor thread 191 */ executeAndWait(Runnable runnable)192 public void executeAndWait(Runnable runnable) { 193 try { 194 executor.submit(runnable).get(); 195 } catch (Exception e) { 196 fail(e.getMessage()); 197 } 198 } 199 } 200