confirm the end of a full last page before failing the page cap

A full page at the cap is not proof of truncation, so a library whose
size is an exact multiple of the page size failed for no reason. Each
paged loop now keeps going one page past the cap and only throws when
that page comes back non-empty; a library up to the cap syncs normally.
Add a boundary test for the exact-cap case.

Also note the accepted per-batch observer invalidation churn in the sync
code and the architecture doc.
This commit is contained in:
austinried
2026-10-04 00:29:58 +00:00
parent c48ec670d8
commit 7b06b23860
4 changed files with 37 additions and 16 deletions
@@ -203,6 +203,27 @@ class SubsonicSourceTest {
assertEquals(true, failure.exceptionOrNull() is SubsonicException)
}
@Test
fun albumsAtThePageCapSucceedWhenTheNextPageIsEmpty() =
runBlocking {
server.dispatcher =
object : Dispatcher() {
override fun dispatch(request: RecordedRequest): MockResponse {
val url = request.requestUrl!!
if (url.encodedPath != "/rest/getAlbumList2.view") return MockResponse().setResponseCode(404)
if (url.queryParameter("type") != "newest") return MockResponse().setBody(emptyAlbumList())
return when (url.queryParameter("offset")) {
"0", "500" -> MockResponse().setBody(albumPage(url.queryParameter("offset")!!.toInt(), 500))
else -> MockResponse().setBody(emptyAlbumList())
}
}
}
val albums = SubsonicSource(1, client(), maxPages = 2).albums().toList().flatten()
assertEquals(1000, albums.size)
}
@Test
fun playlistEntriesWithoutIdsAreSkipped() =
runBlocking {