test(android): run the sync pass in the test body, not through init's background collector (#5654)
release / govulncheck (push) Successful in 14s
release / web (push) Successful in 1m20s
release / go (push) Successful in 1m37s
release / integration (push) Successful in 5m5s
release / android (push) Successful in 5m10s
release / Build signed APK (releases and dev) (push) Successful in 5m23s
release / Attach APK to the Release (tag releases only) (push) Skipped
release / Build + push container image (push) Successful in 1m20s
release / Verify release artifacts (tag releases only) (push) Skipped

advanceUntilIdle does not count backgroundScope work as pending, so the
pass init would start never ran. The network state is Offline so
construction starts none, and each test calls syncSafe itself and asserts
lastSyncError stays null.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
2026-10-21 08:03:51 -04:00
co-authored by Claude Opus 5.5
parent 77f06b60f7
commit 46e1dd6c9c
@@ -22,6 +22,7 @@ import org.junit.jupiter.api.Test
import retrofit2.Response
import retrofit2.Retrofit
import kotlin.test.assertEquals
import kotlin.test.assertNull
/**
* The server returns at most 1000 changes a call (#5654). One page per
@@ -38,7 +39,8 @@ class SyncControllerTest {
every { sessionCookie } returns MutableStateFlow(null)
}
private val networkStatus: NetworkStatusController = mockk {
every { state } returns MutableStateFlow(ServerHealth.Healthy)
// Offline, so construction starts no pass; each test runs one itself.
every { state } returns MutableStateFlow(ServerHealth.Offline)
}
// The cursor round-trips through the DAO, so it is held for real.
@@ -59,11 +61,13 @@ class SyncControllerTest {
coEvery { api.sync(1000) } returns page(2000, deletedTracks = listOf("merged-away"))
coEvery { api.sync(2000) } returns noContent()
SyncController(
val controller = SyncController(
metadataDao, mockk<CachedArtistDao>(relaxed = true), mockk<CachedAlbumDao>(relaxed = true),
trackDao, authStore, backgroundScope, networkStatus, retrofit,
)
testScheduler.advanceUntilIdle()
controller.syncSafe()
assertNull(controller.lastSyncError.value)
coVerify(exactly = 1) { api.sync(2000) }
coVerify { trackDao.deleteByIds(listOf("merged-away")) }
@@ -75,11 +79,13 @@ class SyncControllerTest {
stored = SyncMetadataEntity(cursor = 500)
coEvery { api.sync(500) } returns page(500)
SyncController(
val controller = SyncController(
metadataDao, mockk<CachedArtistDao>(relaxed = true), mockk<CachedAlbumDao>(relaxed = true),
trackDao, authStore, backgroundScope, networkStatus, retrofit,
)
testScheduler.advanceUntilIdle()
controller.syncSafe()
assertNull(controller.lastSyncError.value)
coVerify(exactly = 1) { api.sync(500) }
}
@@ -91,11 +97,13 @@ class SyncControllerTest {
coEvery { api.sync(0) } returns page(1000)
coEvery { api.sync(1000) } returns noContent()
SyncController(
val controller = SyncController(
metadataDao, mockk<CachedArtistDao>(relaxed = true), mockk<CachedAlbumDao>(relaxed = true),
trackDao, authStore, backgroundScope, networkStatus, retrofit,
)
testScheduler.advanceUntilIdle()
controller.syncSafe()
assertNull(controller.lastSyncError.value)
coVerify(exactly = 1) { api.sync(1000) }
assertEquals(1000L, stored?.cursor)