Skip to content

Commit 96efc31

Browse files
committed
Add second PlayLog test
1 parent 123080e commit 96efc31

File tree

2 files changed

+91
-5
lines changed

2 files changed

+91
-5
lines changed

player/events/src/main/java/com/tidal/sdk/player/events/model/PlaybackSession.kt

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -34,10 +34,10 @@ sealed class PlaybackSession<T : PlaybackSession.Payload> :
3434
@Keep
3535
@SuppressWarnings("UnusedPrivateMember")
3636
data class Action(
37-
private val timestamp: Long,
37+
val timestamp: Long,
3838
@SerializedName("assetPosition")
39-
private val assetPositionSeconds: Double,
40-
private val actionType: Type,
39+
val assetPositionSeconds: Double,
40+
val actionType: Type,
4141
) {
4242

4343
@Keep

player/src/androidTest/kotlin/com/tidal/sdk/player/playlog/PlayLogTest.kt

Lines changed: 88 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@ import android.app.Application
44
import androidx.test.platform.app.InstrumentationRegistry
55
import assertk.Assert
66
import assertk.assertThat
7+
import assertk.assertions.isBetween
78
import assertk.assertions.isCloseTo
89
import assertk.assertions.isEqualTo
910
import com.google.gson.Gson
@@ -20,14 +21,18 @@ import com.tidal.sdk.player.common.model.MediaProduct
2021
import com.tidal.sdk.player.common.model.ProductType
2122
import com.tidal.sdk.player.events.EventReporterModuleRoot
2223
import com.tidal.sdk.player.events.di.DefaultEventReporterComponent
24+
import com.tidal.sdk.player.events.model.PlaybackSession
2325
import com.tidal.sdk.player.events.playlogtest.PlayLogTestDefaultEventReporterComponentFactory
2426
import com.tidal.sdk.player.events.reflectionComponentFactoryF
2527
import com.tidal.sdk.player.playbackengine.model.Event
2628
import com.tidal.sdk.player.playbackengine.model.Event.MediaProductEnded
2729
import com.tidal.sdk.player.repeatableflakytest.RepeatableFlakyTest
2830
import com.tidal.sdk.player.repeatableflakytest.RepeatableFlakyTestRule
2931
import com.tidal.sdk.player.setBodyFromFile
32+
import kotlin.time.Duration.Companion.milliseconds
33+
import kotlin.time.Duration.Companion.seconds
3034
import kotlinx.coroutines.Dispatchers
35+
import kotlinx.coroutines.delay
3136
import kotlinx.coroutines.flow.Flow
3237
import kotlinx.coroutines.flow.emptyFlow
3338
import kotlinx.coroutines.flow.filter
@@ -137,7 +142,7 @@ class PlayLogTest {
137142
argThat { !contentEquals("playback_session") },
138143
anyOrNull(),
139144
anyOrNull(),
140-
anyOrNull()
145+
anyOrNull(),
141146
)
142147
verifyNoMoreInteractions(eventSender)
143148
}
@@ -163,7 +168,7 @@ class PlayLogTest {
163168
loadAndPlayUntilEnd(MediaProduct(ProductType.TRACK, "1", null, null))
164169

165170
private fun loadAndPlayUntilEnd(mediaProduct: MediaProduct) = runTest {
166-
responseDispatcher [
171+
responseDispatcher[
167172
"https://api.tidal.com/v1/tracks/1/playbackinfo?playbackmode=STREAM&assetpresentation=FULL&audioquality=LOW".toHttpUrl(),
168173
] = {
169174
MockResponse().setBodyFromFile(
@@ -201,6 +206,87 @@ class PlayLogTest {
201206
)
202207
}
203208

209+
@Test
210+
fun loadAndPlayThenPauseThenPlayNoNulls() =
211+
loadAndPlayThenPauseThenPlay(MediaProduct(ProductType.TRACK, "1", "TESTA", "456"))
212+
213+
@Test
214+
fun loadAndPlayThenPauseThenPlayNullSourceType() =
215+
loadAndPlayThenPauseThenPlay(MediaProduct(ProductType.TRACK, "1", null, "789"))
216+
217+
@Test
218+
fun loadAndPlayThenPauseThenPlayNullSourceId() =
219+
loadAndPlayThenPauseThenPlay(MediaProduct(ProductType.TRACK, "1", "TESTB", null))
220+
221+
@Test
222+
fun loadAndPlayThenPauseThenPlayNullSourceTypeNullSourceId() =
223+
loadAndPlayThenPauseThenPlay(MediaProduct(ProductType.TRACK, "1", null, null))
224+
225+
@Suppress("LongMethod")
226+
private fun loadAndPlayThenPauseThenPlay(mediaProduct: MediaProduct) = runTest {
227+
val gson = Gson()
228+
responseDispatcher[
229+
"https://api.tidal.com/v1/tracks/1/playbackinfo?playbackmode=STREAM&assetpresentation=FULL&audioquality=LOW".toHttpUrl(),
230+
] = {
231+
MockResponse().setBodyFromFile(
232+
"api-responses/playbackinfo/tracks/playlogtest/get_1_bts.json",
233+
)
234+
}
235+
responseDispatcher["https://test.audio.tidal.com/1_bts.m4a".toHttpUrl()] = {
236+
MockResponse().setBodyFromFile("raw/playlogtest/1_bts.m4a")
237+
}
238+
239+
player.playbackEngine.load(mediaProduct)
240+
player.playbackEngine.play()
241+
withContext(Dispatchers.Default.limitedParallelism(1)) {
242+
withTimeout(4.seconds) {
243+
player.playbackEngine.events.filter { it is Event.MediaProductTransition }.first()
244+
}
245+
delay(2.seconds)
246+
while (player.playbackEngine.assetPosition < 2) {
247+
delay(10.milliseconds)
248+
}
249+
player.playbackEngine.pause()
250+
delay(1.seconds)
251+
player.playbackEngine.play()
252+
withTimeout(8000) {
253+
player.playbackEngine.events.filter { it is MediaProductEnded }.first()
254+
}
255+
}
256+
257+
eventReporterCoroutineScope.advanceUntilIdle()
258+
verify(eventSender).sendEvent(
259+
eq("playback_session"),
260+
eq(ConsentCategory.NECESSARY),
261+
argThat {
262+
with(gson.fromJson(this, JsonObject::class.java)["payload"].asJsonObject) {
263+
assertThat(get("startAssetPosition").asDouble).isAssetPositionEqualTo(0.0)
264+
assertThat(get("endAssetPosition").asDouble).isAssetPositionEqualTo(5.065)
265+
assertThat(get("actualProductId").asString).isEqualTo(mediaProduct.productId)
266+
assertThat(get("sourceType")?.asString).isEqualTo(mediaProduct.sourceType)
267+
assertThat(get("sourceId")?.asString).isEqualTo(mediaProduct.sourceId)
268+
with(get("actions").asJsonArray) {
269+
val pauseAction =
270+
gson.fromJson(this[0], PlaybackSession.Payload.Action::class.java)
271+
assertThat(pauseAction.actionType)
272+
.isEqualTo(PlaybackSession.Payload.Action.Type.PLAYBACK_STOP)
273+
val resumeAction =
274+
gson.fromJson(this[1], PlaybackSession.Payload.Action::class.java)
275+
assertThat(resumeAction.actionType)
276+
.isEqualTo(PlaybackSession.Payload.Action.Type.PLAYBACK_START)
277+
assertThat(resumeAction.assetPositionSeconds)
278+
.isAssetPositionEqualTo(pauseAction.assetPositionSeconds)
279+
val perfectResumeTimestamp = pauseAction.timestamp + 1_000
280+
assertThat(resumeAction.timestamp)
281+
.isBetween(perfectResumeTimestamp - 500, perfectResumeTimestamp + 500)
282+
}
283+
}
284+
true
285+
},
286+
eq(emptyMap()),
287+
)
288+
}
289+
204290
private fun Assert<Double>.isAssetPositionEqualTo(targetPosition: Double) = run {
205291
isCloseTo(targetPosition, 0.5)
206292
}

0 commit comments

Comments
 (0)