diff --git a/Source/ARTRealtimePresence.m b/Source/ARTRealtimePresence.m index 9919c9c2a..8d27e63dc 100644 --- a/Source/ARTRealtimePresence.m +++ b/Source/ARTRealtimePresence.m @@ -502,7 +502,9 @@ - (ARTEventListener *)_subscribe:(ARTPresenceAction)action onAttach:(nullable AR ARTLogWarn(self.logger, @"R:%p C:%p (%@) presence subscribe to '%@' action(s) has been ignored (attempted to subscribe while channel is in FAILED state)", self->_realtime, self->_channel, self->_channel.name, ARTPresenceActionToStr(action)); return; } - [self->_channel _attach:onAttach]; + if (self->_channel.shouldAttach) { // RTP6c + [self->_channel _attach:onAttach]; + } listener = action == ARTPresenceActionAll ? [_eventEmitter on:cb] : [_eventEmitter on:[ARTEvent newWithPresenceAction:action] callback:cb]; ARTLogVerbose(self.logger, @"R:%p C:%p (%@) presence subscribe to '%@' action(s)", self->_realtime, self->_channel, self->_channel.name, ARTPresenceActionToStr(action)); }); diff --git a/Source/PrivateHeaders/Ably/ARTRealtimeChannel+Private.h b/Source/PrivateHeaders/Ably/ARTRealtimeChannel+Private.h index d58897a51..15e9e0a0a 100644 --- a/Source/PrivateHeaders/Ably/ARTRealtimeChannel+Private.h +++ b/Source/PrivateHeaders/Ably/ARTRealtimeChannel+Private.h @@ -33,6 +33,7 @@ NS_ASSUME_NONNULL_BEGIN - (ARTErrorInfo *)errorReason_nosync; - (NSString * _Nullable)clientId_nosync; - (BOOL)canBeReattached; +- (BOOL)shouldAttach; @property (readonly, weak, nonatomic) ARTRealtimeInternal *realtime; // weak because realtime owns self @property (readonly, nonatomic) ARTRestChannelInternal *restChannel; diff --git a/Test/Tests/RealtimeClientChannelTests.swift b/Test/Tests/RealtimeClientChannelTests.swift index dc6af1908..966ab5479 100644 --- a/Test/Tests/RealtimeClientChannelTests.swift +++ b/Test/Tests/RealtimeClientChannelTests.swift @@ -3318,11 +3318,24 @@ class RealtimeClientChannelTests: XCTestCase { let test = Test() let client = ARTRealtime(options: try AblyTests.commonAppSetup(for: test)) defer { client.dispose(); client.close() } - let channel = client.channels.get(test.uniqueChannelName()) + // Initialized + XCTAssertEqual(channel.state, ARTRealtimeChannelState.initialized) + channel.subscribe { _ in } + XCTAssertEqual(channel.state, ARTRealtimeChannelState.attaching) + expect(channel.state).toEventually(equal(ARTRealtimeChannelState.attached), timeout: testTimeout) + + // Detaching + channel.detach() + channel.subscribe { _ in } + XCTAssertEqual(channel.state, ARTRealtimeChannelState.detaching) + expect(channel.state).toEventually(equal(ARTRealtimeChannelState.attached), timeout: testTimeout) + + // Detached + channel.detach() + expect(channel.state).toEventually(equal(ARTRealtimeChannelState.detached), timeout: testTimeout) channel.subscribe { _ in } - expect(channel.state).toEventually(equal(ARTRealtimeChannelState.attached), timeout: testTimeout) } diff --git a/Test/Tests/RealtimeClientPresenceTests.swift b/Test/Tests/RealtimeClientPresenceTests.swift index 166616345..f58a0e1c8 100644 --- a/Test/Tests/RealtimeClientPresenceTests.swift +++ b/Test/Tests/RealtimeClientPresenceTests.swift @@ -893,16 +893,22 @@ class RealtimeClientPresenceTests: XCTestCase { defer { client.dispose(); client.close() } let channel = client.channels.get(test.uniqueChannelName()) + // Initialized XCTAssertEqual(channel.state, ARTRealtimeChannelState.initialized) channel.presence.subscribe { _ in } XCTAssertEqual(channel.state, ARTRealtimeChannelState.attaching) expect(channel.state).toEventually(equal(ARTRealtimeChannelState.attached), timeout: testTimeout) - + + // Detaching + channel.detach() + channel.presence.subscribe { _ in } + XCTAssertEqual(channel.state, ARTRealtimeChannelState.detaching) + expect(channel.state).toEventually(equal(ARTRealtimeChannelState.attached), timeout: testTimeout) + + // Detached channel.detach() expect(channel.state).toEventually(equal(ARTRealtimeChannelState.detached), timeout: testTimeout) - - channel.presence.subscribe(.present) { _ in } - XCTAssertEqual(channel.state, ARTRealtimeChannelState.attaching) + channel.presence.subscribe { _ in } expect(channel.state).toEventually(equal(ARTRealtimeChannelState.attached), timeout: testTimeout) } @@ -919,12 +925,10 @@ class RealtimeClientPresenceTests: XCTestCase { waitUntil(timeout: testTimeout) { done in channel.presence.subscribe(attachCallback: { errorInfo in XCTAssertNotNil(errorInfo) - - channel.presence.subscribe(.enter, onAttach: { errorInfo in - XCTAssertNotNil(errorInfo) - done() - }) { _ in } - }) { _ in } + done() + }, callback: { _ in + fail("Should not be called") + }) } } @@ -937,14 +941,13 @@ class RealtimeClientPresenceTests: XCTestCase { waitUntil(timeout: testTimeout) { done in let error = AblyTests.newErrorProtocolMessage() - channel.presence.subscribe(attachCallback: { errorInfo in - XCTAssertNotNil(errorInfo) - - channel.presence.subscribe(.enter, onAttach: { errorInfo in - XCTAssertNotNil(errorInfo) - done() - }) { _ in } - }) { _ in } + channel.presence.subscribe(attachCallback: { error in + XCTAssertEqual(channel.state, ARTRealtimeChannelState.failed) + XCTAssertNotNil(error) + done() + }, callback: { _ in + fail("Should not be called") + }) AblyTests.queue.async { channel.internal.onError(error) } @@ -2332,73 +2335,6 @@ class RealtimeClientPresenceTests: XCTestCase { } } - // RTP6 - - // RTP6c - func test__075__Presence__subscribe__should_implicitly_attach_the_channel() throws { - let test = Test() - let client = ARTRealtime(options: try AblyTests.commonAppSetup(for: test)) - defer { client.dispose(); client.close() } - let channel = client.channels.get(test.uniqueChannelName()) - - XCTAssertEqual(channel.state, ARTRealtimeChannelState.initialized) - channel.presence.subscribe { _ in } - XCTAssertEqual(channel.state, ARTRealtimeChannelState.attaching) - expect(channel.state).toEventually(equal(ARTRealtimeChannelState.attached), timeout: testTimeout) - - channel.detach() - expect(channel.state).toEventually(equal(ARTRealtimeChannelState.detached), timeout: testTimeout) - - channel.presence.subscribe(.present) { _ in } - XCTAssertEqual(channel.state, ARTRealtimeChannelState.attaching) - expect(channel.state).toEventually(equal(ARTRealtimeChannelState.attached), timeout: testTimeout) - } - - // RTP6c - func test__076__Presence__subscribe__should_result_in_an_error_if_the_channel_is_in_the_FAILED_state() throws { - let test = Test() - let client = ARTRealtime(options: try AblyTests.commonAppSetup(for: test)) - defer { client.dispose(); client.close() } - let channel = client.channels.get(test.uniqueChannelName()) - - let protocolError = AblyTests.newErrorProtocolMessage() - AblyTests.queue.async { - channel.internal.onError(protocolError) - } - - waitUntil(timeout: testTimeout) { done in - channel.presence.subscribe(attachCallback: { error in - XCTAssertEqual(channel.state, ARTRealtimeChannelState.failed) - XCTAssertNotNil(error) - done() - }, callback: { _ in - fail("Should not be called") - }) - } - } - - // RTP6c - func test__077__Presence__subscribe__should_result_in_an_error_if_the_channel_moves_to_the_FAILED_state() throws { - let test = Test() - let client = ARTRealtime(options: try AblyTests.commonAppSetup(for: test)) - defer { client.dispose(); client.close() } - let channel = client.channels.get(test.uniqueChannelName()) - - waitUntil(timeout: testTimeout) { done in - let error = AblyTests.newErrorProtocolMessage() - channel.presence.subscribe(attachCallback: { error in - XCTAssertEqual(channel.state, ARTRealtimeChannelState.failed) - XCTAssertNotNil(error) - done() - }, callback: { _ in - fail("Should not be called") - }) - AblyTests.queue.async { - channel.internal.onError(error) - } - } - } - // RTP8 // RTP8e