diff --git a/app/src/main/kotlin/com/subtracks/data/source/subsonic/SubsonicSource.kt b/app/src/main/kotlin/com/subtracks/data/source/subsonic/SubsonicSource.kt
index 35e9d432..e849b5fd 100644
--- a/app/src/main/kotlin/com/subtracks/data/source/subsonic/SubsonicSource.kt
+++ b/app/src/main/kotlin/com/subtracks/data/source/subsonic/SubsonicSource.kt
@@ -1,5 +1,6 @@
package com.subtracks.data.source.subsonic
+import androidx.annotation.VisibleForTesting
import com.subtracks.data.model.Album
import com.subtracks.data.model.Artist
import com.subtracks.data.model.Playlist
@@ -34,6 +35,7 @@ class SubsonicSource(
private val maxBitrate: Int = 0,
private val streamFormat: String? = null,
private val maxPages: Int = MAX_PAGES,
+ @VisibleForTesting(otherwise = VisibleForTesting.PRIVATE)
private val maxConcurrentFetches: Int = MAX_CONCURRENT_FETCHES,
) : MusicSource {
private var emptyQuerySearchSupported: Boolean? = null
diff --git a/app/src/test/kotlin/com/subtracks/data/source/subsonic/SubsonicSourceTest.kt b/app/src/test/kotlin/com/subtracks/data/source/subsonic/SubsonicSourceTest.kt
index 7e4e7905..4200d135 100644
--- a/app/src/test/kotlin/com/subtracks/data/source/subsonic/SubsonicSourceTest.kt
+++ b/app/src/test/kotlin/com/subtracks/data/source/subsonic/SubsonicSourceTest.kt
@@ -1,6 +1,7 @@
package com.subtracks.data.source.subsonic
-import com.subtracks.data.model.PlaylistSong
+import kotlinx.coroutines.Dispatchers
+import kotlinx.coroutines.async
import kotlinx.coroutines.flow.first
import kotlinx.coroutines.flow.toList
import kotlinx.coroutines.runBlocking
@@ -350,7 +351,8 @@ class SubsonicSourceTest {
val bound = 2
val inFlight = AtomicInteger()
val maxInFlight = AtomicInteger()
- val moreThanBoundStarted = CountDownLatch(bound + 1)
+ val started = CountDownLatch(bound)
+ val release = CountDownLatch(1)
server.dispatcher =
object : Dispatcher() {
override fun dispatch(request: RecordedRequest): MockResponse {
@@ -358,42 +360,29 @@ class SubsonicSourceTest {
if (url.encodedPath != "/rest/getPlaylist.view") return MockResponse().setResponseCode(404)
val current = inFlight.incrementAndGet()
maxInFlight.updateAndGet { maxOf(it, current) }
- moreThanBoundStarted.countDown()
- moreThanBoundStarted.await(300, TimeUnit.MILLISECONDS)
+ started.countDown()
+ release.await(5, TimeUnit.SECONDS)
inFlight.decrementAndGet()
return MockResponse().setBody(playlistResponse(url.queryParameter("id")!!))
}
}
- val entries =
- SubsonicSource(1, client(), maxConcurrentFetches = bound)
- .playlistSongs(listOf("p1", "p2", "p3", "p4"))
- .toList()
- .flatten()
+ val fetching =
+ async(Dispatchers.IO) {
+ SubsonicSource(1, client(), maxConcurrentFetches = bound)
+ .playlistSongs(listOf("p1", "p2", "p3", "p4"))
+ .toList()
+ .flatten()
+ }
+
+ assertTrue("$bound fetches should have started together", started.await(5, TimeUnit.SECONDS))
+ release.countDown()
+ val entries = fetching.await()
assertEquals(12, entries.size)
assertEquals(bound, maxInFlight.get())
}
- @Test
- fun playlistSongsUseTheSameRowsAtAnyFetchBound() =
- runBlocking {
- server.dispatcher =
- object : Dispatcher() {
- override fun dispatch(request: RecordedRequest): MockResponse {
- val url = request.requestUrl!!
- if (url.encodedPath != "/rest/getPlaylist.view") return MockResponse().setResponseCode(404)
- return MockResponse().setBody(playlistResponse(url.queryParameter("id")!!))
- }
- }
- val ids = listOf("p1", "p2", "p3", "p4")
-
- val sequential = SubsonicSource(1, client(), maxConcurrentFetches = 1).playlistSongs(ids).toList().flatten()
- val concurrent = SubsonicSource(1, client(), maxConcurrentFetches = 4).playlistSongs(ids).toList().flatten()
-
- assertEquals(normalized(sequential), normalized(concurrent))
- }
-
@Test
fun albumSongsFetchesSequentiallyWhenTheBoundIsOne() =
runBlocking {
@@ -568,9 +557,6 @@ class SubsonicSourceTest {
(1..3).joinToString("") { "" } +
""
- private fun normalized(entries: List): List =
- entries.sortedWith(compareBy({ it.playlistId }, { it.position }))
-
private fun albumListOf(count: Int) =
"" +
(0 until count).joinToString("") {