From a6bbcb23c84b3c2a577a6aaea59944a51beee01e Mon Sep 17 00:00:00 2001 From: sacOO7 Date: Tue, 17 Dec 2024 19:46:19 +0530 Subject: [PATCH] [ECO-5117][RTL5] Fix missing spec implementation for channel detach (RTL5g) 1. Added missing callCompletionListenerError when detachImpl throws exception on invalid connection state 2. Added separate test case for the spec RTL5g 3. Annotated channel detach tests with appropriate spec --- .../io/ably/lib/realtime/ChannelBase.java | 4 +- .../test/realtime/RealtimeChannelTest.java | 84 +++++++++++++++++++ 2 files changed, 87 insertions(+), 1 deletion(-) diff --git a/lib/src/main/java/io/ably/lib/realtime/ChannelBase.java b/lib/src/main/java/io/ably/lib/realtime/ChannelBase.java index c59b399e4..cf0345108 100644 --- a/lib/src/main/java/io/ably/lib/realtime/ChannelBase.java +++ b/lib/src/main/java/io/ably/lib/realtime/ChannelBase.java @@ -350,8 +350,9 @@ private void detachImpl(CompletionListener listener) throws AblyException { default: } ConnectionManager connectionManager = ably.connection.connectionManager; - if(!connectionManager.isActive()) + if(!connectionManager.isActive()) { // RTL5g throw AblyException.fromErrorInfo(connectionManager.getStateErrorInfo()); + } sendDetachMessage(listener); } @@ -609,6 +610,7 @@ public void onError(ErrorInfo reason) { detachImpl(completionListener); } catch (AblyException e) { attachTimer = null; + callCompletionListenerError(listener, e.errorInfo); // RTL5g } if(attachTimer == null) { diff --git a/lib/src/test/java/io/ably/lib/test/realtime/RealtimeChannelTest.java b/lib/src/test/java/io/ably/lib/test/realtime/RealtimeChannelTest.java index b6c979e5a..c5822cb13 100644 --- a/lib/src/test/java/io/ably/lib/test/realtime/RealtimeChannelTest.java +++ b/lib/src/test/java/io/ably/lib/test/realtime/RealtimeChannelTest.java @@ -945,6 +945,9 @@ public void attach_success_callback() { } } + /** + * Spec: RTL4g + */ @Test public void attach_success_callback_for_channel_in_failed_state() { AblyRealtime ably = null; @@ -1037,6 +1040,7 @@ public void attach_fail_callback() { /** * When client detaches from a channel successfully after initialized state, * verify attach {@code CompletionListener#onSuccess()} gets called. + * Spec: RTL5a */ @Test public void detach_success_callback_initialized() { @@ -1069,6 +1073,9 @@ public void detach_success_callback_initialized() { } } + /** + * Spec: RTL5j + */ @Test public void detach_success_callback_on_suspended_state() { AblyRealtime ably = null; @@ -1106,6 +1113,9 @@ public void detach_success_callback_on_suspended_state() { } } + /** + * Spec: RTL5b + */ @Test public void detach_failure_callback_on_failed_state() { AblyRealtime ably = null; @@ -1147,6 +1157,79 @@ public void detach_failure_callback_on_failed_state() { } } + /** + * When connection is in failed or suspended, set error in callback + * Spec: RTL5g + */ + @Test + public void detach_fail_callback_for_connection_invalid_state() { + AblyRealtime ably = null; + try { + ClientOptions opts = createOptions(testVars.keys[0].keyStr); + ably = new AblyRealtime(opts); + ConnectionWaiter connWaiter = new ConnectionWaiter(ably.connection); + + /* wait until connected */ + connWaiter.waitFor(ConnectionState.connected); + + /* create a channel and attach */ + final Channel channel = ably.channels.get("detach_failure"); + ChannelWaiter channelWaiter = new ChannelWaiter(channel); + channel.attach(); + channelWaiter.waitFor(ChannelState.attached); + + // Simulate connection closing from outside + ably.connection.connectionManager.requestState(new ConnectionManager.StateIndication( + ConnectionState.closing, + new ErrorInfo("Connection is closing", 80001) + )); + /* wait until connection closing */ + connWaiter.waitFor(ConnectionState.closing); + + // channel state is ATTACHED despite closing connection state + assertEquals(ChannelState.attached, channel.state); + + /* detach */ + Helpers.CompletionWaiter detachWaiter1 = new Helpers.CompletionWaiter(); + channel.detach(detachWaiter1); + + /* Verify onSuccess callback gets called */ + detachWaiter1.waitFor(); + assertFalse(detachWaiter1.success); + assertNotNull(detachWaiter1.error); + assertEquals("Connection is closing", detachWaiter1.error.message); + assertEquals(80001, detachWaiter1.error.code); + + // Simulate connection failure + ably.connection.connectionManager.requestState(ConnectionState.failed); + /* wait until connection failed */ + connWaiter.waitFor(ConnectionState.failed); + + // Mock channel state to ATTACHED despite failed connection state + channelWaiter.waitFor(ChannelState.failed); + channel.state = ChannelState.attached; + assertEquals(ChannelState.attached, channel.state); + + /* detach */ + Helpers.CompletionWaiter detachWaiter2 = new Helpers.CompletionWaiter(); + channel.detach(detachWaiter2); + + /* Verify onSuccess callback gets called */ + detachWaiter2.waitFor(); + assertFalse(detachWaiter2.success); + assertNotNull(detachWaiter2.error); + assertEquals("Connection failed", detachWaiter2.error.message); + assertEquals(80000, detachWaiter2.error.code); + + } catch (AblyException e) { + e.printStackTrace(); + fail("init0: Unexpected exception instantiating library"); + } finally { + if(ably != null) + ably.close(); + } + } + /** * When client detaches from a channel successfully after attached state, * verify attach {@code CompletionListener#onSuccess()} gets called. @@ -1184,6 +1267,7 @@ public void detach_success_callback_attached() throws AblyException { /** * When client detaches from a channel successfully after detaching state, * verify attach {@code CompletionListener#onSuccess()} gets called. + * Spec: RTL5i */ @Test public void detach_success_callback_detaching() throws AblyException {