Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
21 changes: 21 additions & 0 deletions .github/workflows/gradle.yml
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@ jobs:
build:
name: "Javaagent Gradle Plugin Validation"
strategy:
fail-fast: false
matrix:
platform: [ubuntu-latest, windows-latest]
runs-on: ${{ matrix.platform }}
Expand All @@ -34,5 +35,25 @@ jobs:
- name: Setup TestLens
uses: testlens-app/setup-testlens@v1

- name: Setup Android test SDK
uses: android-actions/setup-android@v4.0.4
with:
packages: 'platforms;android-36 build-tools;36.0.0'
log-accepted-android-sdk-licenses: false

- name: Execute Gradle build
run: ${{ matrix.platform == 'windows-latest' && '.\gradlew.bat' || './gradlew' }} build

- name: Validate Android Gradle Plugin 8 compatibility
run: ${{ matrix.platform == 'windows-latest' && '.\gradlew.bat' || './gradlew' }} :android:functionalTest "-PandroidTestAgpVersion=8.13.2"

- name: Upload Android test reports
if: always()
uses: actions/upload-artifact@v7.0.2
with:
name: android-test-reports-${{ matrix.platform }}
path: |
android/build/reports/tests/functionalTest/
android/build/test-results/functionalTest/
if-no-files-found: ignore
retention-days: 7
6 changes: 6 additions & 0 deletions .github/workflows/release.yml
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,12 @@ jobs:
with:
cache-read-only: false

- name: Setup Android test SDK
uses: android-actions/setup-android@v4.0.4
with:
packages: 'platforms;android-36 build-tools;36.0.0'
log-accepted-android-sdk-licenses: false

- name: Execute Gradle build
run: ./gradlew build

Expand Down
35 changes: 35 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,41 @@ dependencies {

> ℹ️ **Note:** The [Javaagent Test Plugin](#java-test-task-integration) automatically resolves dependency versions for javaagents dependencies that did not request one from the test runtime classpath.

## Android JVM test integration

The `com.ryandens.javaagent-test-android` plugin (available in the next release) attaches agents to
host-side JVM tests in Android application and library projects. Apply it instead of
`com.ryandens.javaagent-test` in Android modules:

```kotlin
plugins {
id("com.android.application") // or com.android.library, using your project's AGP version
id("com.ryandens.javaagent-test-android") version "<plugin-version>"
}

dependencies {
testImplementation(platform("org.mockito:mockito-bom:5.18.0"))
testImplementation("org.mockito:mockito-core")
testJavaagent("org.mockito:mockito-core")
}
```

Agents declared in `javaagent` are inherited; options on `testJavaagent` can override shared options.
Versionless agents are resolved using each host test variant's runtime classpath, including its
flavor/build-type dependencies and BOM constraints. Custom flavors and build types are discovered
through Android's public Variant API. Either plugin order works, and neither the Java nor Android
plugin is applied implicitly. Device/emulator instrumentation tests and Android app packaging are
unaffected.

Set `javaagentTest { enabled.set(false) }` or `-PjavaagentTestEnabled=false` to disable attachment.
The project property takes precedence. Disabled agents are not resolved.

Compatibility is tested with AGP 8.13.2 / Gradle 9.5 and AGP 9.4.1 / Gradle 9.8.1, including
configuration-cache reuse and Isolated Projects. AGP 8 requires Gradle below 9.6 because it uses
an internal Gradle API removed in 9.6. To run this repository's Android functional tests, set
`ANDROID_HOME` (or `ANDROID_SDK_ROOT`) and install `platforms;android-36` and `build-tools;36.0.0`.
Run the compatibility suite with `./gradlew :android:functionalTest "-PandroidTestAgpVersion=8.13.2"`.

## Application Plugin integration

This Gradle plugin tightly integrates with the [Gradle application plugin](https://docs.gradle.org/current/userguide/application_plugin.html)
Expand Down
66 changes: 66 additions & 0 deletions android/build.gradle.kts
Original file line number Diff line number Diff line change
@@ -0,0 +1,66 @@
import org.gradle.plugin.compatibility.compatibility

plugins {
id("com.ryandens.plugin-conventions")
}

repositories {
google {
content {
includeGroupByRegex("com\\.android.*")
includeGroupByRegex("androidx\\..*")
includeGroup("com.google.testing.platform")
}
}
}

// TestKit injects plugins through a separate classloader: include the matching AGP only for tests.
val androidTestPluginDependencies = configurations.dependencyScope("androidTestPluginDependencies")
val androidTestPlugin =
configurations.resolvable("androidTestPlugin") {
extendsFrom(androidTestPluginDependencies.get())
attributes {
attribute(Usage.USAGE_ATTRIBUTE, objects.named(Usage.JAVA_RUNTIME))
attribute(Category.CATEGORY_ATTRIBUTE, objects.named(Category.LIBRARY))
attribute(LibraryElements.LIBRARY_ELEMENTS_ATTRIBUTE, objects.named(LibraryElements.JAR))
}
}

dependencies {
implementation(project(":plugin"))
compileOnly("com.android.tools.build:gradle-api:8.13.2")
testImplementation("org.jetbrains.kotlin:kotlin-test")
testImplementation("org.jetbrains.kotlin:kotlin-test-junit")
addProvider(
androidTestPluginDependencies.name,
providers.gradleProperty("androidTestAgpVersion").orElse("9.4.1").map { "com.android.tools.build:gradle:$it" },
)
}

tasks.named<PluginUnderTestMetadata>("pluginUnderTestMetadata") {
pluginClasspath.from(androidTestPlugin)
}

gradlePlugin {
plugins {
create("javaagentTestAndroidPlugin") {
id = "com.ryandens.javaagent-test-android"
displayName = "Javaagent Android Test Plugin"
description = "Automatically attaches javaagents to Android host-side JVM tests"
implementationClass = "com.ryandens.javaagent.android.JavaagentTestAndroidPlugin"
tags.set(listOf("javaagent", "instrumentation", "android", "test"))
compatibility {
features { configurationCache = true }
}
}
}
}

tasks.named<Test>("functionalTest") {
testLogging.exceptionFormat = org.gradle.api.tasks.testing.logging.TestExceptionFormat.FULL
inputs
.property(
"androidSdkHome",
providers.environmentVariable("ANDROID_HOME").orElse(providers.environmentVariable("ANDROID_SDK_ROOT")),
).optional(true)
}
Loading
Loading