From 0a86600013a48d242dede8bedeb65581e64ff280 Mon Sep 17 00:00:00 2001 From: Raphael Fakhri <153192858+RaphaelFakhri@users.noreply.github.com> Date: Sat, 10 Oct 2026 19:27:52 +0000 Subject: [PATCH] fix: report error code 80017 for a closed connection --- .../ably/lib/transport/ConnectionManager.java | 2 +- .../ConnectionManagerClosedErrorTest.java | 59 +++++++++++++++++++ 2 files changed, 60 insertions(+), 1 deletion(-) create mode 100644 lib/src/test/java/io/ably/lib/transport/ConnectionManagerClosedErrorTest.java diff --git a/lib/src/main/java/io/ably/lib/transport/ConnectionManager.java b/lib/src/main/java/io/ably/lib/transport/ConnectionManager.java index aa5ffe336..d39f65a34 100644 --- a/lib/src/main/java/io/ably/lib/transport/ConnectionManager.java +++ b/lib/src/main/java/io/ably/lib/transport/ConnectionManager.java @@ -72,7 +72,7 @@ public class ConnectionManager implements ConnectListener { * default errors ***********************************/ - static ErrorInfo REASON_CLOSED = new ErrorInfo("Can't attach when not in an active state", 200, 10000); + static ErrorInfo REASON_CLOSED = new ErrorInfo("Connection closed", 400, 80017); static ErrorInfo REASON_DISCONNECTED = new ErrorInfo("Connection temporarily unavailable", 503, 80003); static ErrorInfo REASON_SUSPENDED = new ErrorInfo("Connection unavailable", 503, 80002); static ErrorInfo REASON_FAILED = new ErrorInfo("Connection failed", 400, 80000); diff --git a/lib/src/test/java/io/ably/lib/transport/ConnectionManagerClosedErrorTest.java b/lib/src/test/java/io/ably/lib/transport/ConnectionManagerClosedErrorTest.java new file mode 100644 index 000000000..429555ceb --- /dev/null +++ b/lib/src/test/java/io/ably/lib/transport/ConnectionManagerClosedErrorTest.java @@ -0,0 +1,59 @@ +package io.ably.lib.transport; + +import static org.hamcrest.Matchers.is; +import static org.hamcrest.Matchers.notNullValue; +import static org.junit.Assert.assertThat; + +import io.ably.lib.debug.DebugOptions; +import io.ably.lib.realtime.AblyRealtime; +import io.ably.lib.realtime.CompletionListener; +import io.ably.lib.realtime.ConnectionState; +import io.ably.lib.test.common.Helpers; +import io.ably.lib.test.util.MockWebsocketFactory; +import io.ably.lib.types.AblyException; +import io.ably.lib.types.ErrorInfo; +import java.util.concurrent.atomic.AtomicReference; +import org.junit.Test; + +public class ConnectionManagerClosedErrorTest { + + /** + * Closing the connection reports Ably code 80017 with HTTP status code 400, both in the + * state change and when attaching a channel afterwards. + */ + @Test + public void closed_connection_error_codes() throws AblyException { + DebugOptions options = new DebugOptions("appid.keyid:keysecret"); + options.autoConnect = false; + MockWebsocketFactory mockTransport = new MockWebsocketFactory(); + mockTransport.failConnect(); + options.transportFactory = mockTransport; + + try (AblyRealtime ably = new AblyRealtime(options)) { + Helpers.ConnectionWaiter connectionWaiter = new Helpers.ConnectionWaiter(ably.connection); + ably.connection.connect(); + assertThat(connectionWaiter.waitFor(ConnectionState.disconnected, 1, 10000), is(true)); + ably.connection.close(); + assertThat(connectionWaiter.waitFor(ConnectionState.closed, 1, 10000), is(true)); + + ErrorInfo closedReason = connectionWaiter.lastStateChange().reason; + assertThat(closedReason, is(notNullValue())); + assertThat(closedReason.code, is(80017)); + assertThat(closedReason.statusCode, is(400)); + + AtomicReference attachError = new AtomicReference<>(); + ably.channels.get("closed_connection_attach").attach(new CompletionListener() { + @Override + public void onSuccess() {} + + @Override + public void onError(ErrorInfo reason) { + attachError.set(reason); + } + }); + assertThat(attachError.get(), is(notNullValue())); + assertThat(attachError.get().code, is(80017)); + assertThat(attachError.get().statusCode, is(400)); + } + } +}