Context
PR #226 (iOS syslog broadcast) and its upstream counterpart appium#1096 applied several robustness and test-hygiene fixes in response to review feedback. The iOS IOSDriver / SyslogBroadcastTests were originally a direct mirror of the Android AndroidDriver logcat implementation (merged in appium#969), so the same issues exist on the Android side and were intentionally not touched in that PR to keep its scope to iOS.
This issue tracks backporting the equivalent fixes to Android so the two platforms stay consistent.
Changes to backport
AndroidDriver.cs:
test/integration/Android/Session/Logs/LogcatBroadcastTests.cs:
Shared-client issue to fix (affects both platforms)
Already fixed for both platforms (not a backport item)
Reference
See the corresponding iOS changes and reviewer discussion in PR #226 and appium#1096.
Optional / follow-up
Context
PR #226 (iOS syslog broadcast) and its upstream counterpart appium#1096 applied several robustness and test-hygiene fixes in response to review feedback. The iOS
IOSDriver/SyslogBroadcastTestswere originally a direct mirror of the AndroidAndroidDriverlogcat implementation (merged in appium#969), so the same issues exist on the Android side and were intentionally not touched in that PR to keep its scope to iOS.This issue tracks backporting the equivalent fixes to Android so the two platforms stay consistent.
Changes to backport
AndroidDriver.cs:StartLogcatBroadcast(host, port): if the WebSocketConnectAsyncfails, the server-sidemobile: startLogsBroadcasthas already run, leaving an orphaned broadcast on the Appium server. Stop the broadcast (best-effort) on connection failure, then rethrow.StopLogcatBroadcast(): wrapmobile: stopLogsBroadcastin atry/finallysoDisconnectAsyncalways runs even if the stop command throws.UriBuilderinstead of$"ws://{host}:{port}/..."string interpolation, so IPv6 literal hosts (e.g.::1) are bracketed correctly rather than throwingUriFormatException.test/integration/Android/Session/Logs/LogcatBroadcastTests.cs:SemaphoreSlim.Wait(...)withawait WaitAsync(...)in the async tests.Thread.Sleep(...)withawait Task.Delay(...).CanHandleErrorsGracefully: catchWebDriverExceptioninstead ofAggregateException. AwaitedStringWebSocketClient.ConnectAsyncsurfaces connection failures asWebDriverExceptiondirectly (not wrapped inAggregateException), so the current catch clause is effectively dead code.CanHandleErrorsGracefully: remove the declared-but-never-awaitederrorSemaphoreand itsRelease()call.SemaphoreSlimmaxCounts (1inVerifyLogcatListenerCanBeAssigned,10inCanAddAndRemoveMultipleListeners) while the handler callsRelease()per message. A burst of logcat messages can exceed the max and throwSemaphoreFullException, making the tests flaky. Useint.MaxValueas the max.CanAddAndRemoveMultipleListeners: fix the misleading "both listeners should be called" comment to match the assertion (the semaphore wakes on the first listener, so the test only asserts at least one invocation).CanAddAndRemoveMultipleListeners: add a short drain delay afterRemoveAllLogcatListeners()and before resetting the counter.RemoveAll...races with in-flight dispatch — a message already read from the socket before removal can still invoke the previously captured delegate, flipping the post-removalEqualTo(0)assertion.Shared-client issue to fix (affects both platforms)
StringWebSocketClient.DisconnectInternalAsynconly completes the close handshake and fires_disconnectedhandlers whenState == Open. On a server-initiated close,ReceiveMessagesAsynccallsDisconnectAsync()while the state isCloseReceived, so the handshake and disconnection handlers are skipped. Fix is non-trivial: the server-close path callsDisconnectAsyncfrom within the receive loop, so naively broadening the state check would makeDisconnectInternalAsyncawaitits own_receiveTaskand deadlock. Needs a dedicated fix with tests (raised by Copilot on feat: Add WebSocket-based syslog broadcast support for iOS appium/dotnet-client#1096).Already fixed for both platforms (not a backport item)
StringWebSocketClient.DisconnectInternalAsync: null-guard_clientWebSocket(?.State) soDisconnectAsyncis safe/idempotent when called before any successfulConnectAsync. This lives in shared code and was fixed in feat(ios): implement syslog broadcast support in IOSDriver #226 / feat: Add WebSocket-based syslog broadcast support for iOS appium/dotnet-client#1096, so it already covers Android'sStopLogcatBroadcast().Reference
See the corresponding iOS changes and reviewer discussion in PR #226 and appium#1096.
Optional / follow-up
127.0.0.1:4723) so the broadcast tests also work against a remote server — ideally applied to both the Android and iOS suites together.ActionsChainsTest(StaleElementReferenceException) andAppStringsTest(OneTimeSetUpnew-session HTTP timeout after 10s). Worth investigating a longer session-start timeout and/or a retry, tracked separately if it persists.