summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
Diffstat (limited to 'test/com/isode/stroke/filetransfer/SOCKS5BytestreamClientSessionTest.java')
-rw-r--r--test/com/isode/stroke/filetransfer/SOCKS5BytestreamClientSessionTest.java427
1 files changed, 427 insertions, 0 deletions
diff --git a/test/com/isode/stroke/filetransfer/SOCKS5BytestreamClientSessionTest.java b/test/com/isode/stroke/filetransfer/SOCKS5BytestreamClientSessionTest.java
new file mode 100644
index 0000000..ba696b7
--- /dev/null
+++ b/test/com/isode/stroke/filetransfer/SOCKS5BytestreamClientSessionTest.java
@@ -0,0 +1,427 @@
+/* Copyright (c) 2016, Isode Limited, London, England.
+ * All rights reserved.
+ *
+ * Acquisition and use of this software and related materials for any
+ * purpose requires a written license agreement from Isode Limited,
+ * or a written license from an organisation licensed by Isode Limited
+ * to grant such a license.
+ *
+ */
+package com.isode.stroke.filetransfer;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertTrue;
+import static org.junit.Assert.fail;
+
+import java.io.PrintStream;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.Collection;
+import java.util.List;
+import java.util.Random;
+
+import org.junit.Before;
+import org.junit.Test;
+
+import com.isode.stroke.base.ByteArray;
+import com.isode.stroke.base.SafeByteArray;
+import com.isode.stroke.crypto.CryptoProvider;
+import com.isode.stroke.crypto.JavaCryptoProvider;
+import com.isode.stroke.eventloop.DummyEventLoop;
+import com.isode.stroke.eventloop.Event.Callback;
+import com.isode.stroke.eventloop.EventLoop;
+import com.isode.stroke.eventloop.EventOwner;
+import com.isode.stroke.network.Connection;
+import com.isode.stroke.network.DummyTimerFactory;
+import com.isode.stroke.network.HostAddress;
+import com.isode.stroke.network.HostAddressPort;
+import com.isode.stroke.signals.Signal1;
+import com.isode.stroke.signals.Slot1;
+
+/**
+ * Tests for {@link SOCKS5BytestreamClientSession}
+ */
+public class SOCKS5BytestreamClientSessionTest {
+
+ private static final Random rng = new Random();
+
+ private final HostAddressPort destinationAddressPort = new HostAddressPort(new HostAddress("127.0.0.1"), 8888);
+ private final CryptoProvider crypto = new JavaCryptoProvider();
+ private final String destination = "092a44d859d19c9eed676b551ee80025903351c2";
+ private final DummyEventLoop eventLoop = new DummyEventLoop();
+ private final DummyTimerFactory timerFactory = new DummyTimerFactory();
+ private final List<HostAddressPort> failingPorts = new ArrayList<HostAddressPort>();
+ private final MockeryConnection connection =
+ new MockeryConnection(failingPorts, true, eventLoop);
+
+ @Before
+ public void setUp() {
+ rng.setSeed(System.currentTimeMillis());
+ }
+
+ @Test
+ public void testForSessionReady() {
+ final TestHelper helper = new TestHelper();
+ connection.onDataSent.connect(new Slot1<SafeByteArray>() {
+
+ @Override
+ public void call(SafeByteArray data) {
+ helper.handleConnectionDataWritten(data);
+ }
+
+ });
+
+ SOCKS5BytestreamClientSession clientSession = new SOCKS5BytestreamClientSession(connection, destinationAddressPort, destination, timerFactory);
+ clientSession.onSessionReady.connect(new Slot1<Boolean>() {
+
+ @Override
+ public void call(Boolean hasError) {
+ helper.handleSessionRead(hasError.booleanValue());
+ }
+
+ });
+
+ clientSession.start();
+ eventLoop.processEvents();
+ assertEquals(new ByteArray(new byte[] {0x05,0x01,0x00}),helper.unprocessedInput);
+
+ helper.unprocessedInput.clear();
+ serverRespondHelloOK();
+ eventLoop.processEvents();
+ ByteArray expected = new ByteArray(new byte[] {0x05,0x01,0x00,0x03});
+ expected.append((byte)destination.length());
+ expected.append(destination);
+ expected.append((byte)0x00);
+ ByteArray results = getSubArray(helper.unprocessedInput, expected.getSize());
+ assertEquals(expected,results);
+
+ helper.unprocessedInput.clear();
+ serverRespondRequestOK();
+ eventLoop.processEvents();
+ assertTrue(helper.sessionReadyCalled);
+ assertFalse(helper.sessionReadyError);
+ }
+
+ @Test
+ public void testErrorHandlingHello() {
+ final TestHelper helper = new TestHelper();
+ connection.onDataSent.connect(new Slot1<SafeByteArray>() {
+
+ @Override
+ public void call(SafeByteArray data) {
+ helper.handleConnectionDataWritten(data);
+ }
+
+ });
+
+ SOCKS5BytestreamClientSession clientSession = new SOCKS5BytestreamClientSession(connection, destinationAddressPort, destination, timerFactory);
+ clientSession.onSessionReady.connect(new Slot1<Boolean>() {
+
+ @Override
+ public void call(Boolean hasError) {
+ helper.handleSessionRead(hasError.booleanValue());
+ }
+
+ });
+
+ clientSession.start();
+ eventLoop.processEvents();
+ assertEquals(new ByteArray(new byte[] {0x05,0x01,0x00}),helper.unprocessedInput);
+
+ helper.unprocessedInput.clear();
+ serverRespondHelloAuthFail();
+ eventLoop.processEvents();
+
+ assertTrue(helper.sessionReadyCalled);
+ assertTrue(helper.sessionReadyError);
+ assertTrue(connection.disconnectCalled);
+ }
+
+ @Test
+ public void testErrorHandlingRequest() {
+ final TestHelper helper = new TestHelper();
+ connection.onDataSent.connect(new Slot1<SafeByteArray>() {
+
+ @Override
+ public void call(SafeByteArray data) {
+ helper.handleConnectionDataWritten(data);
+ }
+
+ });
+
+ SOCKS5BytestreamClientSession clientSession = new SOCKS5BytestreamClientSession(connection, destinationAddressPort, destination, timerFactory);
+ clientSession.onSessionReady.connect(new Slot1<Boolean>() {
+
+ @Override
+ public void call(Boolean hasError) {
+ helper.handleSessionRead(hasError.booleanValue());
+ }
+
+ });
+
+ clientSession.start();
+ eventLoop.processEvents();
+ assertEquals(new ByteArray(new byte[] {0x05,0x01,0x00}),helper.unprocessedInput);
+
+ helper.unprocessedInput.clear();
+ serverRespondHelloOK();
+ eventLoop.processEvents();
+ ByteArray expected = new ByteArray(new byte[] {0x05,0x01,0x00,0x03});
+ expected.append((byte)destination.length());
+ expected.append(destination);
+ expected.append((byte)0x00);
+ ByteArray results = getSubArray(helper.unprocessedInput, expected.getSize());
+ assertEquals(expected,results);
+
+ helper.unprocessedInput.clear();
+ serverRespondRequestFail();
+ eventLoop.processEvents();
+ assertTrue(helper.sessionReadyCalled);
+ assertTrue(helper.sessionReadyError);
+ assertTrue(connection.disconnectCalled);
+ }
+
+ @Test
+ public void testWriteBytestream() {
+ final TestHelper helper = new TestHelper();
+ connection.onDataSent.connect(new Slot1<SafeByteArray>() {
+
+ @Override
+ public void call(SafeByteArray data) {
+ helper.handleConnectionDataWritten(data);
+ }
+
+ });
+
+ SOCKS5BytestreamClientSession clientSession = new SOCKS5BytestreamClientSession(connection, destinationAddressPort, destination, timerFactory);
+ clientSession.onSessionReady.connect(new Slot1<Boolean>() {
+
+ @Override
+ public void call(Boolean hasError) {
+ helper.handleSessionRead(hasError.booleanValue());
+ }
+
+ });
+
+ clientSession.start();
+ eventLoop.processEvents();
+
+ helper.unprocessedInput.clear();
+ serverRespondHelloOK();
+ eventLoop.processEvents();
+
+ helper.unprocessedInput.clear();
+ serverRespondRequestOK();
+ eventLoop.processEvents();
+ assertTrue(helper.sessionReadyCalled);
+ assertFalse(helper.sessionReadyError);
+
+ ByteArrayWriteBytestream output = new ByteArrayWriteBytestream();
+ clientSession.startReceiving(output);
+
+ ByteArray transferData = generateRandomByteArray(1024);
+ connection.onDataRead.emit(new SafeByteArray(transferData));
+ assertEquals(transferData,output.getData());
+ }
+
+ @Test
+ public void testReadBytestream() {
+ final TestHelper helper = new TestHelper();
+ connection.onDataSent.connect(new Slot1<SafeByteArray>() {
+
+ @Override
+ public void call(SafeByteArray data) {
+ helper.handleConnectionDataWritten(data);
+ }
+
+ });
+
+ SOCKS5BytestreamClientSession clientSession = new SOCKS5BytestreamClientSession(connection, destinationAddressPort, destination, timerFactory);
+ clientSession.onSessionReady.connect(new Slot1<Boolean>() {
+
+ @Override
+ public void call(Boolean hasError) {
+ helper.handleSessionRead(hasError.booleanValue());
+ }
+
+ });
+
+ clientSession.start();
+ eventLoop.processEvents();
+
+ helper.unprocessedInput.clear();
+ serverRespondHelloOK();
+ eventLoop.processEvents();
+
+ helper.unprocessedInput.clear();
+ serverRespondRequestOK();
+ eventLoop.processEvents();
+ assertTrue(helper.sessionReadyCalled);
+ assertFalse(helper.sessionReadyError);
+
+ helper.unprocessedInput.clear();
+ ByteArray transferData = generateRandomByteArray(1024);
+ ByteArrayReadBytestream input = new ByteArrayReadBytestream(transferData);
+ clientSession.startSending(input);
+ eventLoop.processEvents();
+
+ assertEquals(transferData,helper.unprocessedInput);
+ }
+
+ private static ByteArray generateRandomByteArray(int len) {
+ byte[] randomBytes = new byte[len];
+ rng.nextBytes(randomBytes);
+ return new ByteArray(randomBytes);
+ }
+
+ private void serverRespondHelloOK() {
+ connection.onDataRead.emit(new SafeByteArray(new byte[] {0x05,0x00}));
+ }
+
+ private void serverRespondHelloAuthFail() {
+ connection.onDataRead.emit(new SafeByteArray(new byte[] {0x05,(byte) 0xFF}));
+ }
+
+ private void serverRespondRequestOK() {
+ SafeByteArray dataToSend = new SafeByteArray(new byte[] {0x05,0x00,0x00,0x03});
+ dataToSend.append((byte)destination.length());
+ dataToSend.append(destination);
+ dataToSend.append((byte)0x00);
+ connection.onDataRead.emit(dataToSend);
+ }
+
+ private void serverRespondRequestFail() {
+ SafeByteArray correctData = new SafeByteArray(new byte[] {0x05,0x00,0x00,0x03});
+ correctData.append((byte)destination.length());
+ correctData.append(destination);
+ correctData.append((byte)0x00);
+ SafeByteArray dataToSend;
+ do {
+ ByteArray rndArray = generateRandomByteArray(correctData.getSize());
+ dataToSend = new SafeByteArray(rndArray);
+ } while (dataToSend.equals(correctData));
+ connection.onDataRead.emit(dataToSend);
+ }
+
+ /**
+ * Gets the sub {@link ByteArray} consisting of the first n bytes of
+ * a given {@link ByteArray}
+ * @param array A {@link ByteArray} should not be {@code null} and should
+ * be at least n characters long.
+ * @param n the number of bytes of the {@link ByteArray} to return as a new
+ * {@link ByteArray}
+ * @return The first n characters of the given {@link ByteArray} as a new
+ * {@link ByteArray}. Will not be {@code null}
+ */
+ private ByteArray getSubArray(ByteArray array,int n) {
+ byte[] arrayData = array.getData();
+ byte[] newArrayData = Arrays.copyOfRange(arrayData, 0, n);
+ return new ByteArray(newArrayData);
+ }
+
+ private static final class TestHelper {
+
+ private ByteArray unprocessedInput = new ByteArray();
+ private boolean sessionReadyCalled = false;
+ private boolean sessionReadyError = false;
+
+ public TestHelper() {
+ // Empty Constructor
+ }
+
+ public void handleConnectionDataWritten(SafeByteArray data) {
+ unprocessedInput.append(data);
+ }
+
+ public void handleSessionRead(boolean error) {
+ sessionReadyCalled = true;
+ sessionReadyError = error;
+ }
+
+ }
+
+
+ private static final class MockeryConnection extends Connection implements EventOwner {
+
+ private EventLoop eventLoop;
+ private HostAddressPort hostAddressPort;
+ private final List<HostAddressPort> failingPorts;
+ private boolean isResponsive;
+ private boolean disconnectCalled;
+
+ private final Signal1<SafeByteArray> onDataSent = new Signal1<SafeByteArray>();
+
+ public MockeryConnection(Collection<HostAddressPort> failingPorts,
+ boolean isResponsive,EventLoop eventLoop) {
+ this.eventLoop = eventLoop;
+ this.failingPorts = new ArrayList<HostAddressPort>(failingPorts);
+ this.isResponsive = isResponsive;
+ this.disconnectCalled = false;
+ }
+
+ @Override
+ public void listen() {
+ fail();
+ }
+
+ /* (non-Javadoc)
+ * @see com.isode.stroke.network.Connection#connect(com.isode.stroke.network.HostAddressPort)
+ */
+ @Override
+ public void connect(HostAddressPort address) {
+ hostAddressPort = address;
+ if (isResponsive) {
+ final boolean fail = failingPorts.contains(address);
+ eventLoop.postEvent(new Callback() {
+
+ @Override
+ public void run() {
+ onConnectFinished.emit(fail);
+ }
+
+ });
+ }
+ }
+
+ /* (non-Javadoc)
+ * @see com.isode.stroke.network.Connection#disconnect()
+ */
+ @Override
+ public void disconnect() {
+ disconnectCalled = true;
+ }
+
+ /* (non-Javadoc)
+ * @see com.isode.stroke.network.Connection#write(com.isode.stroke.base.SafeByteArray)
+ */
+ @Override
+ public void write(SafeByteArray data) {
+ eventLoop.postEvent(new Callback() {
+
+ @Override
+ public void run() {
+ onDataWritten.emit();
+ }
+
+ });
+ onDataSent.emit(data);
+ }
+
+
+
+ /* (non-Javadoc)
+ * @see com.isode.stroke.network.Connection#getLocalAddress()
+ */
+ @Override
+ public HostAddressPort getLocalAddress() {
+ return new HostAddressPort();
+ }
+
+ public HostAddressPort getRemoteAddress() {
+ return new HostAddressPort();
+ }
+
+ }
+
+}