1 // Copyright 2014 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
5 package org.chromium.components.devtools_bridge;
7 import android.net.LocalServerSocket;
8 import android.net.LocalSocket;
9 import android.test.InstrumentationTestCase;
10 import android.test.suitebuilder.annotation.MediumTest;
11 import android.test.suitebuilder.annotation.SmallTest;
13 import junit.framework.Assert;
15 import java.io.IOException;
16 import java.io.OutputStream;
17 import java.nio.ByteBuffer;
20 * Tests for {@link SocketTunnelServer}
22 public class SocketTunnelServerTest extends InstrumentationTestCase {
23 private static final int CONNECTION_ID = 30;
24 private static final String SOCKET_NAME = "ksdjhflksjhdflk";
26 private DataChannelMock mDataChannelMock;
27 private SocketTunnelServer mServer;
28 private LocalServerSocket mSocket;
31 public void setUp() throws Exception {
33 mSocket = new LocalServerSocket(SOCKET_NAME);
37 public void tearDown() throws Exception {
39 if (mServer != null) destroyServer();
43 private void createServer() {
44 createServer(new DataChannelMock());
47 private void createServer(DataChannelMock dataChannel) {
48 mDataChannelMock = dataChannel;
49 mServer = new SocketTunnelServer(SOCKET_NAME);
50 mServer.bind(mDataChannelMock);
53 private void destroyServer() {
54 mServer.unbind().dispose();
59 public void testOpenDataChannel() {
61 mDataChannelMock.open();
65 public void testDecodeControlPacket() {
67 ByteBuffer packet = buildControlPacket(CONNECTION_ID, SocketTunnelBase.SERVER_OPEN_ACK);
69 PacketDecoder decoder = PacketDecoder.decode(packet);
70 Assert.assertTrue(decoder.isControlPacket());
71 Assert.assertEquals(CONNECTION_ID, decoder.connectionId());
72 Assert.assertEquals(SocketTunnelBase.SERVER_OPEN_ACK, decoder.opCode());
76 public void testConnectToSocket() throws IOException {
78 LocalSocket socket = connectToSocket(1);
79 Assert.assertTrue(mServer.hasConnections());
83 private LocalSocket connectToSocket(int connectionId) throws IOException {
84 mDataChannelMock.notifyMessage(
85 buildControlPacket(connectionId, SocketTunnelBase.CLIENT_OPEN));
86 return mSocket.accept();
89 private void sendClose(int connectionId) {
90 mDataChannelMock.notifyMessage(
91 buildControlPacket(connectionId, SocketTunnelBase.CLIENT_CLOSE));
94 private ByteBuffer buildControlPacket(int connectionId, byte opCode) {
95 ByteBuffer packet = SocketTunnelBase.buildControlPacket(connectionId, opCode);
96 packet.limit(packet.position());
98 Assert.assertTrue(packet.remaining() > 0);
102 private ByteBuffer buildDataPacket(int connectionId, byte[] data) {
103 ByteBuffer packet = SocketTunnelBase.buildDataPacket(connectionId, data, data.length);
104 packet.limit(packet.position());
106 Assert.assertTrue(packet.remaining() > 0);
111 public void testReceiveOpenAcknowledgement() throws IOException, InterruptedException {
113 LocalSocket socket = connectToSocket(CONNECTION_ID);
115 receiveOpenAck(CONNECTION_ID);
120 private PacketDecoder receiveControlPacket(int connectionId) throws InterruptedException {
121 PacketDecoder decoder = PacketDecoder.decode(mDataChannelMock.receive());
122 Assert.assertTrue(decoder.isControlPacket());
123 Assert.assertEquals(connectionId, decoder.connectionId());
127 private void receiveOpenAck(int connectionId) throws InterruptedException {
128 PacketDecoder decoder = receiveControlPacket(connectionId);
129 Assert.assertEquals(SocketTunnelBase.SERVER_OPEN_ACK, decoder.opCode());
132 private void receiveClose(int connectionId) throws InterruptedException {
133 PacketDecoder decoder = receiveControlPacket(connectionId);
134 Assert.assertEquals(SocketTunnelBase.SERVER_CLOSE, decoder.opCode());
138 public void testClosingSocket() throws IOException, InterruptedException {
140 LocalSocket socket = connectToSocket(CONNECTION_ID);
141 receiveOpenAck(CONNECTION_ID);
143 socket.shutdownOutput();
145 PacketDecoder decoder = PacketDecoder.decode(mDataChannelMock.receive());
147 Assert.assertTrue(decoder.isControlPacket());
148 Assert.assertEquals(SocketTunnelBase.SERVER_CLOSE, decoder.opCode());
149 Assert.assertEquals(CONNECTION_ID, decoder.connectionId());
155 public void testReadData() throws IOException, InterruptedException {
157 LocalSocket socket = connectToSocket(CONNECTION_ID);
158 receiveOpenAck(CONNECTION_ID);
160 byte[] sample = "Sample".getBytes();
162 socket.getOutputStream().write(sample);
163 socket.getOutputStream().flush();
164 socket.shutdownOutput();
166 ByteBuffer result = receiveData(CONNECTION_ID, sample.length);
167 Assert.assertEquals(ByteBuffer.wrap(sample), result);
170 private ByteBuffer receiveData(int connectionId, int length) throws InterruptedException {
171 ByteBuffer result = ByteBuffer.allocate(length);
174 PacketDecoder decoder = PacketDecoder.decode(mDataChannelMock.receive());
175 if (decoder.isDataPacket()) {
176 Assert.assertEquals(connectionId, decoder.connectionId());
177 result.put(decoder.data());
178 } else if (decoder.isControlPacket()) {
179 Assert.assertEquals(SocketTunnelBase.SERVER_CLOSE, decoder.opCode());
180 Assert.assertEquals(connectionId, decoder.connectionId());
184 result.limit(result.position());
189 private int sum(int[] values) {
196 private static final int[] CHUNK_SIZES =
197 new int[] { 0, 1, 5, 100, 1000, SocketTunnelBase.READING_BUFFER_SIZE * 2 };
200 public void testReadLongDataChunk() throws IOException, InterruptedException {
202 LocalSocket socket = connectToSocket(CONNECTION_ID);
203 receiveOpenAck(CONNECTION_ID);
205 byte[] buffer = new byte[CHUNK_SIZES[CHUNK_SIZES.length - 1]];
206 ByteBuffer sentData = ByteBuffer.allocate(sum(CHUNK_SIZES));
207 OutputStream stream = socket.getOutputStream();
210 for (int size : CHUNK_SIZES) {
211 while (prevSize < size)
212 buffer[prevSize++] = next++;
214 stream.write(buffer, 0, size);
215 sentData.put(buffer, 0, size);
218 socket.shutdownOutput();
220 sentData.limit(sentData.position());
221 sentData.position(0);
222 ByteBuffer readData = receiveData(CONNECTION_ID, sentData.limit());
224 Assert.assertEquals(sentData, readData);
228 public void testReuseConnectionId() throws IOException, InterruptedException {
230 LocalSocket socket = connectToSocket(CONNECTION_ID);
231 receiveOpenAck(CONNECTION_ID);
233 socket.shutdownOutput();
235 receiveClose(CONNECTION_ID);
236 sendClose(CONNECTION_ID);
238 // Open connection with the same ID
239 socket = connectToSocket(CONNECTION_ID);
240 receiveOpenAck(CONNECTION_ID);
243 private static final byte[] SAMPLE = "Sample".getBytes();
246 public void testWriteData() throws IOException, InterruptedException {
248 LocalSocket socket = connectToSocket(CONNECTION_ID);
249 receiveOpenAck(CONNECTION_ID);
251 mDataChannelMock.notifyMessage(buildDataPacket(CONNECTION_ID, SAMPLE));
253 byte[] result = new byte[SAMPLE.length];
255 while (read < SAMPLE.length) {
256 int count = socket.getInputStream().read(result, 0, SAMPLE.length - read);
257 Assert.assertTrue(count > 0);
261 Assert.assertEquals(ByteBuffer.wrap(SAMPLE), ByteBuffer.wrap(result));
266 private enum TestStates {
267 INITIAL, SENDING, CLOSING, MAY_FINISH_SENDING, SENT, DONE
271 public void testStopWhileSendingData() throws IOException {
273 final TestUtils.StateBarrier<TestStates> barrier =
274 new TestUtils.StateBarrier<TestStates>(TestStates.INITIAL);
276 createServer(new DataChannelMock() {
278 public void send(ByteBuffer message, AbstractDataChannel.MessageType type) {
279 barrier.advance(TestStates.INITIAL, TestStates.SENDING);
280 barrier.advance(TestStates.MAY_FINISH_SENDING, TestStates.SENT);
284 LocalSocket socket = connectToSocket(CONNECTION_ID);
285 barrier.advance(TestStates.SENDING, TestStates.CLOSING);
293 } catch (InterruptedException e) {
294 throw new RuntimeException(e);
297 barrier.advance(TestStates.CLOSING, TestStates.MAY_FINISH_SENDING);
303 barrier.advance(TestStates.SENT, TestStates.DONE);