Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -367,6 +367,11 @@ class OfflineFirstChatRepository @Inject constructor(

while (true) {
delay(INSURANCE_REQUEST_DELAY)
if (itIsPaused) {
// ChatViewModel.onResume fetches right away when the chat comes back to the foreground
Log.d(TAG, "skip insurance request while paused")
continue
}
Log.d(TAG, "execute insurance request")

fetchNewMessages()
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,8 @@ import kotlinx.coroutines.flow.flowOf
import kotlinx.coroutines.launch
import kotlinx.coroutines.runBlocking
import kotlinx.coroutines.flow.toList
import kotlinx.coroutines.test.advanceTimeBy
import kotlinx.coroutines.test.runCurrent
import kotlinx.coroutines.test.runTest
import kotlinx.coroutines.withTimeout
import okhttp3.MediaType.Companion.toMediaType
Expand All @@ -56,6 +58,7 @@ import org.junit.Test
import org.mockito.kotlin.any
import org.mockito.kotlin.argumentCaptor
import org.mockito.kotlin.atLeastOnce
import org.mockito.kotlin.clearInvocations
import org.mockito.kotlin.eq
import org.mockito.kotlin.doSuspendableAnswer
import org.mockito.kotlin.mock
Expand All @@ -76,7 +79,7 @@ import java.io.IOException
* last read message, otherwise the initial window is re-fetched — anchored at the boundary when
* the unread backlog calls for it.
*/
@Suppress("TooManyFunctions")
@Suppress("TooManyFunctions", "LargeClass")
class OfflineFirstChatRepositoryTest {

private val logger: Logger = mock()
Expand Down Expand Up @@ -245,6 +248,45 @@ class OfflineFirstChatRepositoryTest {
assertFalse(fieldMap.containsKey("lastKnownMessageId"))
}

@Test
fun `insurance requests are skipped while the chat is paused`() =
runTest {
givenHttpSyncedAnchor()
clearInvocations(network)
repository.handleOnPause()
val polling = launch { repository.initInsuranceRequests() }

advanceTimeBy(INSURANCE_DELAY_MS * 5 + 1)
runCurrent()

verifyBlocking(network, never()) { pullChatMessages(any(), any(), any()) }
polling.cancelAndJoin()
}

@Test
fun `insurance requests resume with the next tick after the chat is resumed`() =
runTest {
givenHttpSyncedAnchor()
clearInvocations(network)
repository.handleOnPause()
val polling = launch { repository.initInsuranceRequests() }
advanceTimeBy(INSURANCE_DELAY_MS * 3 + 1)
runCurrent()
verifyBlocking(network, never()) { pullChatMessages(any(), any(), any()) }

repository.handleOnResume()
// the loop keeps its normal step: nothing is sent before the next tick ...
advanceTimeBy(INSURANCE_DELAY_MS / 2)
runCurrent()
verifyBlocking(network, never()) { pullChatMessages(any(), any(), any()) }

// ... and the request is sent on it
advanceTimeBy(INSURANCE_DELAY_MS / 2)
runCurrent()
verifyBlocking(network, times(1)) { pullChatMessages(eq(CREDENTIALS), eq(CHAT_URL), any()) }
polling.cancelAndJoin()
}

@Test
fun `fetchNewMessages skips the request when no HTTP-synced anchor exists yet`() =
runTest {
Expand Down Expand Up @@ -862,6 +904,7 @@ class OfflineFirstChatRepositoryTest {
private const val LONG_POLLING_OBSERVATION_MILLIS = 200L
private const val AWAIT_TIMEOUT_MILLIS = 2000L
private const val CHAT_URL = "https://server.example.com/ocs/v2.php/apps/spreed/api/v1/chat/$ROOM_TOKEN"
private const val INSURANCE_DELAY_MS = 2 * 60 * 1000L
private const val MESSAGE_ID = 42L
private const val SYSTEM_MESSAGE_ID = 43L
private const val MESSAGE_URL = "$CHAT_URL/42"
Expand Down
Loading