diff --git a/src/se/vidstige/jadb/HostConnectToRemoteTcpDevice.java b/src/se/vidstige/jadb/HostConnectToRemoteTcpDevice.java index fd740f5..68271d4 100644 --- a/src/se/vidstige/jadb/HostConnectToRemoteTcpDevice.java +++ b/src/se/vidstige/jadb/HostConnectToRemoteTcpDevice.java @@ -4,11 +4,11 @@ import se.vidstige.jadb.entities.TcpAddressEntity; import java.io.IOException; -public class HostConnectToRemoteTcpDevice { +class HostConnectToRemoteTcpDevice { private final Transport transport; private final ResponseValidator responseValidator; - public HostConnectToRemoteTcpDevice(Transport transport) { + HostConnectToRemoteTcpDevice(Transport transport) { this.transport = transport; this.responseValidator = new ResponseValidatorImp(); } @@ -19,7 +19,7 @@ public class HostConnectToRemoteTcpDevice { this.responseValidator = responseValidator; } - public TcpAddressEntity connect(TcpAddressEntity tcpAddressEntity) + TcpAddressEntity connect(TcpAddressEntity tcpAddressEntity) throws IOException, JadbException, ConnectionToRemoteDeviceException { transport.send(String.format("host:connect:%s:%d", tcpAddressEntity.getHost(), tcpAddressEntity.getPort())); verifyTransportLevel(); @@ -47,7 +47,7 @@ public class HostConnectToRemoteTcpDevice { private final static String ALREADY_CONNECTED = "already connected to"; - public ResponseValidatorImp() { + ResponseValidatorImp() { } public void validate(String response) throws ConnectionToRemoteDeviceException { diff --git a/src/se/vidstige/jadb/HostDisconnectFromRemoteTcpDevice.java b/src/se/vidstige/jadb/HostDisconnectFromRemoteTcpDevice.java new file mode 100644 index 0000000..2130e31 --- /dev/null +++ b/src/se/vidstige/jadb/HostDisconnectFromRemoteTcpDevice.java @@ -0,0 +1,76 @@ +package se.vidstige.jadb; + +import se.vidstige.jadb.entities.TcpAddressEntity; + +import java.io.IOException; + +public class HostDisconnectFromRemoteTcpDevice { + private final Transport transport; + private final ResponseValidator responseValidator; + + public HostDisconnectFromRemoteTcpDevice(Transport transport) { + this.transport = transport; + this.responseValidator = new ResponseValidatorImp(); + } + + //Visible for testing + HostDisconnectFromRemoteTcpDevice(Transport transport, ResponseValidator responseValidator) { + this.transport = transport; + this.responseValidator = responseValidator; + } + + public TcpAddressEntity disconnect(TcpAddressEntity tcpAddressEntity) + throws IOException, JadbException, ConnectionToRemoteDeviceException { + transport.send(String.format("host:disconnect:%s:%d", tcpAddressEntity.getHost(), tcpAddressEntity.getPort())); + verifyTransportLevel(); + verifyProtocolLevel(); + + return tcpAddressEntity; + } + + private void verifyTransportLevel() throws IOException, JadbException { + transport.verifyResponse(); + } + + private void verifyProtocolLevel() throws IOException, ConnectionToRemoteDeviceException { + String status = transport.readString(); + responseValidator.validate(status); + } + + //@VisibleForTesting + interface ResponseValidator { + void validate(String response) throws ConnectionToRemoteDeviceException; + } + + final static class ResponseValidatorImp implements ResponseValidator { + private final static String SUCCESSFULLY_DISCONNECTED = "disconnected"; + private final static String ALREADY_DISCONNECTED = "error: no such device"; + + + public ResponseValidatorImp() { + } + + public void validate(String response) throws ConnectionToRemoteDeviceException { + if(!checkIfConnectedSuccessfully(response) && !checkIfAlreadyConnected(response)) { + throw new ConnectionToRemoteDeviceException(extractError(response)); + } + } + + private boolean checkIfConnectedSuccessfully(String response) { + return response.startsWith(SUCCESSFULLY_DISCONNECTED); + } + + private boolean checkIfAlreadyConnected(String response) { + return response.startsWith(ALREADY_DISCONNECTED); + } + + private String extractError(String response) { + int lastColon = response.lastIndexOf(":"); + if(lastColon != -1) { + return response.substring(lastColon, response.length()); + } else { + return response; + } + } + } +} diff --git a/src/se/vidstige/jadb/JadbConnection.java b/src/se/vidstige/jadb/JadbConnection.java index 229058c..7a3126e 100644 --- a/src/se/vidstige/jadb/JadbConnection.java +++ b/src/se/vidstige/jadb/JadbConnection.java @@ -46,11 +46,11 @@ public class JadbConnection implements ITransportFactory { } } - public TcpAddressEntity connectFromTcpDevice(TcpAddressEntity tcpAddressEntity) + public TcpAddressEntity disconnectFromTcpDevice(TcpAddressEntity tcpAddressEntity) throws IOException, JadbException, ConnectionToRemoteDeviceException { Transport transport = createTransport(); try { - return new HostConnectToRemoteTcpDevice(transport).connect(tcpAddressEntity); + return new HostDisconnectFromRemoteTcpDevice(transport).disconnect(tcpAddressEntity); } finally { transport.close(); } diff --git a/test/se/vidstige/jadb/HostConnectToRemoteTcpDeviceTest.java b/test/se/vidstige/jadb/HostConnectToRemoteTcpDeviceTest.java index 9ef25be..896200a 100644 --- a/test/se/vidstige/jadb/HostConnectToRemoteTcpDeviceTest.java +++ b/test/se/vidstige/jadb/HostConnectToRemoteTcpDeviceTest.java @@ -33,9 +33,10 @@ public class HostConnectToRemoteTcpDeviceTest { public void testTransportLevelException() throws ConnectionToRemoteDeviceException, IOException, JadbException { //Prepare Transport transport = mock(Transport.class); - TcpAddressEntity tcpAddressEntity = new TcpAddressEntity("host", 1); doThrow(new JadbException("Fake exception")).when(transport).verifyResponse(); + TcpAddressEntity tcpAddressEntity = new TcpAddressEntity("host", 1); + //Do HostConnectToRemoteTcpDevice hostConnectToRemoteTcpDevice = new HostConnectToRemoteTcpDevice(transport); hostConnectToRemoteTcpDevice.connect(tcpAddressEntity); diff --git a/test/se/vidstige/jadb/HostDisconnectFromRemoteTcpDeviceTest.java b/test/se/vidstige/jadb/HostDisconnectFromRemoteTcpDeviceTest.java new file mode 100644 index 0000000..92b825b --- /dev/null +++ b/test/se/vidstige/jadb/HostDisconnectFromRemoteTcpDeviceTest.java @@ -0,0 +1,74 @@ +package se.vidstige.jadb; + +import org.junit.Test; +import se.vidstige.jadb.entities.TcpAddressEntity; + +import java.io.IOException; + +import static org.junit.Assert.assertEquals; +import static org.mockito.ArgumentMatchers.anyString; +import static org.mockito.Mockito.doThrow; +import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.when; + +public class HostDisconnectFromRemoteTcpDeviceTest { + + @Test + public void testNormalConnection() throws ConnectionToRemoteDeviceException, IOException, JadbException { + //Prepare + Transport transport = mock(Transport.class); + when(transport.readString()).thenReturn("disconnected host:1"); + + TcpAddressEntity tcpAddressEntity = new TcpAddressEntity("host", 1); + + //Do + HostDisconnectFromRemoteTcpDevice hostConnectToRemoteTcpDevice = new HostDisconnectFromRemoteTcpDevice(transport); + TcpAddressEntity resultTcpAddressEntity = hostConnectToRemoteTcpDevice.disconnect(tcpAddressEntity); + + //Validate + assertEquals(resultTcpAddressEntity, tcpAddressEntity); + } + + @Test(expected = JadbException.class) + public void testTransportLevelException() throws ConnectionToRemoteDeviceException, IOException, JadbException { + //Prepare + Transport transport = mock(Transport.class); + doThrow(new JadbException("Fake exception")).when(transport).verifyResponse(); + + TcpAddressEntity tcpAddressEntity = new TcpAddressEntity("host", 1); + + //Do + HostDisconnectFromRemoteTcpDevice hostConnectToRemoteTcpDevice = new HostDisconnectFromRemoteTcpDevice(transport); + hostConnectToRemoteTcpDevice.disconnect(tcpAddressEntity); + } + + @Test(expected = ConnectionToRemoteDeviceException.class) + public void testProtocolException() throws ConnectionToRemoteDeviceException, IOException, JadbException { + //Prepare + Transport transport = mock(Transport.class); + when(transport.readString()).thenReturn("any string"); + HostConnectToRemoteTcpDevice.ResponseValidator responseValidator = mock(HostConnectToRemoteTcpDevice.ResponseValidator.class); + doThrow(new ConnectionToRemoteDeviceException("Fake exception")).when(responseValidator).validate(anyString()); + + TcpAddressEntity tcpAddressEntity = new TcpAddressEntity("host", 1); + + //Do + HostDisconnectFromRemoteTcpDevice hostConnectToRemoteTcpDevice = new HostDisconnectFromRemoteTcpDevice(transport); + hostConnectToRemoteTcpDevice.disconnect(tcpAddressEntity); + } + + @Test + public void testProtocolResponseValidatorSuccessfullyConnected() throws ConnectionToRemoteDeviceException, IOException, JadbException { + new HostDisconnectFromRemoteTcpDevice.ResponseValidatorImp().validate("disconnected 127.0.0.1:10001"); + } + + @Test + public void testProtocolResponseValidatorAlreadyConnected() throws ConnectionToRemoteDeviceException, IOException, JadbException { + new HostDisconnectFromRemoteTcpDevice.ResponseValidatorImp().validate("error: no such device '127.0.0.1:10001'"); + } + + @Test(expected = ConnectionToRemoteDeviceException.class) + public void testProtocolResponseValidatorErrorInValidate() throws ConnectionToRemoteDeviceException, IOException, JadbException { + new HostDisconnectFromRemoteTcpDevice.ResponseValidatorImp().validate("some error occurred"); + } +} \ No newline at end of file diff --git a/test/se/vidstige/jadb/test/integration/RealDeviceTestCases.java b/test/se/vidstige/jadb/test/integration/RealDeviceTestCases.java index 23847fc..ebe0a44 100644 --- a/test/se/vidstige/jadb/test/integration/RealDeviceTestCases.java +++ b/test/se/vidstige/jadb/test/integration/RealDeviceTestCases.java @@ -123,13 +123,39 @@ public class RealDeviceTestCases { } } - + /** + * This test requires emulator running on non-standard tcp port - this may be achieve by executing such command: + * ${ANDROID_HOME}/emulator -verbose -avd ${NAME} -ports 10000,10001 + * + * @throws IOException + * @throws JadbException + * @throws ConnectionToRemoteDeviceException + */ @Test public void testConnectionToTcpDevice() throws IOException, JadbException, ConnectionToRemoteDeviceException { - TcpAddressEntity tcpAddressEntity = jadb.connectToTcpDevice(new TcpAddressEntity("127.0.0.1", 10001)); + jadb.connectToTcpDevice(new TcpAddressEntity("127.0.0.1", 10001)); List devices = jadb.getDevices(); assertNotNull(devices); assertFalse(devices.isEmpty()); } + + /** + * @see #testConnectionToTcpDevice() + * + * @throws IOException + * @throws JadbException + * @throws ConnectionToRemoteDeviceException + */ + @Test + public void testDisconnectionToTcpDevice() throws IOException, JadbException, ConnectionToRemoteDeviceException { + testConnectionToTcpDevice(); + + jadb.disconnectFromTcpDevice(new TcpAddressEntity("127.0.0.1", 10001)); + jadb.getDevices(); + + List devices = jadb.getDevices(); + assertNotNull(devices); + assertTrue(devices.isEmpty()); + } }