@@ -29,11 +29,13 @@ import kotlin.time.Duration.Companion.milliseconds
2929import kotlin.time.Duration.Companion.minutes
3030import kotlin.time.Duration.Companion.seconds
3131import kotlinx.coroutines.Dispatchers
32+ import kotlinx.coroutines.async
3233import kotlinx.coroutines.delay
3334import kotlinx.coroutines.flow.Flow
3435import kotlinx.coroutines.flow.collect
3536import kotlinx.coroutines.flow.emptyFlow
3637import kotlinx.coroutines.flow.filter
38+ import kotlinx.coroutines.flow.filterIsInstance
3739import kotlinx.coroutines.flow.first
3840import kotlinx.coroutines.flow.take
3941import kotlinx.coroutines.launch
@@ -515,4 +517,146 @@ internal class TwoMediaProductsPlayLogTest {
515517 },
516518 )
517519 }
520+
521+ @Suppress(" CyclomaticComplexMethod" , " LongMethod" )
522+ @Test
523+ fun playAndDoALot () = runTest {
524+ val gson = Gson ()
525+ val payloadCaptor = argumentCaptor<String >()
526+
527+ player.playbackEngine.load(mediaProduct1)
528+ player.playbackEngine.play()
529+ withContext(Dispatchers .Default .limitedParallelism(1 )) {
530+ delay(2 .seconds)
531+ while (player.playbackEngine.assetPosition < 2 ) {
532+ delay(10 .milliseconds)
533+ }
534+ player.playbackEngine.pause()
535+ player.playbackEngine.seek(3_000F )
536+ player.playbackEngine.play()
537+ player.playbackEngine.setNext(mediaProduct2)
538+ player.playbackEngine.pause()
539+ player.playbackEngine.play()
540+ delay(1 .seconds)
541+ while (player.playbackEngine.assetPosition < 4 ) {
542+ delay(10 .milliseconds)
543+ }
544+ withTimeout(4 .seconds) {
545+ val waitJob = async {
546+ player.playbackEngine.events
547+ .filter { it is Event .MediaProductTransition }
548+ .first()
549+ }
550+ player.playbackEngine.skipToNext()
551+ waitJob.await()
552+ }
553+ player.playbackEngine.seek(58_000F )
554+ player.playbackEngine.setRepeatOne(true )
555+ withTimeout(10 .seconds) {
556+ player.playbackEngine
557+ .events
558+ .filterIsInstance<Event .MediaProductTransition >()
559+ .first()
560+ }
561+ delay(1 .seconds)
562+ while (player.playbackEngine.assetPosition < 1 ) {
563+ delay(10 .milliseconds)
564+ }
565+ player.playbackEngine.reset()
566+ }
567+
568+ eventReporterCoroutineScope.advanceUntilIdle()
569+ verify(eventSender, times(3 )).sendEvent(
570+ eq(" playback_session" ),
571+ eq(ConsentCategory .NECESSARY ),
572+ payloadCaptor.capture(),
573+ eq(emptyMap()),
574+ )
575+ payloadCaptor.allValues.map {
576+ gson.fromJson(it, JsonObject ::class .java)[" payload" ].asJsonObject
577+ }.combinedPassAllOf(
578+ 1 to {
579+ assertThat(get(" startAssetPosition" ).asDouble).isAssetPositionEqualTo(0.0 )
580+ assertThat(get(" endAssetPosition" ).asDouble).isAssetPositionEqualTo(4.0 )
581+ assertThat(get(" actualProductId" )?.asString).isEqualTo(mediaProduct1.productId)
582+ assertThat(get(" sourceType" )?.asString).isEqualTo(mediaProduct1.sourceType)
583+ assertThat(get(" sourceId" )?.asString).isEqualTo(mediaProduct1.sourceId)
584+ with (get(" actions" ).asJsonArray) {
585+ val firstStopAction =
586+ gson.fromJson(this [0 ], PlaybackSession .Payload .Action ::class .java)
587+ val firstStartAction =
588+ gson.fromJson(this [1 ], PlaybackSession .Payload .Action ::class .java)
589+ val perfectFirstResumeTimestamp = firstStopAction.timestamp
590+ val secondStopAction =
591+ gson.fromJson(this [2 ], PlaybackSession .Payload .Action ::class .java)
592+ val secondStartAction =
593+ gson.fromJson(this [3 ], PlaybackSession .Payload .Action ::class .java)
594+ val perfectSecondResumeTimestamp = secondStopAction.timestamp
595+ assertThat(firstStopAction.actionType)
596+ .isEqualTo(PlaybackSession .Payload .Action .Type .PLAYBACK_STOP )
597+ assertThat(firstStopAction.assetPositionSeconds)
598+ .isAssetPositionEqualTo(2.0 )
599+ assertThat(firstStartAction.actionType)
600+ .isEqualTo(PlaybackSession .Payload .Action .Type .PLAYBACK_START )
601+ assertThat(firstStartAction.assetPositionSeconds)
602+ .isAssetPositionEqualTo(3.0 )
603+ assertThat(firstStartAction.timestamp)
604+ .isBetween(
605+ perfectFirstResumeTimestamp - 500 ,
606+ perfectFirstResumeTimestamp + 500 ,
607+ )
608+ assertThat(secondStopAction.actionType)
609+ .isEqualTo(PlaybackSession .Payload .Action .Type .PLAYBACK_STOP )
610+ assertThat(secondStopAction.assetPositionSeconds)
611+ .isAssetPositionEqualTo(3.0 )
612+ assertThat(secondStartAction.actionType)
613+ .isEqualTo(PlaybackSession .Payload .Action .Type .PLAYBACK_START )
614+ assertThat(secondStartAction.assetPositionSeconds)
615+ .isAssetPositionEqualTo(3.0 )
616+ assertThat(firstStartAction.timestamp)
617+ .isBetween(
618+ perfectSecondResumeTimestamp - 500 ,
619+ perfectSecondResumeTimestamp + 500 ,
620+ )
621+ }
622+ },
623+ 1 to {
624+ assertThat(get(" startAssetPosition" ).asDouble).isAssetPositionEqualTo(0.0 )
625+ assertThat(get(" endAssetPosition" ).asDouble)
626+ .isAssetPositionEqualTo(MEDIA_PRODUCT_2_DURATION_SECONDS )
627+ assertThat(get(" actualProductId" )?.asString).isEqualTo(mediaProduct2.productId)
628+ assertThat(get(" sourceType" )?.asString).isEqualTo(mediaProduct2.sourceType)
629+ assertThat(get(" sourceId" )?.asString).isEqualTo(mediaProduct2.sourceId)
630+ with (get(" actions" ).asJsonArray) {
631+ val stopAction =
632+ gson.fromJson(
633+ this [0 ],
634+ PlaybackSession .Payload .Action ::class .java,
635+ )
636+ val startAction =
637+ gson.fromJson(
638+ this [1 ],
639+ PlaybackSession .Payload .Action ::class .java,
640+ )
641+ val perfectResumeTimestamp = stopAction.timestamp
642+ assertThat(stopAction.actionType)
643+ .isEqualTo(PlaybackSession .Payload .Action .Type .PLAYBACK_STOP )
644+ assertThat(stopAction.assetPositionSeconds).isAssetPositionEqualTo(0.0 )
645+ assertThat(startAction.actionType)
646+ .isEqualTo(PlaybackSession .Payload .Action .Type .PLAYBACK_START )
647+ assertThat(startAction.assetPositionSeconds).isAssetPositionEqualTo(58.0 )
648+ assertThat(startAction.timestamp)
649+ .isBetween(perfectResumeTimestamp - 500 , perfectResumeTimestamp + 500 )
650+ }
651+ },
652+ 1 to {
653+ assertThat(get(" startAssetPosition" ).asDouble).isAssetPositionEqualTo(0.0 )
654+ assertThat(get(" endAssetPosition" ).asDouble).isAssetPositionEqualTo(1.0 )
655+ assertThat(get(" actualProductId" )?.asString).isEqualTo(mediaProduct2.productId)
656+ assertThat(get(" sourceType" )?.asString).isEqualTo(mediaProduct2.sourceType)
657+ assertThat(get(" sourceId" )?.asString).isEqualTo(mediaProduct2.sourceId)
658+ assertThat(get(" actions" ).asJsonArray).isEmpty()
659+ },
660+ )
661+ }
518662}
0 commit comments