From 9efd3942ab21ea30cec5193de2c62ff350bcb540 Mon Sep 17 00:00:00 2001 From: Mykola Mokhnach Date: Mon, 2 Apr 2018 19:05:51 +0200 Subject: [PATCH 1/8] Add wrappers for Android logcat broadcaster --- build.gradle | 1 + .../java_client/android/AndroidDriver.java | 2 +- .../android/ListensToLogcatMessages.java | 71 +++++++++++++ .../service/local/AppiumServiceBuilder.java | 2 +- .../java_client/ws/CanHandleMessages.java | 49 +++++++++ .../java_client/ws/MessagesHandler.java | 28 +++++ .../java_client/ws/StringMessagesHandler.java | 15 +++ .../java_client/ws/StringWebSocketClient.java | 100 ++++++++++++++++++ .../java_client/ws/WebSocketClient.java | 37 +++++++ .../android/AndroidLogcatListenerTest.java | 59 +++++++++++ 10 files changed, 362 insertions(+), 2 deletions(-) create mode 100644 src/main/java/io/appium/java_client/android/ListensToLogcatMessages.java create mode 100644 src/main/java/io/appium/java_client/ws/CanHandleMessages.java create mode 100644 src/main/java/io/appium/java_client/ws/MessagesHandler.java create mode 100644 src/main/java/io/appium/java_client/ws/StringMessagesHandler.java create mode 100644 src/main/java/io/appium/java_client/ws/StringWebSocketClient.java create mode 100644 src/main/java/io/appium/java_client/ws/WebSocketClient.java create mode 100644 src/test/java/io/appium/java_client/android/AndroidLogcatListenerTest.java diff --git a/build.gradle b/build.gradle index b0e0637b2..49e364c52 100644 --- a/build.gradle +++ b/build.gradle @@ -68,6 +68,7 @@ dependencies { force = true } compile 'com.google.code.gson:gson:2.8.2' + compile 'javax.websocket:javax.websocket-api:1.1' compile 'org.apache.httpcomponents:httpclient:4.5.5' compile 'cglib:cglib:3.2.6' compile 'commons-validator:commons-validator:1.6' diff --git a/src/main/java/io/appium/java_client/android/AndroidDriver.java b/src/main/java/io/appium/java_client/android/AndroidDriver.java index 3af82826b..d3b37f19f 100644 --- a/src/main/java/io/appium/java_client/android/AndroidDriver.java +++ b/src/main/java/io/appium/java_client/android/AndroidDriver.java @@ -53,7 +53,7 @@ public class AndroidDriver FindsByAndroidUIAutomator, LocksDevice, HasAndroidSettings, HasDeviceDetails, HasSupportedPerformanceDataType, AuthenticatesByFinger, CanRecordScreen, SupportsSpecialEmulatorCommands, - SupportsNetworkStateManagement { + SupportsNetworkStateManagement, ListensToLogcatMessages { private static final String ANDROID_PLATFORM = MobilePlatform.ANDROID; diff --git a/src/main/java/io/appium/java_client/android/ListensToLogcatMessages.java b/src/main/java/io/appium/java_client/android/ListensToLogcatMessages.java new file mode 100644 index 000000000..1027a05f2 --- /dev/null +++ b/src/main/java/io/appium/java_client/android/ListensToLogcatMessages.java @@ -0,0 +1,71 @@ +package io.appium.java_client.android; + +import static io.appium.java_client.service.local.AppiumServiceBuilder.DEFAULT_APPIUM_PORT; +import static org.openqa.selenium.remote.DriverCommand.EXECUTE_SCRIPT; + +import com.google.common.collect.ImmutableMap; + +import io.appium.java_client.ExecutesMethod; +import io.appium.java_client.ws.StringMessagesHandler; +import io.appium.java_client.ws.StringWebSocketClient; +import org.openqa.selenium.remote.RemoteWebDriver; + +import java.net.URI; +import java.net.URISyntaxException; + +public interface ListensToLogcatMessages extends ExecutesMethod { + StringWebSocketClient logcatClient = new StringWebSocketClient(); + + /** + * Start logcat messages broadcast via web socket. + * This method assumes that Appium server is running on localhost and + * is assigned to the default port (4723). + */ + default void startLogcatBroadcast() { + startLogcatBroadcast("localhost", DEFAULT_APPIUM_PORT); + } + + /** + * Start logcat messages broadcast via web socket. + * + * @param host the name of the host where Appium server is running + * @param port the port of the host where Appium server is running + */ + default void startLogcatBroadcast(String host, int port) { + execute(EXECUTE_SCRIPT, ImmutableMap.of("script", "mobile: startLogsBroadcast")); + final URI endpointUri; + try { + endpointUri = new URI(String.format("ws://%s:%s/ws/session/%s/appium/device/logcat", + host, port, ((RemoteWebDriver) this).getSessionId())); + } catch (URISyntaxException e) { + throw new IllegalArgumentException(e); + } + logcatClient.connect(endpointUri); + } + + /** + * Adds a new log broadcasting handler. + * Several handlers might be assigned to a single server. + * Multiple calls to this method will cause the handler + * to be called multiple times. + * + * @param handler an instance of a class, which implement string message handlers + */ + default void addLogcatListener(StringMessagesHandler handler) { + logcatClient.addMessageHandler(handler); + } + + /** + * Removes all existing logcat message handlers. + */ + default void removeAllLogcatListeners() { + logcatClient.removeAllMessageHandlers(); + } + + /** + * Stops logcat messages broadcast via web socket. + */ + default void stopLogcatBroadcast() { + execute(EXECUTE_SCRIPT, ImmutableMap.of("script", "mobile: stopLogsBroadcast")); + } +} diff --git a/src/main/java/io/appium/java_client/service/local/AppiumServiceBuilder.java b/src/main/java/io/appium/java_client/service/local/AppiumServiceBuilder.java index 08522521c..c8b44414e 100644 --- a/src/main/java/io/appium/java_client/service/local/AppiumServiceBuilder.java +++ b/src/main/java/io/appium/java_client/service/local/AppiumServiceBuilder.java @@ -75,7 +75,7 @@ public final class AppiumServiceBuilder File.separator + BUILD_FOLDER + File.separator + LIB_FOLDER + File.separator + MAIN_JS; - private static final int DEFAULT_APPIUM_PORT = 4723; + public static final int DEFAULT_APPIUM_PORT = 4723; private static final String BASH = "bash"; private static final String CMD_EXE = "cmd.exe"; private static final String NODE = "node"; diff --git a/src/main/java/io/appium/java_client/ws/CanHandleMessages.java b/src/main/java/io/appium/java_client/ws/CanHandleMessages.java new file mode 100644 index 000000000..209a79acd --- /dev/null +++ b/src/main/java/io/appium/java_client/ws/CanHandleMessages.java @@ -0,0 +1,49 @@ +package io.appium.java_client.ws; + +import java.util.List; + +/** + * This interface might be assigned to classes, which + * are defined as web socket clients. + */ +public interface CanHandleMessages { + /** + * @return The list of web socket message handlers. + */ + List messageHandlers(); + + /** + * Register a new message handler. + * + * @param msgHandler an instance of a class, which + * implements MessagesHandler interface + */ + default void addMessageHandler(T msgHandler) { + messageHandlers().add(msgHandler); + } + + /** + * Removes an existing message handler. + * + * @param msgHandler an instance of a class, which + * implements MessagesHandler interface + * @return true if the given class instance was registered before and has been successfully removed. + */ + default boolean removeMessageHandler(T msgHandler) { + return messageHandlers().remove(msgHandler); + } + + /** + * @return The count of registered message handlers. + */ + default int messageHandlersCount() { + return messageHandlers().size(); + } + + /** + * Removes all registered message handlers. + */ + default void removeAllMessageHandlers() { + messageHandlers().clear(); + } +} diff --git a/src/main/java/io/appium/java_client/ws/MessagesHandler.java b/src/main/java/io/appium/java_client/ws/MessagesHandler.java new file mode 100644 index 000000000..02db8f314 --- /dev/null +++ b/src/main/java/io/appium/java_client/ws/MessagesHandler.java @@ -0,0 +1,28 @@ +package io.appium.java_client.ws; + +/** + * This is the basic interface for all web socket message handlers. + */ +public interface MessagesHandler { + /** + * This event is fired when the client is + * successfully connected to a web socket. + */ + void onConnected(); + + /** + * This event is fired when the client is + * disconnected from a web socket. + */ + void onDisconnected(); + + /** + * This event is fired when there is an error + * in the web socket connection. + * onDisconnected event is always generated after + * onError happens. + * + * @param reason the actual error reason. + */ + void onError(Throwable reason); +} diff --git a/src/main/java/io/appium/java_client/ws/StringMessagesHandler.java b/src/main/java/io/appium/java_client/ws/StringMessagesHandler.java new file mode 100644 index 000000000..211c24e57 --- /dev/null +++ b/src/main/java/io/appium/java_client/ws/StringMessagesHandler.java @@ -0,0 +1,15 @@ +package io.appium.java_client.ws; + +/** + * All classes, that handle web socket messages of String type + * must implement this interface. + */ +public interface StringMessagesHandler extends MessagesHandler { + /** + * This event is fired when the client receives + * a new string message from a web socket. + * + * @param message the actual message content + */ + void onMessage(String message); +} diff --git a/src/main/java/io/appium/java_client/ws/StringWebSocketClient.java b/src/main/java/io/appium/java_client/ws/StringWebSocketClient.java new file mode 100644 index 000000000..1360b5c77 --- /dev/null +++ b/src/main/java/io/appium/java_client/ws/StringWebSocketClient.java @@ -0,0 +1,100 @@ +package io.appium.java_client.ws; + +import java.io.IOException; +import java.net.URI; +import java.util.List; +import java.util.concurrent.CopyOnWriteArrayList; +import javax.websocket.ClientEndpoint; +import javax.websocket.CloseReason; +import javax.websocket.EndpointConfig; +import javax.websocket.OnClose; +import javax.websocket.OnError; +import javax.websocket.OnMessage; +import javax.websocket.OnOpen; +import javax.websocket.Session; + +@ClientEndpoint +public class StringWebSocketClient extends WebSocketClient + implements CanHandleMessages { + private final List messageHandlers = new CopyOnWriteArrayList<>(); + private volatile Session session; + + @Override + public void connect(URI endpoint) { + if (session != null) { + if (endpoint.equals(this.getEndpoint())) { + return; + } + removeAllMessageHandlers(); + try { + session.close(); + } catch (IOException e) { + // ignore + } + session = null; + } + super.connect(endpoint); + } + + /** + * This event if fired when the client is successfully + * connected to a web socket. + * + * @param session the actual web socket session instance + * @param config endpoint config + */ + @OnOpen + public void onOpen(Session session, EndpointConfig config) { + this.session = session; + messageHandlers().forEach(MessagesHandler::onConnected); + } + + /** + * This event if fired when the client is + * disconnected from a web socket. + * + * @param session the actual web socket session instance + * @param reason connection close reason + */ + @OnClose + public void onClose(Session session, CloseReason reason) { + this.session = null; + messageHandlers().forEach(MessagesHandler::onDisconnected); + } + + /** + * This event if fired when there is an unexpected + * error in web socket connection. + * + * @param session the actual web socket session instance + * @param reason the actual error reason + */ + @OnError + public void onError(Session session, Throwable reason) { + this.session = null; + messageHandlers().forEach(x -> { + x.onError(reason); + x.onDisconnected(); + }); + throw new RuntimeException(reason); + } + + /** + * This event if fired when there is a + * new message from the web socket. + * + * @param message the actual message content. + */ + @OnMessage + public void onMessage(String message) { + messageHandlers().forEach(x -> x.onMessage(message)); + } + + /** + * @return The list of all registered web socket messages handlers. + */ + @Override + public List messageHandlers() { + return messageHandlers; + } +} diff --git a/src/main/java/io/appium/java_client/ws/WebSocketClient.java b/src/main/java/io/appium/java_client/ws/WebSocketClient.java new file mode 100644 index 000000000..a61c102c8 --- /dev/null +++ b/src/main/java/io/appium/java_client/ws/WebSocketClient.java @@ -0,0 +1,37 @@ +package io.appium.java_client.ws; + +import org.openqa.selenium.WebDriverException; + +import java.io.IOException; +import java.net.URI; +import javax.websocket.ContainerProvider; +import javax.websocket.DeploymentException; + +public abstract class WebSocketClient { + private URI endpoint; + + private void setEndpoint(URI endpoint) { + this.endpoint = endpoint; + } + + public URI getEndpoint() { + return this.endpoint; + } + + /** + * Connects web socket client. + * + * @param endpoint The full address of an endpoint to connect to. + * Usually starts with 'ws://'. + */ + public void connect(URI endpoint) { + try { + ContainerProvider + .getWebSocketContainer() + .connectToServer(this, endpoint); + setEndpoint(endpoint); + } catch (IOException | DeploymentException e) { + throw new WebDriverException(e); + } + } +} diff --git a/src/test/java/io/appium/java_client/android/AndroidLogcatListenerTest.java b/src/test/java/io/appium/java_client/android/AndroidLogcatListenerTest.java new file mode 100644 index 000000000..8b8af281f --- /dev/null +++ b/src/test/java/io/appium/java_client/android/AndroidLogcatListenerTest.java @@ -0,0 +1,59 @@ +package io.appium.java_client.android; + +import static org.junit.Assert.assertTrue; + +import io.appium.java_client.ws.StringMessagesHandler; +import org.junit.Test; + +import java.time.Duration; +import java.util.concurrent.Semaphore; +import java.util.concurrent.TimeUnit; + +public class AndroidLogcatListenerTest extends BaseAndroidTest { + + @Test + public void verifyLogcatListenerCanBeAssigned() { + final Semaphore messageSemaphore = new Semaphore(1); + final Semaphore connectedSemaphore = new Semaphore(1); + final Duration timeout = Duration.ofSeconds(5); + + try { + driver.startLogcatBroadcast(); + driver.addLogcatListener(new StringMessagesHandler() { + @Override + public void onMessage(String message) { + messageSemaphore.release(); + } + + @Override + public void onConnected() { + connectedSemaphore.release(); + } + + @Override + public void onDisconnected() { + // ignore + } + + @Override + public void onError(Throwable reason) { + // ignore + } + }); + + connectedSemaphore.acquire(); + messageSemaphore.acquire(); + + assertTrue(String.format("Didn't connect to the web socket after %s timeout", timeout), + connectedSemaphore.tryAcquire(timeout.toMillis(), TimeUnit.MILLISECONDS)); + assertTrue(String.format("Didn't receive any log message after %s timeout", timeout), + messageSemaphore.tryAcquire(timeout.toMillis(), TimeUnit.MILLISECONDS)); + } catch (InterruptedException e) { + throw new RuntimeException(e); + } finally { + connectedSemaphore.release(); + messageSemaphore.release(); + driver.stopLogcatBroadcast(); + } + } +} From 91aa380117aada6a87663e9bab8c4dfcce463204 Mon Sep 17 00:00:00 2001 From: Mykola Mokhnach Date: Tue, 3 Apr 2018 09:27:32 +0200 Subject: [PATCH 2/8] Address PR comments --- .../android/ListensToLogcatMessages.java | 14 +++++++++-- .../java_client/ws/CanHandleMessages.java | 10 ++++---- .../java_client/ws/MessagesHandler.java | 16 ++++++++---- .../java_client/ws/StringMessagesHandler.java | 15 ----------- .../java_client/ws/StringWebSocketClient.java | 25 +++++++++---------- .../android/AndroidLogcatListenerTest.java | 8 +++--- 6 files changed, 44 insertions(+), 44 deletions(-) delete mode 100644 src/main/java/io/appium/java_client/ws/StringMessagesHandler.java diff --git a/src/main/java/io/appium/java_client/android/ListensToLogcatMessages.java b/src/main/java/io/appium/java_client/android/ListensToLogcatMessages.java index 1027a05f2..fe01e8f27 100644 --- a/src/main/java/io/appium/java_client/android/ListensToLogcatMessages.java +++ b/src/main/java/io/appium/java_client/android/ListensToLogcatMessages.java @@ -6,7 +6,7 @@ import com.google.common.collect.ImmutableMap; import io.appium.java_client.ExecutesMethod; -import io.appium.java_client.ws.StringMessagesHandler; +import io.appium.java_client.ws.MessagesHandler; import io.appium.java_client.ws.StringWebSocketClient; import org.openqa.selenium.remote.RemoteWebDriver; @@ -25,6 +25,16 @@ default void startLogcatBroadcast() { startLogcatBroadcast("localhost", DEFAULT_APPIUM_PORT); } + /** + * Start logcat messages broadcast via web socket. + * This method assumes that Appium server is assigned to the default port (4723). + * + * @param host the name of the host where Appium server is running + */ + default void startLogcatBroadcast(String host) { + startLogcatBroadcast(host, DEFAULT_APPIUM_PORT); + } + /** * Start logcat messages broadcast via web socket. * @@ -51,7 +61,7 @@ default void startLogcatBroadcast(String host, int port) { * * @param handler an instance of a class, which implement string message handlers */ - default void addLogcatListener(StringMessagesHandler handler) { + default void addLogcatListener(MessagesHandler handler) { logcatClient.addMessageHandler(handler); } diff --git a/src/main/java/io/appium/java_client/ws/CanHandleMessages.java b/src/main/java/io/appium/java_client/ws/CanHandleMessages.java index 209a79acd..8751c493d 100644 --- a/src/main/java/io/appium/java_client/ws/CanHandleMessages.java +++ b/src/main/java/io/appium/java_client/ws/CanHandleMessages.java @@ -10,7 +10,7 @@ public interface CanHandleMessages { /** * @return The list of web socket message handlers. */ - List messageHandlers(); + List getMessageHandlers(); /** * Register a new message handler. @@ -19,7 +19,7 @@ public interface CanHandleMessages { * implements MessagesHandler interface */ default void addMessageHandler(T msgHandler) { - messageHandlers().add(msgHandler); + getMessageHandlers().add(msgHandler); } /** @@ -30,20 +30,20 @@ default void addMessageHandler(T msgHandler) { * @return true if the given class instance was registered before and has been successfully removed. */ default boolean removeMessageHandler(T msgHandler) { - return messageHandlers().remove(msgHandler); + return getMessageHandlers().remove(msgHandler); } /** * @return The count of registered message handlers. */ default int messageHandlersCount() { - return messageHandlers().size(); + return getMessageHandlers().size(); } /** * Removes all registered message handlers. */ default void removeAllMessageHandlers() { - messageHandlers().clear(); + getMessageHandlers().clear(); } } diff --git a/src/main/java/io/appium/java_client/ws/MessagesHandler.java b/src/main/java/io/appium/java_client/ws/MessagesHandler.java index 02db8f314..940b5793e 100644 --- a/src/main/java/io/appium/java_client/ws/MessagesHandler.java +++ b/src/main/java/io/appium/java_client/ws/MessagesHandler.java @@ -3,7 +3,7 @@ /** * This is the basic interface for all web socket message handlers. */ -public interface MessagesHandler { +public interface MessagesHandler { /** * This event is fired when the client is * successfully connected to a web socket. @@ -19,10 +19,16 @@ public interface MessagesHandler { /** * This event is fired when there is an error * in the web socket connection. - * onDisconnected event is always generated after - * onError happens. * - * @param reason the actual error reason. + * @param cause the actual error reason. */ - void onError(Throwable reason); + void onError(Throwable cause); + + /** + * This event is fired when the client receives + * a new message from a web socket. + * + * @param message the actual web socket message content + */ + void onMessage(T message); } diff --git a/src/main/java/io/appium/java_client/ws/StringMessagesHandler.java b/src/main/java/io/appium/java_client/ws/StringMessagesHandler.java deleted file mode 100644 index 211c24e57..000000000 --- a/src/main/java/io/appium/java_client/ws/StringMessagesHandler.java +++ /dev/null @@ -1,15 +0,0 @@ -package io.appium.java_client.ws; - -/** - * All classes, that handle web socket messages of String type - * must implement this interface. - */ -public interface StringMessagesHandler extends MessagesHandler { - /** - * This event is fired when the client receives - * a new string message from a web socket. - * - * @param message the actual message content - */ - void onMessage(String message); -} diff --git a/src/main/java/io/appium/java_client/ws/StringWebSocketClient.java b/src/main/java/io/appium/java_client/ws/StringWebSocketClient.java index 1360b5c77..f56b7cf9a 100644 --- a/src/main/java/io/appium/java_client/ws/StringWebSocketClient.java +++ b/src/main/java/io/appium/java_client/ws/StringWebSocketClient.java @@ -1,5 +1,7 @@ package io.appium.java_client.ws; +import org.openqa.selenium.WebDriverException; + import java.io.IOException; import java.net.URI; import java.util.List; @@ -15,8 +17,8 @@ @ClientEndpoint public class StringWebSocketClient extends WebSocketClient - implements CanHandleMessages { - private final List messageHandlers = new CopyOnWriteArrayList<>(); + implements CanHandleMessages> { + private final List> messageHandlers = new CopyOnWriteArrayList<>(); private volatile Session session; @Override @@ -46,7 +48,7 @@ public void connect(URI endpoint) { @OnOpen public void onOpen(Session session, EndpointConfig config) { this.session = session; - messageHandlers().forEach(MessagesHandler::onConnected); + getMessageHandlers().forEach(MessagesHandler::onConnected); } /** @@ -59,7 +61,7 @@ public void onOpen(Session session, EndpointConfig config) { @OnClose public void onClose(Session session, CloseReason reason) { this.session = null; - messageHandlers().forEach(MessagesHandler::onDisconnected); + getMessageHandlers().forEach(MessagesHandler::onDisconnected); } /** @@ -67,16 +69,13 @@ public void onClose(Session session, CloseReason reason) { * error in web socket connection. * * @param session the actual web socket session instance - * @param reason the actual error reason + * @param cause the actual error reason */ @OnError - public void onError(Session session, Throwable reason) { + public void onError(Session session, Throwable cause) { this.session = null; - messageHandlers().forEach(x -> { - x.onError(reason); - x.onDisconnected(); - }); - throw new RuntimeException(reason); + getMessageHandlers().forEach(x -> x.onError(cause)); + throw new WebDriverException(cause); } /** @@ -87,14 +86,14 @@ public void onError(Session session, Throwable reason) { */ @OnMessage public void onMessage(String message) { - messageHandlers().forEach(x -> x.onMessage(message)); + getMessageHandlers().forEach(x -> x.onMessage(message)); } /** * @return The list of all registered web socket messages handlers. */ @Override - public List messageHandlers() { + public List> getMessageHandlers() { return messageHandlers; } } diff --git a/src/test/java/io/appium/java_client/android/AndroidLogcatListenerTest.java b/src/test/java/io/appium/java_client/android/AndroidLogcatListenerTest.java index 8b8af281f..571b50ec5 100644 --- a/src/test/java/io/appium/java_client/android/AndroidLogcatListenerTest.java +++ b/src/test/java/io/appium/java_client/android/AndroidLogcatListenerTest.java @@ -2,7 +2,7 @@ import static org.junit.Assert.assertTrue; -import io.appium.java_client.ws.StringMessagesHandler; +import io.appium.java_client.ws.MessagesHandler; import org.junit.Test; import java.time.Duration; @@ -19,7 +19,7 @@ public void verifyLogcatListenerCanBeAssigned() { try { driver.startLogcatBroadcast(); - driver.addLogcatListener(new StringMessagesHandler() { + driver.addLogcatListener(new MessagesHandler() { @Override public void onMessage(String message) { messageSemaphore.release(); @@ -36,7 +36,7 @@ public void onDisconnected() { } @Override - public void onError(Throwable reason) { + public void onError(Throwable cause) { // ignore } }); @@ -49,7 +49,7 @@ public void onError(Throwable reason) { assertTrue(String.format("Didn't receive any log message after %s timeout", timeout), messageSemaphore.tryAcquire(timeout.toMillis(), TimeUnit.MILLISECONDS)); } catch (InterruptedException e) { - throw new RuntimeException(e); + throw new IllegalStateException(e); } finally { connectedSemaphore.release(); messageSemaphore.release(); From 443e29a5c9fee2bab214d924d9e1d327a4017023 Mon Sep 17 00:00:00 2001 From: Mykola Mokhnach Date: Tue, 3 Apr 2018 10:34:50 +0200 Subject: [PATCH 3/8] Remove unused arguments --- .../java_client/ws/StringWebSocketClient.java | 14 ++++---------- 1 file changed, 4 insertions(+), 10 deletions(-) diff --git a/src/main/java/io/appium/java_client/ws/StringWebSocketClient.java b/src/main/java/io/appium/java_client/ws/StringWebSocketClient.java index f56b7cf9a..ec30a3c44 100644 --- a/src/main/java/io/appium/java_client/ws/StringWebSocketClient.java +++ b/src/main/java/io/appium/java_client/ws/StringWebSocketClient.java @@ -7,8 +7,6 @@ import java.util.List; import java.util.concurrent.CopyOnWriteArrayList; import javax.websocket.ClientEndpoint; -import javax.websocket.CloseReason; -import javax.websocket.EndpointConfig; import javax.websocket.OnClose; import javax.websocket.OnError; import javax.websocket.OnMessage; @@ -27,6 +25,7 @@ public void connect(URI endpoint) { if (endpoint.equals(this.getEndpoint())) { return; } + removeAllMessageHandlers(); try { session.close(); @@ -43,10 +42,9 @@ public void connect(URI endpoint) { * connected to a web socket. * * @param session the actual web socket session instance - * @param config endpoint config */ @OnOpen - public void onOpen(Session session, EndpointConfig config) { + public void onOpen(Session session) { this.session = session; getMessageHandlers().forEach(MessagesHandler::onConnected); } @@ -54,12 +52,9 @@ public void onOpen(Session session, EndpointConfig config) { /** * This event if fired when the client is * disconnected from a web socket. - * - * @param session the actual web socket session instance - * @param reason connection close reason */ @OnClose - public void onClose(Session session, CloseReason reason) { + public void onClose() { this.session = null; getMessageHandlers().forEach(MessagesHandler::onDisconnected); } @@ -68,11 +63,10 @@ public void onClose(Session session, CloseReason reason) { * This event if fired when there is an unexpected * error in web socket connection. * - * @param session the actual web socket session instance * @param cause the actual error reason */ @OnError - public void onError(Session session, Throwable cause) { + public void onError(Throwable cause) { this.session = null; getMessageHandlers().forEach(x -> x.onError(cause)); throw new WebDriverException(cause); From c76ffc5bca0cb6b17a26a946c09e4833044c21a6 Mon Sep 17 00:00:00 2001 From: Mykola Mokhnach Date: Fri, 6 Apr 2018 14:28:57 +0200 Subject: [PATCH 4/8] Tune execute args --- .../java_client/android/ListensToLogcatMessages.java | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/src/main/java/io/appium/java_client/android/ListensToLogcatMessages.java b/src/main/java/io/appium/java_client/android/ListensToLogcatMessages.java index fe01e8f27..c39f35ef6 100644 --- a/src/main/java/io/appium/java_client/android/ListensToLogcatMessages.java +++ b/src/main/java/io/appium/java_client/android/ListensToLogcatMessages.java @@ -12,6 +12,7 @@ import java.net.URI; import java.net.URISyntaxException; +import java.util.Collections; public interface ListensToLogcatMessages extends ExecutesMethod { StringWebSocketClient logcatClient = new StringWebSocketClient(); @@ -42,7 +43,8 @@ default void startLogcatBroadcast(String host) { * @param port the port of the host where Appium server is running */ default void startLogcatBroadcast(String host, int port) { - execute(EXECUTE_SCRIPT, ImmutableMap.of("script", "mobile: startLogsBroadcast")); + execute(EXECUTE_SCRIPT, ImmutableMap.of("script", "mobile: startLogsBroadcast", + "args", Collections.emptyList())); final URI endpointUri; try { endpointUri = new URI(String.format("ws://%s:%s/ws/session/%s/appium/device/logcat", @@ -76,6 +78,7 @@ default void removeAllLogcatListeners() { * Stops logcat messages broadcast via web socket. */ default void stopLogcatBroadcast() { - execute(EXECUTE_SCRIPT, ImmutableMap.of("script", "mobile: stopLogsBroadcast")); + execute(EXECUTE_SCRIPT, ImmutableMap.of("script", "mobile: stopLogsBroadcast", + "args", Collections.emptyList())); } } From cbf4c43ccc683842dfc32414a8ce5cc16ff2fd36 Mon Sep 17 00:00:00 2001 From: Mykola Mokhnach Date: Fri, 6 Apr 2018 15:48:00 +0200 Subject: [PATCH 5/8] Add missing dependencies --- build.gradle | 6 ++- .../android/AndroidLogcatListenerTest.java | 49 ++++++++----------- 2 files changed, 25 insertions(+), 30 deletions(-) diff --git a/build.gradle b/build.gradle index 49e364c52..9aff9e21d 100644 --- a/build.gradle +++ b/build.gradle @@ -68,7 +68,6 @@ dependencies { force = true } compile 'com.google.code.gson:gson:2.8.2' - compile 'javax.websocket:javax.websocket-api:1.1' compile 'org.apache.httpcomponents:httpclient:4.5.5' compile 'cglib:cglib:3.2.6' compile 'commons-validator:commons-validator:1.6' @@ -77,7 +76,10 @@ dependencies { compile 'org.springframework:spring-context:5.0.3.RELEASE' compile 'org.aspectj:aspectjweaver:1.8.13' compile 'org.openpnp:opencv:3.2.0-1' - + compile 'javax.websocket:javax.websocket-api:1.1' + compile 'org.glassfish.tyrus:tyrus-client:1.1' + compile 'org.glassfish.tyrus:tyrus-container-grizzly:1.1' + testCompile 'junit:junit:4.12' testCompile 'org.hamcrest:hamcrest-all:1.3' } diff --git a/src/test/java/io/appium/java_client/android/AndroidLogcatListenerTest.java b/src/test/java/io/appium/java_client/android/AndroidLogcatListenerTest.java index 571b50ec5..d66ed81d8 100644 --- a/src/test/java/io/appium/java_client/android/AndroidLogcatListenerTest.java +++ b/src/test/java/io/appium/java_client/android/AndroidLogcatListenerTest.java @@ -14,44 +14,37 @@ public class AndroidLogcatListenerTest extends BaseAndroidTest { @Test public void verifyLogcatListenerCanBeAssigned() { final Semaphore messageSemaphore = new Semaphore(1); - final Semaphore connectedSemaphore = new Semaphore(1); final Duration timeout = Duration.ofSeconds(5); + driver.addLogcatListener(new MessagesHandler() { + @Override + public void onMessage(String message) { + messageSemaphore.release(); + } + + @Override + public void onConnected() { + System.out.println("Connected to web socket"); + } + + @Override + public void onDisconnected() { + System.out.println("Disconnected from web socket"); + } + + @Override + public void onError(Throwable cause) { + cause.printStackTrace(); + } + }); try { driver.startLogcatBroadcast(); - driver.addLogcatListener(new MessagesHandler() { - @Override - public void onMessage(String message) { - messageSemaphore.release(); - } - - @Override - public void onConnected() { - connectedSemaphore.release(); - } - - @Override - public void onDisconnected() { - // ignore - } - - @Override - public void onError(Throwable cause) { - // ignore - } - }); - - connectedSemaphore.acquire(); messageSemaphore.acquire(); - - assertTrue(String.format("Didn't connect to the web socket after %s timeout", timeout), - connectedSemaphore.tryAcquire(timeout.toMillis(), TimeUnit.MILLISECONDS)); assertTrue(String.format("Didn't receive any log message after %s timeout", timeout), messageSemaphore.tryAcquire(timeout.toMillis(), TimeUnit.MILLISECONDS)); } catch (InterruptedException e) { throw new IllegalStateException(e); } finally { - connectedSemaphore.release(); messageSemaphore.release(); driver.stopLogcatBroadcast(); } From c978b1bbeff65ff51dd57b7cca2f252569304040 Mon Sep 17 00:00:00 2001 From: Mykola Mokhnach Date: Fri, 6 Apr 2018 15:54:25 +0200 Subject: [PATCH 6/8] Add license headers --- .../android/ListensToLogcatMessages.java | 16 ++++++++++++++++ .../appium/java_client/ws/CanHandleMessages.java | 16 ++++++++++++++++ .../appium/java_client/ws/MessagesHandler.java | 16 ++++++++++++++++ .../java_client/ws/StringWebSocketClient.java | 16 ++++++++++++++++ .../appium/java_client/ws/WebSocketClient.java | 16 ++++++++++++++++ 5 files changed, 80 insertions(+) diff --git a/src/main/java/io/appium/java_client/android/ListensToLogcatMessages.java b/src/main/java/io/appium/java_client/android/ListensToLogcatMessages.java index c39f35ef6..1a98abe49 100644 --- a/src/main/java/io/appium/java_client/android/ListensToLogcatMessages.java +++ b/src/main/java/io/appium/java_client/android/ListensToLogcatMessages.java @@ -1,3 +1,19 @@ +/* + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * See the NOTICE file distributed with this work for additional + * information regarding copyright ownership. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + package io.appium.java_client.android; import static io.appium.java_client.service.local.AppiumServiceBuilder.DEFAULT_APPIUM_PORT; diff --git a/src/main/java/io/appium/java_client/ws/CanHandleMessages.java b/src/main/java/io/appium/java_client/ws/CanHandleMessages.java index 8751c493d..daff2f7d6 100644 --- a/src/main/java/io/appium/java_client/ws/CanHandleMessages.java +++ b/src/main/java/io/appium/java_client/ws/CanHandleMessages.java @@ -1,3 +1,19 @@ +/* + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * See the NOTICE file distributed with this work for additional + * information regarding copyright ownership. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + package io.appium.java_client.ws; import java.util.List; diff --git a/src/main/java/io/appium/java_client/ws/MessagesHandler.java b/src/main/java/io/appium/java_client/ws/MessagesHandler.java index 940b5793e..9665932f7 100644 --- a/src/main/java/io/appium/java_client/ws/MessagesHandler.java +++ b/src/main/java/io/appium/java_client/ws/MessagesHandler.java @@ -1,3 +1,19 @@ +/* + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * See the NOTICE file distributed with this work for additional + * information regarding copyright ownership. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + package io.appium.java_client.ws; /** diff --git a/src/main/java/io/appium/java_client/ws/StringWebSocketClient.java b/src/main/java/io/appium/java_client/ws/StringWebSocketClient.java index ec30a3c44..46e3535fd 100644 --- a/src/main/java/io/appium/java_client/ws/StringWebSocketClient.java +++ b/src/main/java/io/appium/java_client/ws/StringWebSocketClient.java @@ -1,3 +1,19 @@ +/* + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * See the NOTICE file distributed with this work for additional + * information regarding copyright ownership. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + package io.appium.java_client.ws; import org.openqa.selenium.WebDriverException; diff --git a/src/main/java/io/appium/java_client/ws/WebSocketClient.java b/src/main/java/io/appium/java_client/ws/WebSocketClient.java index a61c102c8..0101e5d2f 100644 --- a/src/main/java/io/appium/java_client/ws/WebSocketClient.java +++ b/src/main/java/io/appium/java_client/ws/WebSocketClient.java @@ -1,3 +1,19 @@ +/* + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * See the NOTICE file distributed with this work for additional + * information regarding copyright ownership. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + package io.appium.java_client.ws; import org.openqa.selenium.WebDriverException; From 67c4235d90fd8597d7a6f506b77cce7ffe0f7e85 Mon Sep 17 00:00:00 2001 From: Mykola Mokhnach Date: Thu, 12 Apr 2018 16:27:38 +0200 Subject: [PATCH 7/8] Rewrite the stuff using functional approach --- .../android/ListensToLogcatMessages.java | 52 ++++++++++++++--- ...gesHandler.java => CanHandleConnects.java} | 35 +++++------- .../java_client/ws/CanHandleDisconnects.java | 43 ++++++++++++++ .../java_client/ws/CanHandleErrors.java | 44 ++++++++++++++ .../java_client/ws/CanHandleMessages.java | 39 +++---------- .../java_client/ws/StringWebSocketClient.java | 57 ++++++++++++++++--- .../android/AndroidLogcatListenerTest.java | 26 ++------- 7 files changed, 207 insertions(+), 89 deletions(-) rename src/main/java/io/appium/java_client/ws/{MessagesHandler.java => CanHandleConnects.java} (51%) create mode 100644 src/main/java/io/appium/java_client/ws/CanHandleDisconnects.java create mode 100644 src/main/java/io/appium/java_client/ws/CanHandleErrors.java diff --git a/src/main/java/io/appium/java_client/android/ListensToLogcatMessages.java b/src/main/java/io/appium/java_client/android/ListensToLogcatMessages.java index 1a98abe49..4b2629815 100644 --- a/src/main/java/io/appium/java_client/android/ListensToLogcatMessages.java +++ b/src/main/java/io/appium/java_client/android/ListensToLogcatMessages.java @@ -22,13 +22,13 @@ import com.google.common.collect.ImmutableMap; import io.appium.java_client.ExecutesMethod; -import io.appium.java_client.ws.MessagesHandler; import io.appium.java_client.ws.StringWebSocketClient; import org.openqa.selenium.remote.RemoteWebDriver; import java.net.URI; import java.net.URISyntaxException; import java.util.Collections; +import java.util.function.Consumer; public interface ListensToLogcatMessages extends ExecutesMethod { StringWebSocketClient logcatClient = new StringWebSocketClient(); @@ -72,22 +72,60 @@ default void startLogcatBroadcast(String host, int port) { } /** - * Adds a new log broadcasting handler. + * Adds a new log messages broadcasting handler. * Several handlers might be assigned to a single server. - * Multiple calls to this method will cause the handler + * Multiple calls to this method will cause such handler * to be called multiple times. * - * @param handler an instance of a class, which implement string message handlers + * @param handler a function, which accepts a single argument, which is the actual log message */ - default void addLogcatListener(MessagesHandler handler) { + default void addLogcatMessagesListener(Consumer handler) { logcatClient.addMessageHandler(handler); } /** - * Removes all existing logcat message handlers. + * Adds a new log broadcasting errors handler. + * Several handlers might be assigned to a single server. + * Multiple calls to this method will cause such handler + * to be called multiple times. + * + * @param handler a function, which accepts a single argument, which is the actual exception instance + */ + default void addLogcatErrorsListener(Consumer handler) { + logcatClient.addErrorHandler(handler); + } + + /** + * Adds a new log broadcasting connection handler. + * Several handlers might be assigned to a single server. + * Multiple calls to this method will cause such handler + * to be called multiple times. + * + * @param handler a function, which is executed as soon as the client is successfully + * connected to the web socket + */ + default void addLogcatConnectionListener(Runnable handler) { + logcatClient.addConnectionHandler(handler); + } + + /** + * Adds a new log broadcasting disconnection handler. + * Several handlers might be assigned to a single server. + * Multiple calls to this method will cause such handler + * to be called multiple times. + * + * @param handler a function, which is executed as soon as the client is successfully + * disconnected from the web socket + */ + default void addLogcatDisconnectionListener(Runnable handler) { + logcatClient.addDisconnectionHandler(handler); + } + + /** + * Removes all existing logcat handlers. */ default void removeAllLogcatListeners() { - logcatClient.removeAllMessageHandlers(); + logcatClient.removeAllHandlers(); } /** diff --git a/src/main/java/io/appium/java_client/ws/MessagesHandler.java b/src/main/java/io/appium/java_client/ws/CanHandleConnects.java similarity index 51% rename from src/main/java/io/appium/java_client/ws/MessagesHandler.java rename to src/main/java/io/appium/java_client/ws/CanHandleConnects.java index 9665932f7..47cf91d09 100644 --- a/src/main/java/io/appium/java_client/ws/MessagesHandler.java +++ b/src/main/java/io/appium/java_client/ws/CanHandleConnects.java @@ -16,35 +16,28 @@ package io.appium.java_client.ws; -/** - * This is the basic interface for all web socket message handlers. - */ -public interface MessagesHandler { - /** - * This event is fired when the client is - * successfully connected to a web socket. - */ - void onConnected(); +import java.util.List; + +public interface CanHandleConnects { /** - * This event is fired when the client is - * disconnected from a web socket. + * @return The list of web socket connection handlers. */ - void onDisconnected(); + List getConnectionHandlers(); /** - * This event is fired when there is an error - * in the web socket connection. + * Register a new message handler. * - * @param cause the actual error reason. + * @param handler a callback function, which is going to be executed when web socket connection event arrives */ - void onError(Throwable cause); + default void addConnectionHandler(Runnable handler) { + getConnectionHandlers().add(handler); + } /** - * This event is fired when the client receives - * a new message from a web socket. - * - * @param message the actual web socket message content + * Removes existing web socket connection handlers. */ - void onMessage(T message); + default void removeConnectionHandlers() { + getConnectionHandlers().clear(); + } } diff --git a/src/main/java/io/appium/java_client/ws/CanHandleDisconnects.java b/src/main/java/io/appium/java_client/ws/CanHandleDisconnects.java new file mode 100644 index 000000000..52c429726 --- /dev/null +++ b/src/main/java/io/appium/java_client/ws/CanHandleDisconnects.java @@ -0,0 +1,43 @@ +/* + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * See the NOTICE file distributed with this work for additional + * information regarding copyright ownership. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package io.appium.java_client.ws; + +import java.util.List; + +public interface CanHandleDisconnects { + + /** + * @return The list of web socket disconnection handlers. + */ + List getDisconnectionHandlers(); + + /** + * Register a new web socket disconnect handler. + * + * @param handler a callback function, which is going to be executed when web socket disconnect event arrives + */ + default void addDisconnectionHandler(Runnable handler) { + getDisconnectionHandlers().add(handler); + } + + /** + * Removes existing disconnection handlers. + */ + default void removeDisconnectionHandlers() { + getDisconnectionHandlers().clear(); + } +} diff --git a/src/main/java/io/appium/java_client/ws/CanHandleErrors.java b/src/main/java/io/appium/java_client/ws/CanHandleErrors.java new file mode 100644 index 000000000..86f2b4e9e --- /dev/null +++ b/src/main/java/io/appium/java_client/ws/CanHandleErrors.java @@ -0,0 +1,44 @@ +/* + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * See the NOTICE file distributed with this work for additional + * information regarding copyright ownership. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package io.appium.java_client.ws; + +import java.util.List; +import java.util.function.Consumer; + +public interface CanHandleErrors { + + /** + * @return The list of web socket error handlers. + */ + List> getErrorHandlers(); + + /** + * Register a new error handler. + * + * @param handler a callback function, which accepts the received exception instance as a parameter + */ + default void addErrorHandler(Consumer handler) { + getErrorHandlers().add(handler); + } + + /** + * Removes existing error handlers. + */ + default void removeErrorHandlers() { + getErrorHandlers().clear(); + } +} diff --git a/src/main/java/io/appium/java_client/ws/CanHandleMessages.java b/src/main/java/io/appium/java_client/ws/CanHandleMessages.java index daff2f7d6..f1688f3d3 100644 --- a/src/main/java/io/appium/java_client/ws/CanHandleMessages.java +++ b/src/main/java/io/appium/java_client/ws/CanHandleMessages.java @@ -17,49 +17,28 @@ package io.appium.java_client.ws; import java.util.List; +import java.util.function.Consumer; -/** - * This interface might be assigned to classes, which - * are defined as web socket clients. - */ -public interface CanHandleMessages { +public interface CanHandleMessages { /** * @return The list of web socket message handlers. */ - List getMessageHandlers(); + List> getMessageHandlers(); /** * Register a new message handler. * - * @param msgHandler an instance of a class, which - * implements MessagesHandler interface - */ - default void addMessageHandler(T msgHandler) { - getMessageHandlers().add(msgHandler); - } - - /** - * Removes an existing message handler. - * - * @param msgHandler an instance of a class, which - * implements MessagesHandler interface - * @return true if the given class instance was registered before and has been successfully removed. + * @param handler a callback function, which accepts the received message as a parameter */ - default boolean removeMessageHandler(T msgHandler) { - return getMessageHandlers().remove(msgHandler); + default void addMessageHandler(Consumer handler) { + getMessageHandlers().add(handler); } /** - * @return The count of registered message handlers. + * Removes existing message handlers. */ - default int messageHandlersCount() { - return getMessageHandlers().size(); - } - - /** - * Removes all registered message handlers. - */ - default void removeAllMessageHandlers() { + default void removeMessageHandlers() { getMessageHandlers().clear(); } } + diff --git a/src/main/java/io/appium/java_client/ws/StringWebSocketClient.java b/src/main/java/io/appium/java_client/ws/StringWebSocketClient.java index 46e3535fd..ebb99d7da 100644 --- a/src/main/java/io/appium/java_client/ws/StringWebSocketClient.java +++ b/src/main/java/io/appium/java_client/ws/StringWebSocketClient.java @@ -22,6 +22,7 @@ import java.net.URI; import java.util.List; import java.util.concurrent.CopyOnWriteArrayList; +import java.util.function.Consumer; import javax.websocket.ClientEndpoint; import javax.websocket.OnClose; import javax.websocket.OnError; @@ -30,9 +31,13 @@ import javax.websocket.Session; @ClientEndpoint -public class StringWebSocketClient extends WebSocketClient - implements CanHandleMessages> { - private final List> messageHandlers = new CopyOnWriteArrayList<>(); +public class StringWebSocketClient extends WebSocketClient implements + CanHandleMessages, CanHandleErrors, CanHandleConnects, CanHandleDisconnects { + private final List> messageHandlers = new CopyOnWriteArrayList<>(); + private final List> errorHandlers = new CopyOnWriteArrayList<>(); + private final List connectHandlers = new CopyOnWriteArrayList<>(); + private final List disconnectHandlers = new CopyOnWriteArrayList<>(); + private volatile Session session; @Override @@ -42,7 +47,7 @@ public void connect(URI endpoint) { return; } - removeAllMessageHandlers(); + removeAllHandlers(); try { session.close(); } catch (IOException e) { @@ -62,7 +67,7 @@ public void connect(URI endpoint) { @OnOpen public void onOpen(Session session) { this.session = session; - getMessageHandlers().forEach(MessagesHandler::onConnected); + getConnectionHandlers().forEach(Runnable::run); } /** @@ -72,7 +77,7 @@ public void onOpen(Session session) { @OnClose public void onClose() { this.session = null; - getMessageHandlers().forEach(MessagesHandler::onDisconnected); + getDisconnectionHandlers().forEach(Runnable::run); } /** @@ -84,7 +89,7 @@ public void onClose() { @OnError public void onError(Throwable cause) { this.session = null; - getMessageHandlers().forEach(x -> x.onError(cause)); + getErrorHandlers().forEach(x -> x.accept(cause)); throw new WebDriverException(cause); } @@ -96,14 +101,48 @@ public void onError(Throwable cause) { */ @OnMessage public void onMessage(String message) { - getMessageHandlers().forEach(x -> x.onMessage(message)); + getMessageHandlers().forEach(x -> x.accept(message)); } /** * @return The list of all registered web socket messages handlers. */ @Override - public List> getMessageHandlers() { + public List> getMessageHandlers() { return messageHandlers; } + + /** + * @return The list of all registered web socket error handlers. + */ + @Override + public List> getErrorHandlers() { + return errorHandlers; + } + + /** + * @return The list of all registered web socket connection handlers. + */ + @Override + public List getConnectionHandlers() { + return connectHandlers; + } + + /** + * @return The list of all registered web socket disconnection handlers. + */ + @Override + public List getDisconnectionHandlers() { + return disconnectHandlers; + } + + /** + * Remove all the registered handlers. + */ + public void removeAllHandlers() { + removeMessageHandlers(); + removeErrorHandlers(); + removeConnectionHandlers(); + removeDisconnectionHandlers(); + } } diff --git a/src/test/java/io/appium/java_client/android/AndroidLogcatListenerTest.java b/src/test/java/io/appium/java_client/android/AndroidLogcatListenerTest.java index d66ed81d8..731fd352e 100644 --- a/src/test/java/io/appium/java_client/android/AndroidLogcatListenerTest.java +++ b/src/test/java/io/appium/java_client/android/AndroidLogcatListenerTest.java @@ -2,7 +2,6 @@ import static org.junit.Assert.assertTrue; -import io.appium.java_client.ws.MessagesHandler; import org.junit.Test; import java.time.Duration; @@ -16,27 +15,10 @@ public void verifyLogcatListenerCanBeAssigned() { final Semaphore messageSemaphore = new Semaphore(1); final Duration timeout = Duration.ofSeconds(5); - driver.addLogcatListener(new MessagesHandler() { - @Override - public void onMessage(String message) { - messageSemaphore.release(); - } - - @Override - public void onConnected() { - System.out.println("Connected to web socket"); - } - - @Override - public void onDisconnected() { - System.out.println("Disconnected from web socket"); - } - - @Override - public void onError(Throwable cause) { - cause.printStackTrace(); - } - }); + driver.addLogcatMessagesListener((msg) -> messageSemaphore.release()); + driver.addLogcatConnectionListener(() -> System.out.println("Connected to the web socket")); + driver.addLogcatDisconnectionListener(() -> System.out.println("Disconnected from the web socket")); + driver.addLogcatErrorsListener(Throwable::printStackTrace); try { driver.startLogcatBroadcast(); messageSemaphore.acquire(); From 74e7fdd9073a9813a1d9e07561b3c3d1855e7a37 Mon Sep 17 00:00:00 2001 From: Mykola Mokhnach Date: Fri, 13 Apr 2018 16:58:06 +0200 Subject: [PATCH 8/8] Minimize the app to push log messages --- .../java_client/android/AndroidLogcatListenerTest.java | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/src/test/java/io/appium/java_client/android/AndroidLogcatListenerTest.java b/src/test/java/io/appium/java_client/android/AndroidLogcatListenerTest.java index 731fd352e..5cfdee5c2 100644 --- a/src/test/java/io/appium/java_client/android/AndroidLogcatListenerTest.java +++ b/src/test/java/io/appium/java_client/android/AndroidLogcatListenerTest.java @@ -2,6 +2,7 @@ import static org.junit.Assert.assertTrue; +import org.apache.commons.lang3.time.DurationFormatUtils; import org.junit.Test; import java.time.Duration; @@ -13,7 +14,7 @@ public class AndroidLogcatListenerTest extends BaseAndroidTest { @Test public void verifyLogcatListenerCanBeAssigned() { final Semaphore messageSemaphore = new Semaphore(1); - final Duration timeout = Duration.ofSeconds(5); + final Duration timeout = Duration.ofSeconds(15); driver.addLogcatMessagesListener((msg) -> messageSemaphore.release()); driver.addLogcatConnectionListener(() -> System.out.println("Connected to the web socket")); @@ -22,7 +23,10 @@ public void verifyLogcatListenerCanBeAssigned() { try { driver.startLogcatBroadcast(); messageSemaphore.acquire(); - assertTrue(String.format("Didn't receive any log message after %s timeout", timeout), + // This is needed for pushing some internal log messages + driver.runAppInBackground(Duration.ofSeconds(1)); + assertTrue(String.format("Didn't receive any log message after %s timeout", + DurationFormatUtils.formatDuration(timeout.toMillis(), "H:mm:ss", true)), messageSemaphore.tryAcquire(timeout.toMillis(), TimeUnit.MILLISECONDS)); } catch (InterruptedException e) { throw new IllegalStateException(e);