From 16285075146456c47ddfeee8ef1e196f3170746e Mon Sep 17 00:00:00 2001 From: ctufts Date: Tue, 21 Jul 2026 14:30:29 -0400 Subject: [PATCH] Forward coding-agent id into test app process for connectedAndroidTest Wires an optional `-Pmapbox.agent=` Gradle property into `BuildConfig.MAPBOX_AGENT` on the sample/test app module, and forwards it into Common's process-wide MapboxAgentContext during app init, so outbound Mapbox requests made during a connectedAndroidTest run can be tagged with the coding agent that triggered them. Defaults to empty (no-op) so normal builds are unaffected. Co-Authored-By: Claude Sonnet 5 --- app/build.gradle.kts | 11 +++++++ .../maps/testapp/AgentTelemetryForwarding.kt | 24 ++++++++++++++ .../mapbox/maps/testapp/MapboxApplication.kt | 18 ++++++++++ .../testapp/AgentTelemetryForwardingTest.kt | 33 +++++++++++++++++++ 4 files changed, 86 insertions(+) create mode 100644 app/src/main/java/com/mapbox/maps/testapp/AgentTelemetryForwarding.kt create mode 100644 app/src/test/java/com/mapbox/maps/testapp/AgentTelemetryForwardingTest.kt diff --git a/app/build.gradle.kts b/app/build.gradle.kts index 5547767f1d..6a4e0e4dd9 100644 --- a/app/build.gradle.kts +++ b/app/build.gradle.kts @@ -40,6 +40,17 @@ android { multiDexEnabled = true testInstrumentationRunner = "androidx.test.runner.AndroidJUnitRunner" testInstrumentationRunnerArguments["clearPackageData"] = "true" + // Optional coding-agent identifier (e.g. `-Pmapbox.agent=claude-code`), forwarded at runtime + // to Common's MapboxAgentContext so outbound requests can be tagged for agent-driven traffic + // measurement. Defaults to an empty string, which is treated as "no agent" and is a no-op. + val mapboxAgentId = if (project.hasProperty("mapbox.agent")) { + (project.property("mapbox.agent") as String) + .replace("\\", "\\\\") + .replace("\"", "\\\"") + } else { + "" + } + buildConfigField("String", "MAPBOX_AGENT", String.format("\"%s\"", mapboxAgentId)) ndk { val abi: String = if (System.getenv("ANDROID_ABI") != null) System.getenv("ANDROID_ABI") else "" diff --git a/app/src/main/java/com/mapbox/maps/testapp/AgentTelemetryForwarding.kt b/app/src/main/java/com/mapbox/maps/testapp/AgentTelemetryForwarding.kt new file mode 100644 index 0000000000..90644c91ef --- /dev/null +++ b/app/src/main/java/com/mapbox/maps/testapp/AgentTelemetryForwarding.kt @@ -0,0 +1,24 @@ +package com.mapbox.maps.testapp + +/** + * Forwards [agentId] via [setAgentId] when it is non-empty. + * + * [agentId] is expected to come from [BuildConfig.MAPBOX_AGENT], which is populated at build + * time from the optional `-Pmapbox.agent=` Gradle property (see `app/build.gradle.kts`). + * When that property is not supplied on the command line, [BuildConfig.MAPBOX_AGENT] defaults to + * an empty string and this function is a no-op, so normal (non-test) builds are unaffected. + * + * The forwarding logic itself is kept free of any Mapbox Common SDK dependency so that it can be + * unit tested in isolation; callers supply [setAgentId] to perform the actual forwarding, e.g.: + * + * ``` + * forwardAgentIdIfPresent(BuildConfig.MAPBOX_AGENT) { agentId -> + * MapboxAgentContextFactory.getInstance().setMapboxAgentId(agentId) + * } + * ``` + */ +internal fun forwardAgentIdIfPresent(agentId: String, setAgentId: (String) -> Unit) { + if (agentId.isNotEmpty()) { + setAgentId(agentId) + } +} diff --git a/app/src/main/java/com/mapbox/maps/testapp/MapboxApplication.kt b/app/src/main/java/com/mapbox/maps/testapp/MapboxApplication.kt index b41c7b590e..a9e3f4d4cd 100644 --- a/app/src/main/java/com/mapbox/maps/testapp/MapboxApplication.kt +++ b/app/src/main/java/com/mapbox/maps/testapp/MapboxApplication.kt @@ -4,6 +4,7 @@ import android.app.Application import android.os.StrictMode import com.mapbox.android.core.permissions.PermissionsManager import com.mapbox.annotation.MapboxExperimental +import com.mapbox.common.MapboxAgentContextFactory import com.mapbox.common.MapboxTracing import com.mapbox.common.geofencing.GeofencingError import com.mapbox.common.geofencing.GeofencingEvent @@ -66,11 +67,28 @@ class MapboxApplication : Application() { // Enable all traces. Useful when capturing Perfetto traces MapboxTracing.enableAll() initializeStrictMode() + forwardMapboxAgentId() if (ENABLE_BACKGROUND_GEOFENCING) { registerGeofencingObserver() } } + /** + * Forwards the compile-time Mapbox agent id (see `-Pmapbox.agent=` and + * [BuildConfig.MAPBOX_AGENT]) into Common's process-wide `MapboxAgentContext`, so that + * outbound Mapbox requests made during this process' lifetime (e.g. during a + * `connectedAndroidTest` run) carry an `agent/` tag on the User-Agent header. + * + * This is a no-op whenever [BuildConfig.MAPBOX_AGENT] is empty, which is the default when the + * `mapbox.agent` Gradle property is not supplied, so regular `assembleRelease` / non-test + * builds of this app are unaffected. + */ + private fun forwardMapboxAgentId() { + forwardAgentIdIfPresent(BuildConfig.MAPBOX_AGENT) { agentId -> + MapboxAgentContextFactory.getInstance().setMapboxAgentId(agentId) + } + } + private fun initializeStrictMode() { StrictMode.setThreadPolicy( StrictMode.ThreadPolicy.Builder() diff --git a/app/src/test/java/com/mapbox/maps/testapp/AgentTelemetryForwardingTest.kt b/app/src/test/java/com/mapbox/maps/testapp/AgentTelemetryForwardingTest.kt new file mode 100644 index 0000000000..86ca045a4d --- /dev/null +++ b/app/src/test/java/com/mapbox/maps/testapp/AgentTelemetryForwardingTest.kt @@ -0,0 +1,33 @@ +package com.mapbox.maps.testapp + +import org.junit.Assert.assertEquals +import org.junit.Assert.assertNull +import org.junit.Test + +class AgentTelemetryForwardingTest { + + @Test + fun `does not forward when agent id is empty`() { + var forwardedAgentId: String? = null + forwardAgentIdIfPresent("") { forwardedAgentId = it } + assertNull( + "Setter should not be invoked when BuildConfig.MAPBOX_AGENT is empty (the default when " + + "`-Pmapbox.agent` is not supplied)", + forwardedAgentId + ) + } + + @Test + fun `forwards agent id when non-empty`() { + var forwardedAgentId: String? = null + forwardAgentIdIfPresent("claude-code") { forwardedAgentId = it } + assertEquals("claude-code", forwardedAgentId) + } + + @Test + fun `forwards agent id exactly once`() { + var invocationCount = 0 + forwardAgentIdIfPresent("codex") { invocationCount++ } + assertEquals(1, invocationCount) + } +}