Skip to content

Commit b9c2e51

Browse files
committed
Migrate Android Tests to Unit Tests
1 parent 903172d commit b9c2e51

File tree

7 files changed

+118
-183
lines changed

7 files changed

+118
-183
lines changed

.github/workflows/quality.yml

Lines changed: 0 additions & 39 deletions
Original file line numberDiff line numberDiff line change
@@ -167,42 +167,3 @@ jobs:
167167
cache-encryption-key: ${{ secrets.GRADLE_CACHE_ENCRYPTION_KEY }}
168168
- name: Generate documentation
169169
run: ./gradlew :dokkaGenerate
170-
171-
android-tests:
172-
name: Android Tests
173-
runs-on: ubuntu-latest
174-
env:
175-
USERNAME: ${{ github.actor }}
176-
GITHUB_TOKEN: ${{ github.token }}
177-
strategy:
178-
matrix:
179-
api-level: [ 26 ]
180-
steps:
181-
- name: Enable KVM
182-
# https://github.blog/changelog/2023-02-23-hardware-accelerated-android-virtualization-on-actions-windows-and-linux-larger-hosted-runners/
183-
run: |
184-
echo 'KERNEL=="kvm", GROUP="kvm", MODE="0666", OPTIONS+="static_node=kvm"' | sudo tee /etc/udev/rules.d/99-kvm4all.rules
185-
sudo udevadm control --reload-rules
186-
sudo udevadm trigger --name-match=kvm
187-
- name: Checkout
188-
uses: actions/checkout@v4
189-
- name: Set up Java
190-
uses: actions/setup-java@v4
191-
with:
192-
java-version: '17'
193-
distribution: 'temurin'
194-
- name: Set up Gradle
195-
uses: gradle/actions/setup-gradle@v4
196-
with:
197-
cache-encryption-key: ${{ secrets.GRADLE_CACHE_ENCRYPTION_KEY }}
198-
- name: Run Android Tests
199-
uses: reactivecircus/android-emulator-runner@v2
200-
with:
201-
api-level: ${{ matrix.api-level }}
202-
arch: x86_64
203-
# Supported tasks per module
204-
# :pillarbox-analytics:connectedDebugAndroidTest
205-
# :pillarbox-core-business:connectedDebugAndroidTest
206-
# :pillarbox-player:connectedDebugAndroidTest
207-
# :pillarbox-ui:connectedDebugAndroidTest
208-
script: ./gradlew :pillarbox-player:connectedDebugAndroidTest

