diff --git a/chat-android/src/test/java/com/ably/chat/room/RetryTest.kt b/chat-android/src/test/java/com/ably/chat/room/RetryTest.kt index f11b9db..f9ce4fe 100644 --- a/chat-android/src/test/java/com/ably/chat/room/RetryTest.kt +++ b/chat-android/src/test/java/com/ably/chat/room/RetryTest.kt @@ -1,6 +1,7 @@ package com.ably.chat.room import com.ably.chat.DefaultRoomLifecycle +import com.ably.chat.HttpStatusCodes import com.ably.chat.RoomLifecycleManager import com.ably.chat.RoomStatus import com.ably.chat.assertWaiter @@ -12,6 +13,8 @@ import com.ably.utils.retry import com.ably.utils.setState import io.ably.lib.realtime.ChannelState import io.ably.lib.realtime.ChannelStateListener +import io.ably.lib.types.AblyException +import io.ably.lib.types.ErrorInfo import io.mockk.coEvery import io.mockk.coJustRun import io.mockk.every @@ -165,10 +168,68 @@ class RetryTest { @Suppress("MaximumLineLength") @Test fun `(CHA-RL5e) If, during the CHA-RL5d wait, the contributor channel becomes failed, then the room enters failed state and retry operation stops`() = runTest { + val statusLifecycle = spyk() + + mockkStatic(io.ably.lib.realtime.Channel::attachCoroutine) + coJustRun { any().attachCoroutine() } + coJustRun { any().detachCoroutine() } + + val contributors = createRoomFeatureMocks() + val messagesContributor = contributors.first { it.contributor.featureName == "messages" } + messagesContributor.channel.setState(ChannelState.failed) + messagesContributor.channel.reason = ErrorInfo("Failed channel messages", HttpStatusCodes.InternalServerError) + + val roomLifecycle = spyk(RoomLifecycleManager(roomScope, statusLifecycle, contributors)) + + val result = kotlin.runCatching { roomLifecycle.retry(messagesContributor) } + Assert.assertTrue(result.isFailure) + val exception = result.exceptionOrNull() as AblyException + Assert.assertEquals("Failed channel messages", exception.errorInfo.message) + Assert.assertEquals(RoomStatus.Failed, statusLifecycle.status) + + assertWaiter { roomLifecycle.atomicCoroutineScope().finishedProcessing } } @Suppress("MaximumLineLength") @Test fun `(CHA-RL5f) If, during the CHA-RL5d wait, the contributor channel becomes ATTACHED, then attach operation continues for other contributors as per CHA-RL1e`() = runTest { + val statusLifecycle = spyk() + + mockkStatic(io.ably.lib.realtime.Channel::attachCoroutine) + val capturedAttachedChannels = mutableListOf() + coEvery { any().attachCoroutine() } coAnswers { + capturedAttachedChannels.add(firstArg()) + } + + val capturedDetachedChannels = mutableListOf() + coEvery { any().detachCoroutine() } coAnswers { + capturedDetachedChannels.add(firstArg()) + } + + val contributors = createRoomFeatureMocks() + Assert.assertEquals(5, contributors.size) + val messagesContributor = contributors.first { it.contributor.featureName == "messages" } + messagesContributor.channel.setState(ChannelState.attached) + + val roomLifecycle = spyk(RoomLifecycleManager(roomScope, statusLifecycle, contributors)) + + val result = kotlin.runCatching { roomLifecycle.retry(messagesContributor) } + Assert.assertTrue(result.isSuccess) + Assert.assertEquals(RoomStatus.Attached, statusLifecycle.status) + + Assert.assertEquals(2, capturedDetachedChannels.size) + + Assert.assertEquals("1234::\$chat::\$typingIndicators", capturedDetachedChannels[0].name) + Assert.assertEquals("1234::\$chat::\$reactions", capturedDetachedChannels[1].name) + + Assert.assertEquals(5, capturedAttachedChannels.size) + + Assert.assertEquals("1234::\$chat::\$chatMessages", capturedAttachedChannels[0].name) + Assert.assertEquals("1234::\$chat::\$chatMessages", capturedAttachedChannels[1].name) + Assert.assertEquals("1234::\$chat::\$chatMessages", capturedAttachedChannels[2].name) + Assert.assertEquals("1234::\$chat::\$typingIndicators", capturedAttachedChannels[3].name) + Assert.assertEquals("1234::\$chat::\$reactions", capturedAttachedChannels[4].name) + + assertWaiter { roomLifecycle.atomicCoroutineScope().finishedProcessing } } }