From 8a5ddb1bdcd7c3066430cbe607a5d4b6d2b72e4f Mon Sep 17 00:00:00 2001 From: Tim Froehlich Date: Tue, 21 Apr 2026 17:46:49 +0000 Subject: [PATCH] test(oss-licenses): implement comprehensive E2E testing with standalone testapp MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit ## Summary Part 3 of the stacked testing infrastructure update for `oss-licenses-plugin`. ## Key changes - Added a dedicated `src/e2eTest/kotlin/` source set with its own `e2eTestTask` Test task, wired into `check`. - `EndToEndTest.kt` uses GradleTestKit to build the standalone `testapp` against the AGP/Gradle matrix, patching the testapp's `libs.versions.toml` and (for AGP 8.x) the Kotlin block in `app/build.gradle.kts`. - Split the AGP/Gradle version matrix in `build.gradle.kts` into `e2eVersions` (heavier, modern AGPs only) and `integrationOnlyVersions` (older AGPs for backward-compat coverage). - Shared the TestKit task setup (publish dep, repo inputs, `plugin_version` / `testkit_path` / `java21_home` / `repo_path` system properties) between `integrationTestTask` and `e2eTestTask` via a `Test.configureTestKitDefaults()` helper. - Added `oss-licenses-e2e` matrix job to `.github/workflows/oss-licenses.yml`, downloading the local repo artifact from `oss-licenses-build` and running `./gradlew e2eTestTask --tests "…EndToEndTest_AGP_X"`. - Pre-created `$ANDROID_USER_HOME` before `setup-gradle` runs to keep its cache path stable across CI runs (explained in a new comment). - Added keep-in-sync comments between the e2e matrix in the workflow and the `e2eVersions` map. - Minor cleanup: enabled `isShrinkResources` on testapp release; dropped the unused `org.junit.Ignore` import from `OssLicensesV2Test`; removed a stale "CC strictness flags" comment. ## Test plan - [x] `./gradlew :oss-licenses-plugin:check` passes locally across the full integration matrix (AGP 7.4 / 8.7 / 8.12 / 9.x stable / 9.x alpha) and the full e2e matrix (AGP 8.12 / 9.x stable / 9.x alpha). Ran on macOS with `ANDROID_HOME` set. - [ ] CI workflow_call runs green across `oss-licenses-build`, `oss-licenses-integration-test` matrix, and `oss-licenses-e2e` matrix. --- .github/workflows/oss-licenses.yml | 55 +++++- oss-licenses-plugin/GEMINI.md | 22 ++- oss-licenses-plugin/build.gradle.kts | 85 ++++++--- .../gms/oss/licenses/plugin/EndToEndTest.kt | 178 ++++++++++++++++++ .../oss/licenses/plugin/IntegrationTest.kt | 4 +- .../testapp/app/build.gradle.kts | 1 + .../oss/licenses/testapp/OssLicensesV2Test.kt | 9 +- oss-licenses-plugin/testapp/gradle.properties | 2 +- 8 files changed, 316 insertions(+), 40 deletions(-) create mode 100644 oss-licenses-plugin/src/e2eTest/kotlin/com/google/android/gms/oss/licenses/plugin/EndToEndTest.kt diff --git a/.github/workflows/oss-licenses.yml b/.github/workflows/oss-licenses.yml index cc8f8255..addfea8c 100644 --- a/.github/workflows/oss-licenses.yml +++ b/.github/workflows/oss-licenses.yml @@ -28,8 +28,8 @@ jobs: dependency-graph: generate-and-submit - name: Build and run unit tests - # Integration tests live in their own source set + task (integrationTestTask), - # so the default 'test' task only runs the unit suite. + # Integration tests (integrationTestTask) and e2e tests (e2eTestTask) live in + # their own source sets; the default 'test' task only runs the unit suite. run: ./gradlew assemble test working-directory: ./oss-licenses-plugin @@ -49,7 +49,7 @@ jobs: runs-on: ubuntu-latest strategy: fail-fast: false - # Keep this list in sync with the integrationVersions map in + # Keep this list in sync with the integrationOnlyVersions + e2eVersions maps in # oss-licenses-plugin/build.gradle.kts. matrix: agp-version-key: [AGP74, AGP87, AGP812, AGP_STABLE, AGP_ALPHA] @@ -83,11 +83,60 @@ jobs: run: ./gradlew integrationTestTask --tests "com.google.android.gms.oss.licenses.plugin.IntegrationTest_${{ matrix.agp-version-key }}" -x publishAllPublicationsToLocalRepository working-directory: ./oss-licenses-plugin + # Run end-to-end tests: build the full testapp against the AGP/Gradle version matrix. + # Uses the locally-published plugin from oss-licenses-build via -PusePublishedPluginFrom. + oss-licenses-e2e: + needs: oss-licenses-build + runs-on: ubuntu-latest + strategy: + fail-fast: false + # Keep this list in sync with the e2eVersions map in + # oss-licenses-plugin/build.gradle.kts. + matrix: + agp-version-key: [AGP812, AGP_STABLE, AGP_ALPHA] + env: + ANDROID_USER_HOME: /home/runner/.android + steps: + - uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # ratchet:actions/checkout@v6.0.2 + + - name: Download local repo artifact + uses: actions/download-artifact@3e5f45b2cfb9172054b4087a40e8e0b5a5461e7c # ratchet:actions/download-artifact@v8.0.1 + with: + name: oss-licenses-local-repo + path: oss-licenses-plugin/build/repo/ + + - name: Set up JDK 17 + uses: actions/setup-java@be666c2fcd27ec809703dec50e508c2fdc7f6654 # ratchet:actions/setup-java@v5.2.0 + with: + java-version: '17' + distribution: 'temurin' + + - name: Set up JDK 21 + uses: actions/setup-java@be666c2fcd27ec809703dec50e508c2fdc7f6654 # ratchet:actions/setup-java@v5.2.0 + with: + java-version: '21' + distribution: 'temurin' + + - name: Setup Gradle + uses: gradle/actions/setup-gradle@50e97c2cd7a37755bbfafc9c5b7cafaece252f6e # ratchet:gradle/actions/setup-gradle@v6.1.0 + + # setup-gradle's cache-restore step runs before any step creates $ANDROID_USER_HOME, + # and it fails if the directory it's asked to restore into doesn't exist. Pre-creating + # it here keeps the cache path stable across runs. + - name: Pre-create Android SDK cache directory + run: mkdir -p "$ANDROID_USER_HOME/cache" + + - name: Build testapp (verify ${{ matrix.agp-version-key }}) + # Skip the local-repo publish here because we want to use the pre-built plugin from the artifact. + run: ./gradlew e2eTestTask --tests "com.google.android.gms.oss.licenses.plugin.EndToEndTest_${{ matrix.agp-version-key }}" -x publishAllPublicationsToLocalRepository + working-directory: oss-licenses-plugin + # Aggregate status oss-licenses-success: needs: - oss-licenses-build - oss-licenses-integration-test + - oss-licenses-e2e if: always() runs-on: ubuntu-latest steps: diff --git a/oss-licenses-plugin/GEMINI.md b/oss-licenses-plugin/GEMINI.md index 2863077b..6e89f5c7 100644 --- a/oss-licenses-plugin/GEMINI.md +++ b/oss-licenses-plugin/GEMINI.md @@ -4,7 +4,7 @@ This document provides essential information for AI agents and developers workin ## Test Architecture -The project uses a two-tier testing strategy to ensure both internal logic and integration across the Android Gradle Plugin (AGP) and Gradle version matrix. +The project uses a three-tier testing strategy: fast unit tests for task logic, a GradleTestKit integration matrix for plugin-on-Gradle behavior, and heavy end-to-end tests that build the full testapp against the AGP/Gradle matrix. ### 1. Unit Tests (`src/test/`) These tests verify the logic of individual tasks and utility classes. @@ -20,9 +20,18 @@ These tests verify the plugin's integration with the Gradle lifecycle and its be * **File:** `IntegrationTest.kt` * **Mechanism:** Uses `GradleTestKit` (`GradleRunner`) to execute the plugin against a set of static test projects. * **Focus:** Task wiring, Configuration Cache compatibility, and relocatability. -* **Matrix:** Defined in `build.gradle.kts` (`integrationVersions`). +* **Matrix:** Defined in `build.gradle.kts` as `integrationOnlyVersions + e2eVersions` (integration covers the full backward-compat range). * **Execution:** `./gradlew integrationTestTask` (also runs as part of `check`). +### 3. End-to-End Tests (`src/e2eTest/`) +These tests build the full standalone testapp under `testapp/` against multiple AGP/Gradle versions, exercising the plugin from the outside just like a real downstream project. + +* **File:** `EndToEndTest.kt` +* **Mechanism:** Uses `GradleTestKit` to run `./gradlew build` inside a copy of `testapp/` whose `libs.versions.toml` has been patched to the matrix-selected AGP (and, on AGP 8.x, the Kotlin block in `app/build.gradle.kts` is rewritten to the legacy KGP form). +* **Focus:** Real consumer build — verifies the testapp compiles, resources shrink, and the plugin integrates cleanly. +* **Matrix:** Defined in `build.gradle.kts` as `e2eVersions` (modern AGP only — the e2e path is heavy). +* **Execution:** `./gradlew e2eTestTask` (also runs as part of `check`). + --- ## Testing Infrastructure & Matrix @@ -31,9 +40,9 @@ The complexity of testing across multiple AGP/Gradle versions is managed through ### Centralized Version Matrix The `build.gradle.kts` file is the **single source of truth** for all versions. -* It defines a map (`integrationVersions`) of version pairs. -* It configures the manually declared test subclasses by injecting these version values as **system properties** (e.g., `IntegrationTest_AGP74.agpVersion`). -* To add a new version to the matrix: Add the entry to the map in `build.gradle.kts` and create the corresponding empty subclass in `IntegrationTest.kt`. +* It defines two maps of version pairs: `e2eVersions` (modern AGPs exercised by both integration and e2e) and `integrationOnlyVersions` (older AGPs kept for backward-compat coverage, integration-only). +* It configures the manually declared test subclasses by injecting these version values as **system properties** (e.g., `IntegrationTest_AGP74.agpVersion`, `EndToEndTest_AGP_STABLE.gradleVersion`). +* To add a new version: add the entry to `e2eVersions` (if it should run e2e) or `integrationOnlyVersions` (integration-only), then create the matching empty subclass in `IntegrationTest.kt` and/or `EndToEndTest.kt`. Keep the key in sync with the `agp-version-key` matrices in `.github/workflows/oss-licenses.yml`. ### Test Isolation To allow safe parallel execution, each test subclass uses a dedicated `TestKit` directory (set via `.withTestKitDir()`). This prevents different AGP versions from clobbering each other's Gradle User Home caches. @@ -47,7 +56,8 @@ To ensure tests run consistently regardless of the host environment, the build s | Task | Command | Description | | :--- | :--- | :--- | -| **Full Check** | `./gradlew check` | Runs unit tests and the full integration matrix. | +| **Full Check** | `./gradlew check` | Runs unit, integration, and e2e matrices. | | **Unit only** | `./gradlew test` | Runs internal plugin unit tests only. | | **Integration only** | `./gradlew integrationTestTask` | Runs the GradleTestKit integration matrix. | +| **E2E only** | `./gradlew e2eTestTask` | Runs the testapp build e2e matrix. Requires `ANDROID_HOME` or a `local.properties` with `sdk.dir=`. | | **Publish** | `./gradlew publishAllPublicationsToLocalRepository` | Publishes the plugin to the internal `build/repo`. | diff --git a/oss-licenses-plugin/build.gradle.kts b/oss-licenses-plugin/build.gradle.kts index e6531f0d..e59d3fe0 100644 --- a/oss-licenses-plugin/build.gradle.kts +++ b/oss-licenses-plugin/build.gradle.kts @@ -71,18 +71,23 @@ dependencies { // AGP/Gradle version matrix — single source of truth for all GradleTestKit tests. // Each entry maps a test subclass name to its (AGP, Gradle) version pair. // The versions are injected as system properties so the test files contain no hardcoded versions. -// Keep the keys in sync with the agp-version-key matrix in +// Keep the keys in sync with the agp-version-key matrices in // .github/workflows/oss-licenses.yml. -val integrationVersions = mapOf( - "AGP74" to ("7.4.2" to "7.5.1"), // oldest supported - "AGP87" to ("8.7.3" to "8.9"), // mainstream - "AGP812" to ("8.12.2" to "8.14.1"), // latest stable 8.x - "AGP_STABLE" to ("9.0.1" to "9.1.0"), // latest stable 9.x - "AGP_ALPHA" to ("9.2.0-alpha02" to "9.4.0"), // latest alpha +// E2E versions are a subset of the integration versions. Integration tests extend the E2E set +// with older AGP versions to ensure broad backward compatibility. +val e2eVersions = mapOf( + "AGP812" to ("8.12.2" to "8.14.1"), // latest stable 8.x + "AGP_STABLE" to ("9.1.1" to "9.4.1"), // latest stable 9.x + "AGP_ALPHA" to ("9.3.0-alpha01" to "9.5.0-rc-3"), // latest alpha +) +val integrationOnlyVersions = mapOf( + "AGP74" to ("7.4.2" to "7.5.1"), // oldest supported + "AGP87" to ("8.7.3" to "8.9"), // mainstream mid-range ) // Build the full maps with class-name prefixes -val integrationTestVersions = integrationVersions.mapKeys { "IntegrationTest_${it.key}" } +val e2eTestVersions = e2eVersions.mapKeys { "EndToEndTest_${it.key}" } +val integrationTestVersions = (e2eVersions + integrationOnlyVersions).mapKeys { "IntegrationTest_${it.key}" } // Separate source set for GradleTestKit integration tests that run the plugin // against the AGP/Gradle matrix. Keeps the default 'test' task fast. @@ -112,15 +117,11 @@ tasks.withType().configureEach { } } -val integrationTestTask by tasks.registering(Test::class) { - description = "Runs GradleTestKit integration tests against the AGP/Gradle version matrix" - group = "verification" - testClassesDirs = integrationTest.output.classesDirs - classpath = integrationTest.runtimeClasspath - +// Common TestKit setup: both integration and e2e tasks spawn GradleRunner instances +// that need the locally-published plugin, a Java 21 toolchain path for newer AGP, and +// a repo_path pointing at the local publication directory. +fun Test.configureTestKitDefaults() { val localRepo = repo - // Prepare the path to the Java 21 JVM used by the main build to inject into the - // integration test's environment. Required for some AGP versions (9.0+) val javaToolchains = project.extensions.getByType() val java21Home = javaToolchains.launcherFor { languageVersion.set(JavaLanguageVersion.of(21)) @@ -139,25 +140,63 @@ val integrationTestTask by tasks.registering(Test::class) { ).withPathSensitivity(PathSensitivity.RELATIVE).withPropertyName("repo") val localVersion = project.version.toString() - systemProperties["plugin_version"] = localVersion // value used by IntegrationTest.kt - // Point TestKit to a directory inside the host Gradle User Home so it can be cached by CI (setup-gradle) + systemProperties["plugin_version"] = localVersion + // Point TestKit to a directory inside the host Gradle User Home so it can be cached by CI (setup-gradle). systemProperties["testkit_path"] = File(System.getProperty("user.home"), ".gradle/testkit").absolutePath doFirst { // Resolved inside doFirst so contributors without JDK 21 can still run ./gradlew help, tasks, etc. // — the toolchain is only required when a Test task actually executes. - systemProperties["java21_home"] = java21Home.get() // value used by IntegrationTest.kt - // Inside doFirst to make sure that absolute path is not considered to be input to the task - systemProperties["repo_path"] = localRepo.get().asFile.absolutePath // value used by IntegrationTest.kt + systemProperties["java21_home"] = java21Home.get() + // Inside doFirst to keep absolute paths out of the task input fingerprint. + systemProperties["repo_path"] = localRepo.get().asFile.absolutePath } +} - // Inject AGP/Gradle version pairs as system properties for each test subclass +val integrationTestTask by tasks.registering(Test::class) { + description = "Runs GradleTestKit integration tests against the AGP/Gradle version matrix" + group = "verification" + testClassesDirs = integrationTest.output.classesDirs + classpath = integrationTest.runtimeClasspath + + configureTestKitDefaults() + + // Inject AGP/Gradle version pairs as system properties for each integration test subclass. integrationTestVersions.forEach { (className, versions) -> systemProperties["$className.agpVersion"] = versions.first systemProperties["$className.gradleVersion"] = versions.second } } -tasks.named("check") { dependsOn(integrationTestTask) } +// Separate source set for heavy E2E tests that build the full testapp against multiple AGP versions. +// Lives in src/e2eTest/kotlin/ — fully independent from the unit/integration test source set. +val e2eTest by sourceSets.creating { + compileClasspath += sourceSets.main.get().output + runtimeClasspath += sourceSets.main.get().output +} + +configurations[e2eTest.implementationConfigurationName].extendsFrom(configurations.testImplementation.get()) +configurations[e2eTest.runtimeOnlyConfigurationName].extendsFrom(configurations.testRuntimeOnly.get()) + +dependencies { + "e2eTestImplementation"(gradleTestKit()) +} + +val e2eTestTask by tasks.registering(Test::class) { + description = "Runs end-to-end tests that build the full testapp against multiple AGP versions" + group = "verification" + testClassesDirs = e2eTest.output.classesDirs + classpath = e2eTest.runtimeClasspath + + configureTestKitDefaults() + + // Inject AGP/Gradle version pairs as system properties for each e2e subclass. + e2eTestVersions.forEach { (className, versions) -> + systemProperties["$className.agpVersion"] = versions.first + systemProperties["$className.gradleVersion"] = versions.second + } +} + +tasks.named("check") { dependsOn(integrationTestTask, e2eTestTask) } publishing { repositories { diff --git a/oss-licenses-plugin/src/e2eTest/kotlin/com/google/android/gms/oss/licenses/plugin/EndToEndTest.kt b/oss-licenses-plugin/src/e2eTest/kotlin/com/google/android/gms/oss/licenses/plugin/EndToEndTest.kt new file mode 100644 index 00000000..6d9cd727 --- /dev/null +++ b/oss-licenses-plugin/src/e2eTest/kotlin/com/google/android/gms/oss/licenses/plugin/EndToEndTest.kt @@ -0,0 +1,178 @@ +/* + * Copyright 2025-2026 Google LLC + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * https://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.google.android.gms.oss.licenses.plugin + +import org.gradle.testkit.runner.GradleRunner +import org.gradle.testkit.runner.TaskOutcome +import org.junit.Assert +import org.junit.Before +import org.junit.Rule +import org.junit.Test +import org.junit.rules.TemporaryFolder +import java.io.File + +/** + * E2E test that builds the standalone testapp against multiple AGP/Gradle versions. + */ +abstract class EndToEndTest { + + // AGP and Gradle versions are defined in build.gradle.kts (single source of truth) and injected + // as system properties keyed by class name. E.g., EndToEndTest_AGP812 reads the system + // properties "EndToEndTest_AGP812.agpVersion" and "EndToEndTest_AGP812.gradleVersion". + // To add a new version: add an entry to e2eVersions in build.gradle.kts and a subclass here + // whose name matches the map key (prefixed with "EndToEndTest_"). + private val agpVersion: String = System.getProperty("${javaClass.simpleName}.agpVersion") + ?: error("Missing ${javaClass.simpleName}.agpVersion — add to e2eVersions in build.gradle.kts") + private val gradleVersion: String = System.getProperty("${javaClass.simpleName}.gradleVersion") + ?: error("Missing ${javaClass.simpleName}.gradleVersion — add to e2eVersions in build.gradle.kts") + + companion object { + private val AGP_VERSION_REGEX = Regex("""agp = ".*"""") + private val KOTLIN_VERSION_REGEX = Regex("""kotlin = ".*"""") + + // Files to copy from the testapp source into the temp project directory + private val TESTAPP_ALLOW_LIST = listOf( + "app", "gradle", "build.gradle.kts", "settings.gradle.kts", "gradle.properties", + "gradlew", "gradlew.bat" + ) + + // AGP 9+ has built-in Kotlin support; AGP 8.x requires the standalone KGP with legacy config. + private val AGP_9_KOTLIN_BLOCK = """ + kotlin { + jvmToolchain(21) + compilerOptions { jvmTarget.set(org.jetbrains.kotlin.gradle.dsl.JvmTarget.JVM_21) } + } + """.trimIndent() + + private val AGP_8_KOTLIN_BLOCK = """ + tasks.withType().configureEach { + @Suppress("DEPRECATION") + kotlinOptions { + jvmTarget = "21" + } + } + """.trimIndent() + } + + @get:Rule + val tempDirectory: TemporaryFolder = TemporaryFolder() + + private lateinit var projectDir: File + + @Before + fun setup() { + projectDir = tempDirectory.newFolder("testapp") + + val currentDir = File(System.getProperty("user.dir")!!) // if this is missing then something is very wrong + val testAppSourceDir = File(currentDir, "testapp") + require(testAppSourceDir.exists()) { + "Test app source not found at: ${testAppSourceDir.absolutePath}" + } + + configureAndroidSdk(currentDir) + copyTestApp(testAppSourceDir) + + // Remove the Gradle daemon JVM file — the JAVA_HOME injection in createRunner() handles + // JVM selection more cleanly across all Gradle versions. + File(projectDir, "gradle/gradle-daemon-jvm.properties").delete() + + patchVersions() + } + + private fun configureAndroidSdk(currentDir: File) { + val sdkDir = System.getenv("ANDROID_HOME") + ?: File(currentDir, "local.properties").takeIf { it.exists() } + ?.readLines()?.firstOrNull { it.startsWith("sdk.dir=") } + ?.substringAfter("sdk.dir=") + ?: error("Cannot find Android SDK: set ANDROID_HOME or create local.properties") + File(projectDir, "local.properties").writeText("sdk.dir=${sdkDir.replace("\\", "\\\\")}\n") + } + + private fun copyTestApp(sourceDir: File) { + TESTAPP_ALLOW_LIST + .map { sourceDir.resolve(it) } + .filter { it.exists() } + .forEach { it.copyRecursively(projectDir.resolve(it.name), overwrite = true) } + } + + private fun patchVersions() { + val agpBundlesKgp = agpVersion.substringBefore('.').toIntOrNull()?.let { it >= 9 } ?: false + + // Patch AGP (and optionally Kotlin) version in the version catalog + val tomlFile = File(projectDir, "gradle/libs.versions.toml") + var tomlContent = tomlFile.readText() + check(AGP_VERSION_REGEX.containsMatchIn(tomlContent)) { + "libs.versions.toml missing expected 'agp = \"...\"' entry — has the testapp template changed?" + } + tomlContent = tomlContent.replace(AGP_VERSION_REGEX, "agp = \"$agpVersion\"") + if (!agpBundlesKgp) { + check(KOTLIN_VERSION_REGEX.containsMatchIn(tomlContent)) { + "libs.versions.toml missing expected 'kotlin = \"...\"' entry — has the testapp template changed?" + } + tomlContent = tomlContent.replace(KOTLIN_VERSION_REGEX, "kotlin = \"2.1.10\"") + } + tomlFile.writeText(tomlContent) + + // AGP 8.x doesn't have built-in Kotlin support — replace with standalone KGP config + if (!agpBundlesKgp) { + val buildFile = File(projectDir, "app/build.gradle.kts") + val original = buildFile.readText() + val patched = original.replace(AGP_9_KOTLIN_BLOCK, AGP_8_KOTLIN_BLOCK) + check(patched != original) { + "Failed to patch Kotlin block in app/build.gradle.kts — has the testapp template changed?" + } + buildFile.writeText(patched) + } + } + + private fun createRunner(vararg arguments: String): GradleRunner { + // -PusePublishedPluginFrom forces the testapp to resolve the plugin from the locally-published + // Maven repo (see testapp/settings.gradle.kts). Without it, includeBuild("..") points at the + // temp folder's parent, falls through silently, and Gradle resolves the "+" version from + // Google Maven — meaning the test runs against the published plugin, not the local build. + val runner = GradleRunner.create() + .withProjectDir(projectDir) + .withGradleVersion(gradleVersion) + .withTestKitDir(File(System.getProperty("testkit_path"), this.javaClass.simpleName)) + .forwardOutput() + .withArguments( + *arguments, + "-PusePublishedPluginFrom=${System.getProperty("repo_path")}", + "--configuration-cache", "--parallel", + "-Dorg.gradle.configuration-cache.problems=fail", "-s" + ) + + val javaHome = System.getProperty("java21_home") + if (javaHome != null) { + // Merge with the host environment — withEnvironment() replaces it entirely, so a bare + // map of {JAVA_HOME} would strip PATH, ANDROID_HOME, HOME, etc. from the forked Gradle. + runner.withEnvironment(System.getenv() + mapOf("JAVA_HOME" to javaHome)) + } + return runner + } + + @Test + fun testBuildSucceeds() { + val result = createRunner("build").build() + Assert.assertEquals(TaskOutcome.SUCCESS, result.task(":app:build")?.outcome) + } +} + +// Due to the dependency requirements of the library, we can only test with recent versions of AGP +class EndToEndTest_AGP812 : EndToEndTest() +class EndToEndTest_AGP_STABLE : EndToEndTest() +class EndToEndTest_AGP_ALPHA : EndToEndTest() diff --git a/oss-licenses-plugin/src/integrationTest/kotlin/com/google/android/gms/oss/licenses/plugin/IntegrationTest.kt b/oss-licenses-plugin/src/integrationTest/kotlin/com/google/android/gms/oss/licenses/plugin/IntegrationTest.kt index 7ac8467a..b80b976a 100644 --- a/oss-licenses-plugin/src/integrationTest/kotlin/com/google/android/gms/oss/licenses/plugin/IntegrationTest.kt +++ b/oss-licenses-plugin/src/integrationTest/kotlin/com/google/android/gms/oss/licenses/plugin/IntegrationTest.kt @@ -36,13 +36,13 @@ abstract class IntegrationTest { ?: error( "Missing ${javaClass.simpleName}.agpVersion — run this test via Gradle so version " + "properties are injected, or set the system property manually. If this is a new " + - "test variant, add it to integrationVersions in build.gradle.kts" + "test variant, add it to integrationOnlyVersions or e2eVersions in build.gradle.kts" ) private val gradleVersion: String = System.getProperty("${javaClass.simpleName}.gradleVersion") ?: error( "Missing ${javaClass.simpleName}.gradleVersion — run this test via Gradle so version " + "properties are injected, or set the system property manually. If this is a new " + - "test variant, add it to integrationVersions in build.gradle.kts" + "test variant, add it to integrationOnlyVersions or e2eVersions in build.gradle.kts" ) @get:Rule diff --git a/oss-licenses-plugin/testapp/app/build.gradle.kts b/oss-licenses-plugin/testapp/app/build.gradle.kts index b4226877..bc5a60bb 100644 --- a/oss-licenses-plugin/testapp/app/build.gradle.kts +++ b/oss-licenses-plugin/testapp/app/build.gradle.kts @@ -44,6 +44,7 @@ android { release { signingConfig = signingConfigs.getByName("debug") isMinifyEnabled = true + isShrinkResources = true proguardFiles(getDefaultProguardFile("proguard-android-optimize.txt")) } } diff --git a/oss-licenses-plugin/testapp/app/src/testRelease/java/com/google/android/gms/oss/licenses/testapp/OssLicensesV2Test.kt b/oss-licenses-plugin/testapp/app/src/testRelease/java/com/google/android/gms/oss/licenses/testapp/OssLicensesV2Test.kt index 465b44f0..65997aa5 100644 --- a/oss-licenses-plugin/testapp/app/src/testRelease/java/com/google/android/gms/oss/licenses/testapp/OssLicensesV2Test.kt +++ b/oss-licenses-plugin/testapp/app/src/testRelease/java/com/google/android/gms/oss/licenses/testapp/OssLicensesV2Test.kt @@ -28,7 +28,6 @@ import android.util.TypedValue import com.google.android.gms.oss.licenses.v2.OssLicensesMenuActivity import org.junit.Assert.assertEquals import org.junit.Assert.assertTrue -import org.junit.Ignore import org.junit.Rule import org.junit.Test import org.junit.runner.RunWith @@ -86,8 +85,6 @@ class OssLicensesV2Test { } } - - @Test fun testV2ActivitySetActivityTitle() { val customTitle = "Test Title via API" @@ -108,13 +105,15 @@ class OssLicensesV2Test { val typedValue = TypedValue() val theme = activity.theme val success = theme.resolveAttribute(android.R.attr.windowBackground, typedValue, true) - + assertTrue("Failed to resolve windowBackground attribute", success) - + // The expected color is #FCE4EC (Light Pink) defined in Theme.CustomOssThemeV2 val expectedColor = Color.parseColor("#FCE4EC") assertEquals("Theme background color mismatch", expectedColor, typedValue.data) } } } + + } diff --git a/oss-licenses-plugin/testapp/gradle.properties b/oss-licenses-plugin/testapp/gradle.properties index a8a5a6a3..053a516f 100644 --- a/oss-licenses-plugin/testapp/gradle.properties +++ b/oss-licenses-plugin/testapp/gradle.properties @@ -28,7 +28,7 @@ org.gradle.jvmargs=-Xmx2048m -Dfile.encoding=UTF-8 com.google.protobuf.use_unsafe_pre22_gencode=true # AGP 9.0's built-in Kotlin is incompatible with the kotlin-android plugin, which -# is required for AGP 8.x backward compatibility in TestAppEndToEndTest. +# is required for AGP 8.x backward compatibility in EndToEndTest. # These opt-outs are removed in AGP 10.0 — drop AGP 8.x from the test matrix then. android.builtInKotlin=false android.newDsl=false