From 091abad348bc5ff748ec662cf5dbf0990c10446e Mon Sep 17 00:00:00 2001 From: Simon Marquis Date: Sat, 22 Apr 2023 14:14:05 +0100 Subject: [PATCH 1/8] Simplify String resource loading in NavigationTest.kt --- .../apps/nowinandroid/ui/NavigationTest.kt | 46 +++++++------------ 1 file changed, 17 insertions(+), 29 deletions(-) diff --git a/app/src/androidTest/java/com/google/samples/apps/nowinandroid/ui/NavigationTest.kt b/app/src/androidTest/java/com/google/samples/apps/nowinandroid/ui/NavigationTest.kt index a37eb7a77..382bd9a46 100644 --- a/app/src/androidTest/java/com/google/samples/apps/nowinandroid/ui/NavigationTest.kt +++ b/app/src/androidTest/java/com/google/samples/apps/nowinandroid/ui/NavigationTest.kt @@ -16,12 +16,14 @@ package com.google.samples.apps.nowinandroid.ui +import androidx.annotation.StringRes import androidx.compose.ui.test.assertCountEquals import androidx.compose.ui.test.assertIsOn import androidx.compose.ui.test.assertIsSelected import androidx.compose.ui.test.hasAnyAncestor import androidx.compose.ui.test.hasTestTag import androidx.compose.ui.test.hasText +import androidx.compose.ui.test.junit4.AndroidComposeTestRule import androidx.compose.ui.test.junit4.createAndroidComposeRule import androidx.compose.ui.test.onAllNodesWithText import androidx.compose.ui.test.onNodeWithContentDescription @@ -34,10 +36,10 @@ import com.google.samples.apps.nowinandroid.R import dagger.hilt.android.testing.BindValue import dagger.hilt.android.testing.HiltAndroidRule import dagger.hilt.android.testing.HiltAndroidTest -import org.junit.Before import org.junit.Rule import org.junit.Test import org.junit.rules.TemporaryFolder +import kotlin.properties.ReadOnlyProperty import com.google.samples.apps.nowinandroid.feature.bookmarks.R as BookmarksR import com.google.samples.apps.nowinandroid.feature.foryou.R as FeatureForyouR import com.google.samples.apps.nowinandroid.feature.interests.R as FeatureInterestsR @@ -69,35 +71,21 @@ class NavigationTest { @get:Rule(order = 2) val composeTestRule = createAndroidComposeRule() - // The strings used for matching in these tests - private lateinit var done: String - private lateinit var navigateUp: String - private lateinit var forYouLoading: String - private lateinit var forYou: String - private lateinit var interests: String - private lateinit var sampleTopic: String - private lateinit var appName: String - private lateinit var saved: String - private lateinit var settings: String - private lateinit var brand: String - private lateinit var ok: String + private fun AndroidComposeTestRule<*, *>.stringResource(@StringRes resId: Int) = + ReadOnlyProperty { _, _ -> activity.getString(resId) } - @Before - fun setup() { - composeTestRule.activity.apply { - done = getString(FeatureForyouR.string.done) - navigateUp = getString(FeatureForyouR.string.navigate_up) - forYouLoading = getString(FeatureForyouR.string.for_you_loading) - forYou = getString(FeatureForyouR.string.for_you) - interests = getString(FeatureInterestsR.string.interests) - sampleTopic = "Headlines" - appName = getString(R.string.app_name) - saved = getString(BookmarksR.string.saved) - settings = getString(SettingsR.string.top_app_bar_action_icon_description) - brand = getString(SettingsR.string.brand_android) - ok = getString(SettingsR.string.dismiss_dialog_button_text) - } - } + // The strings used for matching in these tests + private val done by composeTestRule.stringResource(FeatureForyouR.string.done) + private val navigateUp by composeTestRule.stringResource(FeatureForyouR.string.navigate_up) + private val forYouLoading by composeTestRule.stringResource(FeatureForyouR.string.for_you_loading) + private val forYou by composeTestRule.stringResource(FeatureForyouR.string.for_you) + private val interests by composeTestRule.stringResource(FeatureInterestsR.string.interests) + private val sampleTopic = "Headlines" + private val appName by composeTestRule.stringResource(R.string.app_name) + private val saved by composeTestRule.stringResource(BookmarksR.string.saved) + private val settings by composeTestRule.stringResource(SettingsR.string.top_app_bar_action_icon_description) + private val brand by composeTestRule.stringResource(SettingsR.string.brand_android) + private val ok by composeTestRule.stringResource(SettingsR.string.dismiss_dialog_button_text) @Test fun firstScreen_isForYou() { From 3a810f015bafc37bbc059c039b5e6a9643849a93 Mon Sep 17 00:00:00 2001 From: Simon Marquis Date: Mon, 24 Apr 2023 20:04:11 +0200 Subject: [PATCH 2/8] Remove unused variables --- .../com/google/samples/apps/nowinandroid/ui/NavigationTest.kt | 2 -- 1 file changed, 2 deletions(-) diff --git a/app/src/androidTest/java/com/google/samples/apps/nowinandroid/ui/NavigationTest.kt b/app/src/androidTest/java/com/google/samples/apps/nowinandroid/ui/NavigationTest.kt index 382bd9a46..5aa3ab02e 100644 --- a/app/src/androidTest/java/com/google/samples/apps/nowinandroid/ui/NavigationTest.kt +++ b/app/src/androidTest/java/com/google/samples/apps/nowinandroid/ui/NavigationTest.kt @@ -75,9 +75,7 @@ class NavigationTest { ReadOnlyProperty { _, _ -> activity.getString(resId) } // The strings used for matching in these tests - private val done by composeTestRule.stringResource(FeatureForyouR.string.done) private val navigateUp by composeTestRule.stringResource(FeatureForyouR.string.navigate_up) - private val forYouLoading by composeTestRule.stringResource(FeatureForyouR.string.for_you_loading) private val forYou by composeTestRule.stringResource(FeatureForyouR.string.for_you) private val interests by composeTestRule.stringResource(FeatureInterestsR.string.interests) private val sampleTopic = "Headlines" From 246d6c652865caabf20678b9b033c506ab4d06a0 Mon Sep 17 00:00:00 2001 From: Simon Marquis Date: Sat, 4 Feb 2023 17:36:56 +0100 Subject: [PATCH 3/8] Use dedicated build step to package test apps before spawning the emulator --- .github/workflows/Build.yaml | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/.github/workflows/Build.yaml b/.github/workflows/Build.yaml index c15daea80..e7a23f358 100644 --- a/.github/workflows/Build.yaml +++ b/.github/workflows/Build.yaml @@ -82,6 +82,9 @@ jobs: - name: Setup Gradle uses: gradle/gradle-build-action@v2 + - name: Build AndroidTest apps + run: ./gradlew packageDemoDebug packageDemoDebugAndroidTest --daemon + - name: Run instrumentation tests uses: reactivecircus/android-emulator-runner@v2 with: @@ -90,7 +93,7 @@ jobs: disable-animations: true disk-size: 6000M heap-size: 600M - script: ./gradlew connectedDemoDebugAndroidTest -x :benchmark:connectedDemoBenchmarkAndroidTest + script: ./gradlew connectedDemoDebugAndroidTest -x :benchmark:connectedDemoBenchmarkAndroidTest --daemon - name: Upload test reports if: always() From a68fe38411c7902b0cee1cd5afb0029e92d2b184 Mon Sep 17 00:00:00 2001 From: Simon Marquis Date: Wed, 26 Apr 2023 23:30:32 +0200 Subject: [PATCH 4/8] Use dedicated build step to package test apps before spawning the emulator --- .github/workflows/AndroidCIWithGmd.yaml | 3 +++ 1 file changed, 3 insertions(+) diff --git a/.github/workflows/AndroidCIWithGmd.yaml b/.github/workflows/AndroidCIWithGmd.yaml index 1c1206ed4..9aa8f2ad9 100644 --- a/.github/workflows/AndroidCIWithGmd.yaml +++ b/.github/workflows/AndroidCIWithGmd.yaml @@ -24,6 +24,9 @@ jobs: - name: Setup Android SDK uses: android-actions/setup-android@v2 + - name: Build AndroidTest apps + run: ./gradlew packageDemoDebug packageDemoDebugAndroidTest + - name: Run instrumented tests with GMD run: ./gradlew cleanManagedDevices --unused-only && ./gradlew ${{ matrix.device-config }}DemoDebugAndroidTest -Dorg.gradle.workers.max=1 From ef27c050b62a0ec2c75fa98ef3b585c72fa0a474 Mon Sep 17 00:00:00 2001 From: Simon Marquis Date: Wed, 26 Apr 2023 22:14:37 +0100 Subject: [PATCH 5/8] Add missing gradle/gradle-build-action setup in AndroidCIWithGmd.yaml This will prevent downloading and unzipping Gradle distribution but fetch it from the cache instead like other workflows. --- .github/workflows/AndroidCIWithGmd.yaml | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/.github/workflows/AndroidCIWithGmd.yaml b/.github/workflows/AndroidCIWithGmd.yaml index 9aa8f2ad9..4c27018c4 100644 --- a/.github/workflows/AndroidCIWithGmd.yaml +++ b/.github/workflows/AndroidCIWithGmd.yaml @@ -15,11 +15,12 @@ jobs: device-config: [ "pixel4api30aospatd", "pixelcapi30aospatd" ] steps: + - uses: actions/checkout@v3 - uses: actions/setup-java@v3 with: distribution: 'zulu' java-version: 17 - - uses: actions/checkout@v3 + - uses: gradle/gradle-build-action@v2 - name: Setup Android SDK uses: android-actions/setup-android@v2 From 4550743fac032677a4947799b47ea1ecb32bc091 Mon Sep 17 00:00:00 2001 From: Simon Marquis Date: Sat, 29 Apr 2023 12:47:48 +0200 Subject: [PATCH 6/8] Create and use CI specific group of GMD devices This should reduce the total CI time of `AndroidCIWithGmd` workflow. Using the matrix strategy at the GitHub Actions level forces us to run the tests sequentially and download/rebuild everything from scratch at each iteration. --- .github/workflows/AndroidCIWithGmd.yaml | 5 +---- .../apps/nowinandroid/GradleManagedDevices.kt | 22 +++++++++++++------ 2 files changed, 16 insertions(+), 11 deletions(-) diff --git a/.github/workflows/AndroidCIWithGmd.yaml b/.github/workflows/AndroidCIWithGmd.yaml index 4c27018c4..80a70834e 100644 --- a/.github/workflows/AndroidCIWithGmd.yaml +++ b/.github/workflows/AndroidCIWithGmd.yaml @@ -10,9 +10,6 @@ jobs: android-ci: runs-on: macos-12 - strategy: - matrix: - device-config: [ "pixel4api30aospatd", "pixelcapi30aospatd" ] steps: - uses: actions/checkout@v3 @@ -30,7 +27,7 @@ jobs: - name: Run instrumented tests with GMD run: ./gradlew cleanManagedDevices --unused-only && - ./gradlew ${{ matrix.device-config }}DemoDebugAndroidTest -Dorg.gradle.workers.max=1 + ./gradlew ciDemoDebugAndroidTest -Dorg.gradle.workers.max=1 -Pandroid.testoptions.manageddevices.emulator.gpu="swiftshader_indirect" -Pandroid.experimental.testOptions.managedDevices.emulator.showKernelLogging=true - name: Upload test reports diff --git a/build-logic/convention/src/main/kotlin/com/google/samples/apps/nowinandroid/GradleManagedDevices.kt b/build-logic/convention/src/main/kotlin/com/google/samples/apps/nowinandroid/GradleManagedDevices.kt index 8129defeb..86e29be33 100644 --- a/build-logic/convention/src/main/kotlin/com/google/samples/apps/nowinandroid/GradleManagedDevices.kt +++ b/build-logic/convention/src/main/kotlin/com/google/samples/apps/nowinandroid/GradleManagedDevices.kt @@ -18,7 +18,7 @@ package com.google.samples.apps.nowinandroid import com.android.build.api.dsl.CommonExtension import com.android.build.api.dsl.ManagedVirtualDevice -import org.gradle.api.Project +import org.gradle.kotlin.dsl.get import org.gradle.kotlin.dsl.invoke /** @@ -27,16 +27,17 @@ import org.gradle.kotlin.dsl.invoke internal fun configureGradleManagedDevices( commonExtension: CommonExtension<*, *, *, *>, ) { - val deviceConfigs = listOf( - DeviceConfig("Pixel 4", 30, "aosp-atd"), - DeviceConfig("Pixel 6", 31, "aosp"), - DeviceConfig("Pixel C", 30, "aosp-atd"), - ) + val pixel4 = DeviceConfig("Pixel 4", 30, "aosp-atd") + val pixel6 = DeviceConfig("Pixel 6", 31, "aosp") + val pixelC = DeviceConfig("Pixel C", 30, "aosp-atd") + + val allDevices = listOf(pixel4, pixel6, pixelC) + val ciDevices = listOf(pixel4, pixelC) commonExtension.testOptions { managedDevices { devices { - deviceConfigs.forEach { deviceConfig -> + allDevices.forEach { deviceConfig -> maybeCreate(deviceConfig.taskName, ManagedVirtualDevice::class.java).apply { device = deviceConfig.device apiLevel = deviceConfig.apiLevel @@ -44,6 +45,13 @@ internal fun configureGradleManagedDevices( } } } + groups { + maybeCreate("ci").apply { + ciDevices.forEach { deviceConfig -> + targetDevices.add(devices[deviceConfig.taskName]) + } + } + } } } } From cd6931d6736c20d7e0046a27219cab43df7c7931 Mon Sep 17 00:00:00 2001 From: Simon Marquis Date: Sat, 29 Apr 2023 14:52:32 +0200 Subject: [PATCH 7/8] Fix instrumented test reports archives - Fixes missing tests reports from `AndroidCIWithGmd.yaml` ``` Warning: No files were found with the provided path: '**/*/build/reports/androidTests/'. No artifacts will be uploaded. ``` - Fixes missing tests reports from `Build.yaml`, where only top-level tests from `:app` were reported. --- .github/workflows/AndroidCIWithGmd.yaml | 3 +-- .github/workflows/Build.yaml | 2 +- 2 files changed, 2 insertions(+), 3 deletions(-) diff --git a/.github/workflows/AndroidCIWithGmd.yaml b/.github/workflows/AndroidCIWithGmd.yaml index 1c1206ed4..f1af37591 100644 --- a/.github/workflows/AndroidCIWithGmd.yaml +++ b/.github/workflows/AndroidCIWithGmd.yaml @@ -34,5 +34,4 @@ jobs: uses: actions/upload-artifact@v3 with: name: test-reports - path: | - '**/*/build/reports/androidTests/' + path: '**/build/reports/androidTests' diff --git a/.github/workflows/Build.yaml b/.github/workflows/Build.yaml index c15daea80..008e1635f 100644 --- a/.github/workflows/Build.yaml +++ b/.github/workflows/Build.yaml @@ -97,4 +97,4 @@ jobs: uses: actions/upload-artifact@v3 with: name: test-reports-${{ matrix.api-level }} - path: '*/build/reports/androidTests' + path: '**/build/reports/androidTests' From 1269b29aee45a282875cf1b94b667f3807633752 Mon Sep 17 00:00:00 2001 From: Simon Marquis Date: Sat, 29 Apr 2023 15:18:36 +0200 Subject: [PATCH 8/8] Fix incomplete build reports - Add all generated lint reports (only app was archived) - Add all unit tests reports (none were archived) - Add all APKs (missing app-nia-catalog) and remove unnecessary files (logs, sdkDependencies, proguard's config/mapping/seeds etc. which are also quite large compared to APKs) --- .github/workflows/Build.yaml | 17 ++++++++++++----- 1 file changed, 12 insertions(+), 5 deletions(-) diff --git a/.github/workflows/Build.yaml b/.github/workflows/Build.yaml index c15daea80..2d94c322e 100644 --- a/.github/workflows/Build.yaml +++ b/.github/workflows/Build.yaml @@ -48,15 +48,22 @@ jobs: - name: Upload build outputs (APKs) uses: actions/upload-artifact@v3 with: - name: build-outputs - path: app/build/outputs + name: APKs + path: '**/build/outputs/apk/**/*.apk' - - name: Upload build reports + - name: Upload lint reports (HTML) if: always() uses: actions/upload-artifact@v3 with: - name: build-reports - path: app/build/reports + name: lint-reports + path: '**/build/reports/lint-results-*.html' + + - name: Upload test results (XML) + if: always() + uses: actions/upload-artifact@v3 + with: + name: test-results + path: '**/build/test-results/test*UnitTest/**.xml' androidTest: needs: build