gradle/libs.versions.toml

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,6 @@ androidx-paging = "3.3.6"
1212
androidx-test-core = "1.6.1"
1313
androidx-test-ext-junit = "1.2.1"
1414
androidx-test-monitor = "1.7.2"
15-
androidx-test-runner = "1.6.2"
1615
androidx-tv-material = "1.0.0"
1716
coil = "3.2.0"
1817
comscore = "6.11.1"
@@ -61,7 +60,6 @@ androidx-paging-common = { module = "androidx.paging:paging-common", version.ref
6160
androidx-paging-compose = { module = "androidx.paging:paging-compose", version.ref = "androidx-paging" }
6261
androidx-test-core = { module = "androidx.test:core", version.ref = "androidx-test-core" }
6362
androidx-test-monitor = { module = "androidx.test:monitor", version.ref = "androidx-test-monitor" }
64-
androidx-test-runner = { module = "androidx.test:runner", version.ref = "androidx-test-runner" }
6563
androidx-tv-material = { module = "androidx.tv:tv-material", version.ref = "androidx-tv-material" }
6664
coil = { group = "io.coil-kt.coil3", name = "coil", version.ref = "coil" }
6765
coil-compose = { group = "io.coil-kt.coil3", name = "coil-compose", version.ref = "coil" }

pillarbox-player-testutils/src/main/java/ch/srgssr/pillarbox/player/test/utils/TestPillarboxRunHelper.kt

Lines changed: 34 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -30,7 +30,7 @@ object TestPillarboxRunHelper {
3030
* Runs tasks of the main [Looper] until [Player.Listener.onEvents] matches the
3131
* expected state or a playback error occurs.
3232
*
33-
* <p>If a playback error occurs it will be thrown wrapped in an [IllegalStateException].
33+
* If a playback error occurs, it will be thrown wrapped in an [IllegalStateException].
3434
*
3535
* @param player The [Player].
3636
* @param expectedEvents The expected [Player.Event]. If empty, waits until the first [Player.Listener.onEvents].
@@ -62,7 +62,7 @@ object TestPillarboxRunHelper {
6262
/**
6363
* Runs tasks of the main Looper until [Player.Listener.onPlaybackParametersChanged] is called or a playback error occurs.
6464
*
65-
* <p>If a playback error occurs it will be thrown wrapped in an {@link IllegalStateException}.
65+
* If a playback error occurs, it will be thrown wrapped in an [IllegalStateException].
6666
*
6767
* @param player The [Player].
6868
* @throws TimeoutException If the [RobolectricUtil.DEFAULT_TIMEOUT_MS] is exceeded.
@@ -105,4 +105,36 @@ object TestPillarboxRunHelper {
105105
player.currentPosition >= position.inWholeMilliseconds
106106
}
107107
}
108+
109+
/**
110+
* Run and wait until [Player.isPlaying] is [isPlaying].
111+
112+
* If a playback error occurs, it will be thrown wrapped in an [IllegalStateException].
113+
*
114+
* @param player The [Player].
115+
* @param isPlaying The expected value of [Player.isPlaying].
116+
117+
* @throws TimeoutException If the [RobolectricUtil.DEFAULT_TIMEOUT_MS] is exceeded.
118+
*/
119+
@Throws(TimeoutException::class)
120+
fun runUntilIsPlaying(player: Player, isPlaying: Boolean) {
121+
verifyMainTestThread(player)
122+
if (player is ExoPlayer) {
123+
verifyPlaybackThreadIsAlive(player)
124+
}
125+
val receivedCallback = AtomicBoolean(false)
126+
val listener = object : Player.Listener {
127+
override fun onIsPlayingChanged(actual: Boolean) {
128+
if (actual == isPlaying) {
129+
receivedCallback.set(true)
130+
}
131+
}
132+
}
133+
player.addListener(listener)
134+
RobolectricUtil.runMainLooperUntil { receivedCallback.get() || player.playerError != null }
135+
player.removeListener(listener)
136+
if (player.playerError != null) {
137+
throw IllegalStateException(player.playerError)
138+
}
139+
}
108140
}

pillarbox-player/build.gradle.kts

Lines changed: 1 addition & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -19,16 +19,6 @@ android {
1919
buildFeatures {
2020
buildConfig = true
2121
}
22-
23-
// Mockk includes some licenses information, which may conflict with other license files. This block merges all licenses together.
24-
// Mockk excludes all licenses instead:
25-
// https://github.com/mockk/mockk/blob/f879502a044c83c2a5fd52992f20903209eb34f3/modules/mockk-android/build.gradle.kts#L14-L19
26-
packaging {
27-
resources {
28-
merges += "META-INF/LICENSE.md"
29-
merges += "META-INF/LICENSE-notice.md"
30-
}
31-
}
3222
}
3323

3424
dependencies {
@@ -64,15 +54,8 @@ dependencies {
6454
testImplementation(libs.mockk)
6555
testImplementation(libs.mockk.dsl)
6656
testImplementation(libs.okio)
67-
testRuntimeOnly(libs.robolectric)
57+
testImplementation(libs.robolectric)
6858
testImplementation(libs.robolectric.annotations)
6959
testImplementation(libs.robolectric.shadows.framework)
7060
testImplementation(libs.turbine)
71-
72-
androidTestImplementation(libs.androidx.test.monitor)
73-
androidTestRuntimeOnly(libs.androidx.test.runner)
74-
androidTestImplementation(libs.junit)
75-
androidTestImplementation(libs.kotlin.test)
76-
androidTestRuntimeOnly(libs.kotlinx.coroutines.android)
77-
androidTestImplementation(libs.mockk)
7861
}

pillarbox-player/src/androidTest/java/ch/srgssr/pillarbox/player/IsPlayingAllTypeOfContentTest.kt

Lines changed: 0 additions & 102 deletions
This file was deleted.

pillarbox-player/src/androidTest/java/ch/srgssr/pillarbox/player/utils/ContentUrls.kt

Lines changed: 0 additions & 20 deletions
This file was deleted.
Lines changed: 83 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,83 @@
1+
/*
2+
* Copyright (c) SRG SSR. All rights reserved.
3+
* License information is available from the LICENSE file.
4+
*/
5+
package ch.srgssr.pillarbox.player
6+
7+
import android.net.Uri
8+
import android.os.Looper
9+
import androidx.media3.common.MediaItem
10+
import androidx.media3.common.Player
11+
import androidx.media3.test.utils.FakeClock
12+
import androidx.test.core.app.ApplicationProvider
13+
import ch.srgssr.pillarbox.player.test.utils.TestPillarboxRunHelper
14+
import org.junit.runner.RunWith
15+
import org.robolectric.ParameterizedRobolectricTestRunner
16+
import org.robolectric.ParameterizedRobolectricTestRunner.Parameters
17+
import org.robolectric.Shadows.shadowOf
18+
import kotlin.coroutines.EmptyCoroutineContext
19+
import kotlin.test.AfterTest
20+
import kotlin.test.BeforeTest
21+
import kotlin.test.Test
22+
import kotlin.test.assertEquals
23+
import kotlin.test.assertNotNull
24+
import kotlin.test.assertTrue
25+
26+
@RunWith(ParameterizedRobolectricTestRunner::class)
27+
class IsPlayingAllTypeOfContentTest(
28+
private val urlToTest: String,
29+
) {
30+
private lateinit var player: PillarboxExoPlayer
31+
32+
@BeforeTest
33+
fun setUp() {
34+
player = PillarboxExoPlayer(
35+
context = ApplicationProvider.getApplicationContext(),
36+
type = Default,
37+
) {
38+
clock(FakeClock(true))
39+
coroutineContext(EmptyCoroutineContext)
40+
}
41+
}
42+
43+
@AfterTest
44+
fun tearDown() {
45+
player.release()
46+
47+
shadowOf(Looper.getMainLooper()).idle()
48+
}
49+
50+
@Test
51+
fun `is playing`() {
52+
player.setMediaItem(MediaItem.fromUri(urlToTest))
53+
player.prepare()
54+
player.play()
55+
56+
TestPillarboxRunHelper.runUntilIsPlaying(player, isPlaying = true)
57+
58+
assertEquals(Player.STATE_READY, player.playbackState)
59+
assertTrue(player.isPlaying)
60+
assertNotNull(player.currentMediaItem)
61+
assertEquals(player.currentMediaItem?.localConfiguration?.uri, Uri.parse(urlToTest))
62+
}
63+
64+
companion object {
65+
@JvmStatic
66+
@Suppress("unused", "MaximumLineLength", "MaxLineLength")
67+
@Parameters(name = "{index}: {0}")
68+
fun parameters(): Iterable<Any> {
69+
return listOf(
70+
// From urn:swi:video:48940210
71+
"https://cdn.prod.swi-services.ch/video-projects/141b30ce-3850-424b-9063-a20d5619d342/localised-videos/ENG/renditions/ENG.mp4",
72+
"https://rts-vod-amd.akamaized.net/ww/14970442/da2b38fb-ca9f-3c76-80c6-e6fa7f3c2699/master.m3u8",
73+
"https://storage.googleapis.com/wvmedia/clear/h264/tears/tears.mpd",
74+
"https://storage.googleapis.com/wvmedia/clear/hevc/tears/tears.mpd",
75+
"https://rtsc3video.akamaized.net/hls/live/2042837/c3video/3/playlist.m3u8?dw=0",
76+
"https://rtsc3video.akamaized.net/hls/live/2042837/c3video/3/playlist.m3u8",
77+
"https://download-media.srf.ch/world/audio/Echo_der_Zeit_radio/2025/01/Echo_der_Zeit_radio_AUDI20250119_RS_0069_8a020b8274994bfdbc724cb0c6ed520c.mp3",
78+
"https://stream.srg-ssr.ch/m/la-1ere/mp3_128",
79+
"https://lsaplus.swisstxt.ch/audio/couleur3_96.stream/playlist.m3u8",
80+
)
81+
}
82+
}
83+
}

0 commit comments

Comments
 (0)