From 04303e133ac0f8a5a6d05e04d42a3544fece891c Mon Sep 17 00:00:00 2001 From: Roman Zavarnitsyn Date: Tue, 14 Jun 2022 19:54:46 +0200 Subject: [PATCH] fix: Okhttp-integration version check (#327) --- CHANGELOG.md | 6 ++ .../io/sentry/android/gradle/SentryPlugin.kt | 8 +- .../SpanAddingClassVisitorFactory.kt | 58 ++++++++------ ...StateHolder.kt => SentryModulesService.kt} | 12 +-- .../gradle/util/SentryAndroidSdkChecker.kt | 49 ++++++------ .../gradle/util/SentryAndroidSdkState.kt | 32 -------- .../io/sentry/android/gradle/util/Versions.kt | 12 +++ .../gradle/SentryPluginCheckAndroidSdkTest.kt | 19 +++-- .../fakes/TestSpanAddingParameters.kt | 4 +- .../util/SentryAndroidSdkCheckerTest.kt | 78 +++++++++++-------- 10 files changed, 146 insertions(+), 132 deletions(-) rename plugin-build/src/main/kotlin/io/sentry/android/gradle/services/{SentrySdkStateHolder.kt => SentryModulesService.kt} (59%) delete mode 100644 plugin-build/src/main/kotlin/io/sentry/android/gradle/util/SentryAndroidSdkState.kt diff --git a/CHANGELOG.md b/CHANGELOG.md index 89a946b3..4a8e5ea1 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,11 @@ # Changelog +## Unreleased + +### Fixes + +- Fix `OkHttp` auto-instrumentation crash, when `sentry-android-okhttp` is not present on classpath ([#327](https://github.com/getsentry/sentry-android-gradle-plugin/pull/327)) + ## 3.1.0 ### Features diff --git a/plugin-build/src/main/kotlin/io/sentry/android/gradle/SentryPlugin.kt b/plugin-build/src/main/kotlin/io/sentry/android/gradle/SentryPlugin.kt index 1920c690..52751678 100644 --- a/plugin-build/src/main/kotlin/io/sentry/android/gradle/SentryPlugin.kt +++ b/plugin-build/src/main/kotlin/io/sentry/android/gradle/SentryPlugin.kt @@ -19,7 +19,7 @@ import io.sentry.android.gradle.SentryTasksProvider.getTransformerTask import io.sentry.android.gradle.autoinstall.installDependencies import io.sentry.android.gradle.extensions.SentryPluginExtension import io.sentry.android.gradle.instrumentation.SpanAddingClassVisitorFactory -import io.sentry.android.gradle.services.SentrySdkStateHolder +import io.sentry.android.gradle.services.SentryModulesService import io.sentry.android.gradle.tasks.SentryGenerateProguardUuidTask import io.sentry.android.gradle.tasks.SentryUploadNativeSymbolsTask import io.sentry.android.gradle.tasks.SentryUploadProguardMappingsTask @@ -97,11 +97,11 @@ class SentryPlugin : Plugin { * the state between builds and also during a single build, because transforms * are run in parallel. */ - val sdkStateHolderProvider = SentrySdkStateHolder.register(project) + val sentryModulesService = SentryModulesService.register(project) project.detectSentryAndroidSdk( "${variant.name}RuntimeClasspath", variant.name, - sdkStateHolderProvider + sentryModulesService ) variant.transformClassesWith( @@ -117,7 +117,7 @@ class SentryPlugin : Plugin { params.features.setDisallowChanges( extension.tracingInstrumentation.features.get() ) - params.sdkStateHolder.setDisallowChanges(sdkStateHolderProvider) + params.sentryModulesService.setDisallowChanges(sentryModulesService) params.tmpDir.set(tmpDir) } variant.setAsmFramesComputationMode( diff --git a/plugin-build/src/main/kotlin/io/sentry/android/gradle/instrumentation/SpanAddingClassVisitorFactory.kt b/plugin-build/src/main/kotlin/io/sentry/android/gradle/instrumentation/SpanAddingClassVisitorFactory.kt index 38aa275e..416b5ac9 100644 --- a/plugin-build/src/main/kotlin/io/sentry/android/gradle/instrumentation/SpanAddingClassVisitorFactory.kt +++ b/plugin-build/src/main/kotlin/io/sentry/android/gradle/instrumentation/SpanAddingClassVisitorFactory.kt @@ -12,11 +12,10 @@ import io.sentry.android.gradle.instrumentation.androidx.sqlite.statement.Androi import io.sentry.android.gradle.instrumentation.okhttp.OkHttp import io.sentry.android.gradle.instrumentation.remap.RemappingInstrumentable import io.sentry.android.gradle.instrumentation.wrap.WrappingInstrumentable -import io.sentry.android.gradle.services.SentrySdkStateHolder -import io.sentry.android.gradle.util.SentryAndroidSdkState -import io.sentry.android.gradle.util.SentryAndroidSdkState.FILE_IO -import io.sentry.android.gradle.util.SentryAndroidSdkState.OKHTTP -import io.sentry.android.gradle.util.SentryAndroidSdkState.PERFORMANCE +import io.sentry.android.gradle.services.SentryModulesService +import io.sentry.android.gradle.util.SemVer +import io.sentry.android.gradle.util.SentryModules +import io.sentry.android.gradle.util.SentryVersions import io.sentry.android.gradle.util.debug import io.sentry.android.gradle.util.info import io.sentry.android.gradle.util.warn @@ -50,7 +49,7 @@ abstract class SpanAddingClassVisitorFactory : val features: SetProperty @get:Internal - val sdkStateHolder: Property + val sentryModulesService: Property @get:Internal val tmpDir: Property @@ -69,27 +68,29 @@ abstract class SpanAddingClassVisitorFactory : return memoized } - val sdkState = parameters.get().sdkStateHolder.get().sdkState - SentryPlugin.logger.info { "Read sentry-android sdk state: $sdkState" } + val sentryModules = parameters.get().sentryModulesService.get().modules + SentryPlugin.logger.info { "Read sentry modules: $sentryModules" } /** * When adding a new instrumentable to the list below, do not forget to add a new - * version range to [SentryAndroidSdkState.from], if it involves runtime classes + * version to [SentryVersions] if it involves runtime classes * from the sentry-android SDK. */ val instrumentables = listOfNotNull( AndroidXSQLiteDatabase().takeIf { - isDatabaseInstrEnabled(sdkState, parameters.get()) + isDatabaseInstrEnabled(sentryModules, parameters.get()) }, AndroidXSQLiteStatement().takeIf { - isDatabaseInstrEnabled(sdkState, parameters.get()) + isDatabaseInstrEnabled(sentryModules, parameters.get()) }, - AndroidXRoomDao().takeIf { isDatabaseInstrEnabled(sdkState, parameters.get()) }, - OkHttp().takeIf { isOkHttpInstrEnabled(sdkState, parameters.get()) }, + AndroidXRoomDao().takeIf { + isDatabaseInstrEnabled(sentryModules, parameters.get()) + }, + OkHttp().takeIf { isOkHttpInstrEnabled(sentryModules, parameters.get()) }, ChainedInstrumentable( listOf(WrappingInstrumentable(), RemappingInstrumentable()) - ).takeIf { isFileIOInstrEnabled(sdkState, parameters.get()) } + ).takeIf { isFileIOInstrEnabled(sentryModules, parameters.get()) } ) - SentryPlugin.logger.debug { + SentryPlugin.logger.info { "Instrumentables: ${instrumentables.joinToString { it::class.java.simpleName }}" } parameters.get()._instrumentables = ArrayList(instrumentables) @@ -97,24 +98,33 @@ abstract class SpanAddingClassVisitorFactory : } private fun isDatabaseInstrEnabled( - sdkState: SentryAndroidSdkState, + sentryModules: Map, parameters: SpanAddingParameters ): Boolean = - sdkState.isAtLeast(PERFORMANCE) && - parameters.features.get().contains(InstrumentationFeature.DATABASE) + sentryModules.isAtLeast( + SentryModules.SENTRY_ANDROID_CORE, + SentryVersions.VERSION_PERFORMANCE + ) && parameters.features.get().contains(InstrumentationFeature.DATABASE) private fun isFileIOInstrEnabled( - sdkState: SentryAndroidSdkState, + sentryModules: Map, parameters: SpanAddingParameters ): Boolean = - sdkState.isAtLeast(FILE_IO) && - parameters.features.get().contains(InstrumentationFeature.FILE_IO) + sentryModules.isAtLeast( + SentryModules.SENTRY_ANDROID_CORE, + SentryVersions.VERSION_FILE_IO + ) && parameters.features.get().contains(InstrumentationFeature.FILE_IO) private fun isOkHttpInstrEnabled( - sdkState: SentryAndroidSdkState, + sentryModules: Map, parameters: SpanAddingParameters - ): Boolean = sdkState.isAtLeast(OKHTTP) && - parameters.features.get().contains(InstrumentationFeature.OKHTTP) + ): Boolean = sentryModules.isAtLeast( + SentryModules.SENTRY_ANDROID_OKHTTP, + SentryVersions.VERSION_OKHTTP + ) && parameters.features.get().contains(InstrumentationFeature.OKHTTP) + + private fun Map.isAtLeast(module: String, minVersion: SemVer): Boolean = + getOrDefault(module, SentryVersions.VERSION_DEFAULT) >= minVersion override fun createClassVisitor( classContext: ClassContext, diff --git a/plugin-build/src/main/kotlin/io/sentry/android/gradle/services/SentrySdkStateHolder.kt b/plugin-build/src/main/kotlin/io/sentry/android/gradle/services/SentryModulesService.kt similarity index 59% rename from plugin-build/src/main/kotlin/io/sentry/android/gradle/services/SentrySdkStateHolder.kt rename to plugin-build/src/main/kotlin/io/sentry/android/gradle/services/SentryModulesService.kt index cd523acf..081a322f 100644 --- a/plugin-build/src/main/kotlin/io/sentry/android/gradle/services/SentrySdkStateHolder.kt +++ b/plugin-build/src/main/kotlin/io/sentry/android/gradle/services/SentryModulesService.kt @@ -2,24 +2,24 @@ package io.sentry.android.gradle.services -import io.sentry.android.gradle.util.SentryAndroidSdkState +import io.sentry.android.gradle.util.SemVer import io.sentry.android.gradle.util.getBuildServiceName import org.gradle.api.Project import org.gradle.api.provider.Provider import org.gradle.api.services.BuildService import org.gradle.api.services.BuildServiceParameters -abstract class SentrySdkStateHolder : BuildService { +abstract class SentryModulesService : BuildService { @get:Synchronized @set:Synchronized - var sdkState: SentryAndroidSdkState = SentryAndroidSdkState.MISSING + var modules: Map = emptyMap() companion object { - fun register(project: Project): Provider { + fun register(project: Project): Provider { return project.gradle.sharedServices.registerIfAbsent( - getBuildServiceName(SentrySdkStateHolder::class.java), - SentrySdkStateHolder::class.java + getBuildServiceName(SentryModulesService::class.java), + SentryModulesService::class.java ) {} } } diff --git a/plugin-build/src/main/kotlin/io/sentry/android/gradle/util/SentryAndroidSdkChecker.kt b/plugin-build/src/main/kotlin/io/sentry/android/gradle/util/SentryAndroidSdkChecker.kt index 3ebe663e..6ab35e00 100644 --- a/plugin-build/src/main/kotlin/io/sentry/android/gradle/util/SentryAndroidSdkChecker.kt +++ b/plugin-build/src/main/kotlin/io/sentry/android/gradle/util/SentryAndroidSdkChecker.kt @@ -1,15 +1,16 @@ package io.sentry.android.gradle.util -import io.sentry.android.gradle.services.SentrySdkStateHolder +import io.sentry.android.gradle.services.SentryModulesService import org.gradle.api.Project import org.gradle.api.UnknownDomainObjectException import org.gradle.api.artifacts.result.ResolvedComponentResult +import org.gradle.api.logging.Logger import org.gradle.api.provider.Provider fun Project.detectSentryAndroidSdk( configurationName: String, variantName: String, - sdkStateHolder: Provider + sentryModulesService: Provider ) { val configProvider = try { configurations.named(configurationName) @@ -17,39 +18,35 @@ fun Project.detectSentryAndroidSdk( logger.warn { "Unable to find configuration $configurationName for variant $variantName." } - sdkStateHolder.get().sdkState = SentryAndroidSdkState.MISSING + sentryModulesService.get().modules = emptyMap() return } configProvider.configure { configuration -> configuration.incoming.afterResolve { - val version = it.resolutionResult.allComponents.findSentryAndroidSdk() - if (version == null) { - logger.warn { "sentry-android dependency was not found." } - sdkStateHolder.get().sdkState = SentryAndroidSdkState.MISSING - return@afterResolve + val sentryModules = it.resolutionResult.allComponents.filterSentryModules(logger) + logger.info { + "Detected Sentry modules $sentryModules " + + "for variant: $variantName, config: $configurationName" } - - val state = try { - val sdkState = SentryAndroidSdkState.from(version) - logger.info { - "Detected sentry-android $sdkState for version: $version, " + - "variant: $variantName, config: $configurationName" - } - sdkState - } catch (e: IllegalStateException) { - logger.warn { e.localizedMessage } - SentryAndroidSdkState.MISSING - } - sdkStateHolder.get().sdkState = state + sentryModulesService.get().modules = sentryModules } } } -private fun Set.findSentryAndroidSdk(): String? { - val sentryDep = find { resolvedComponent: ResolvedComponentResult -> - val moduleVersion = resolvedComponent.moduleVersion ?: return@find false - moduleVersion.group == "io.sentry" && moduleVersion.name == "sentry-android-core" +private fun Set.filterSentryModules(logger: Logger): Map { + return filter { resolvedComponent: ResolvedComponentResult -> + val moduleVersion = resolvedComponent.moduleVersion ?: return@filter false + moduleVersion.group == "io.sentry" + }.associate { + val name = it.moduleVersion?.name ?: "" + val version = it.moduleVersion?.version ?: "" + val semver = try { + SemVer.parse(version) + } catch (e: Throwable) { + logger.info { "Unable to parse version $version of $name" } + SemVer() + } + name to semver } - return sentryDep?.moduleVersion?.version } diff --git a/plugin-build/src/main/kotlin/io/sentry/android/gradle/util/SentryAndroidSdkState.kt b/plugin-build/src/main/kotlin/io/sentry/android/gradle/util/SentryAndroidSdkState.kt deleted file mode 100644 index 02d834a8..00000000 --- a/plugin-build/src/main/kotlin/io/sentry/android/gradle/util/SentryAndroidSdkState.kt +++ /dev/null @@ -1,32 +0,0 @@ -package io.sentry.android.gradle.util - -import java.io.Serializable - -enum class SentryAndroidSdkState(val minVersion: SemVer) : Serializable { - MISSING(SemVer()), - - PERFORMANCE(SemVer(4, 0, 0)), - - OKHTTP(SemVer(5, 0, 0)), - - FILE_IO(SemVer(5, 5, 0)); - - fun isAtLeast(state: SentryAndroidSdkState): Boolean = this.ordinal >= state.ordinal - - companion object { - fun from(version: String): SentryAndroidSdkState { - if (version == "unspecified") { - return MISSING - } - - val semVer = SemVer.parse(version) - return when { - semVer < PERFORMANCE.minVersion -> MISSING - semVer >= PERFORMANCE.minVersion && semVer < OKHTTP.minVersion -> PERFORMANCE - semVer >= OKHTTP.minVersion && semVer < FILE_IO.minVersion -> OKHTTP - semVer >= FILE_IO.minVersion -> FILE_IO - else -> error("Unknown version $version of sentry-android") - } - } - } -} diff --git a/plugin-build/src/main/kotlin/io/sentry/android/gradle/util/Versions.kt b/plugin-build/src/main/kotlin/io/sentry/android/gradle/util/Versions.kt index c7f846b4..7822af7a 100644 --- a/plugin-build/src/main/kotlin/io/sentry/android/gradle/util/Versions.kt +++ b/plugin-build/src/main/kotlin/io/sentry/android/gradle/util/Versions.kt @@ -10,6 +10,18 @@ internal object AgpVersions { val VERSION_7_0_0: SemVer = SemVer.parse("7.0.0") } +internal object SentryVersions { + internal val VERSION_DEFAULT = SemVer() + internal val VERSION_PERFORMANCE = SemVer(4, 0, 0) + internal val VERSION_OKHTTP = SemVer(5, 0, 0) + internal val VERSION_FILE_IO = SemVer(5, 5, 0) +} + +internal object SentryModules { + internal const val SENTRY_ANDROID_CORE = "sentry-android-core" + internal const val SENTRY_ANDROID_OKHTTP = "sentry-android-okhttp" +} + /** * Adapted from https://github.com/swiftzer/semver/blob/master/src/main/java/net/swiftzer/semver/SemVer.kt */ diff --git a/plugin-build/src/test/kotlin/io/sentry/android/gradle/SentryPluginCheckAndroidSdkTest.kt b/plugin-build/src/test/kotlin/io/sentry/android/gradle/SentryPluginCheckAndroidSdkTest.kt index 3a7ea950..b3a9e8e2 100644 --- a/plugin-build/src/test/kotlin/io/sentry/android/gradle/SentryPluginCheckAndroidSdkTest.kt +++ b/plugin-build/src/test/kotlin/io/sentry/android/gradle/SentryPluginCheckAndroidSdkTest.kt @@ -37,7 +37,7 @@ class SentryPluginCheckAndroidSdkTest( assertTrue { result.output.contains( Regex( - """[BuildServiceRegistration with name 'io.sentry.android.gradle.services.SentrySdkStateHolder_(\w*)' not found]""" + """[BuildServiceRegistration with name 'io.sentry.android.gradle.services.SentryModulesService_(\w*)' not found]""" ) ) } @@ -55,6 +55,7 @@ class SentryPluginCheckAndroidSdkTest( } sentry.tracingInstrumentation.enabled = true + sentry.autoInstallation.enabled = false sentry.includeProguardMapping = false ${captureSdkState()} @@ -62,10 +63,10 @@ class SentryPluginCheckAndroidSdkTest( ) val result = runner - .appendArguments("app:tasks") + .appendArguments("app:assembleDebug") .build() assertTrue { - "SDK STATE: MISSING" in result.output + "SENTRY MODULES: [:]" in result.output } } @@ -81,6 +82,7 @@ class SentryPluginCheckAndroidSdkTest( sentry { tracingInstrumentation.enabled = true + autoInstallation.enabled = false includeProguardMapping = false } @@ -102,7 +104,10 @@ class SentryPluginCheckAndroidSdkTest( .appendArguments("app:assembleDebug") .build() - print(result.output) + assertTrue { + "SENTRY MODULES: [sentry-android:5.4.0, sentry-android-core:5.4.0, " + + "sentry:5.4.0, sentry-android-ndk:5.4.0]" in result.output + } } private fun captureSdkState(): String = @@ -112,9 +117,9 @@ class SentryPluginCheckAndroidSdkTest( import io.sentry.android.gradle.services.* project.gradle.buildFinished { println( - "SDK STATE: " + BuildServicesKt - .getBuildService(project.gradle.sharedServices, SentrySdkStateHolder.class) - .get().sdkState + "SENTRY MODULES: " + BuildServicesKt + .getBuildService(project.gradle.sharedServices, SentryModulesService.class) + .get().modules ) } """.trimIndent() diff --git a/plugin-build/src/test/kotlin/io/sentry/android/gradle/instrumentation/fakes/TestSpanAddingParameters.kt b/plugin-build/src/test/kotlin/io/sentry/android/gradle/instrumentation/fakes/TestSpanAddingParameters.kt index 4e9f2381..ae17eee0 100644 --- a/plugin-build/src/test/kotlin/io/sentry/android/gradle/instrumentation/fakes/TestSpanAddingParameters.kt +++ b/plugin-build/src/test/kotlin/io/sentry/android/gradle/instrumentation/fakes/TestSpanAddingParameters.kt @@ -3,7 +3,7 @@ package io.sentry.android.gradle.instrumentation.fakes import io.sentry.android.gradle.extensions.InstrumentationFeature import io.sentry.android.gradle.instrumentation.ClassInstrumentable import io.sentry.android.gradle.instrumentation.SpanAddingClassVisitorFactory -import io.sentry.android.gradle.services.SentrySdkStateHolder +import io.sentry.android.gradle.services.SentryModulesService import java.io.File import org.gradle.api.internal.provider.DefaultProperty import org.gradle.api.internal.provider.DefaultSetProperty @@ -27,7 +27,7 @@ class TestSpanAddingParameters( get() = DefaultSetProperty(PropertyHost.NO_OP, InstrumentationFeature::class.java) .convention(setOf(InstrumentationFeature.FILE_IO, InstrumentationFeature.DATABASE)) - override val sdkStateHolder: Property + override val sentryModulesService: Property get() = TODO() override val tmpDir: Property diff --git a/plugin-build/src/test/kotlin/io/sentry/android/gradle/util/SentryAndroidSdkCheckerTest.kt b/plugin-build/src/test/kotlin/io/sentry/android/gradle/util/SentryAndroidSdkCheckerTest.kt index 530c1c79..5e4e11fb 100644 --- a/plugin-build/src/test/kotlin/io/sentry/android/gradle/util/SentryAndroidSdkCheckerTest.kt +++ b/plugin-build/src/test/kotlin/io/sentry/android/gradle/util/SentryAndroidSdkCheckerTest.kt @@ -6,7 +6,7 @@ import com.nhaarman.mockitokotlin2.mock import com.nhaarman.mockitokotlin2.spy import com.nhaarman.mockitokotlin2.whenever import io.sentry.android.gradle.instrumentation.fakes.CapturingTestLogger -import io.sentry.android.gradle.services.SentrySdkStateHolder +import io.sentry.android.gradle.services.SentryModulesService import java.io.File import kotlin.test.assertTrue import org.gradle.api.Action @@ -33,7 +33,7 @@ class SentryAndroidSdkCheckerTest { val configurationName: String = "debugRuntimeClasspath" val variantName: String = "debug" - lateinit var sdkStateHolderProvider: Provider + lateinit var sentryModulesServiceProvider: Provider val logger = CapturingTestLogger() fun getSut( @@ -60,12 +60,12 @@ class SentryAndroidSdkCheckerTest { whenever(project.logger).thenReturn(logger) project.configurations.add(configuration) - sdkStateHolderProvider = SentrySdkStateHolder.register(project) + sentryModulesServiceProvider = SentryModulesService.register(project) return project } - fun getSdkState() = sdkStateHolderProvider.get().sdkState + fun getModules() = sentryModulesServiceProvider.get().modules } @get:Rule @@ -74,15 +74,14 @@ class SentryAndroidSdkCheckerTest { private val fixture = Fixture() @Test - fun `configuration cannot be found - logs a warning and returns MISSING state`() { + fun `configuration cannot be found - logs a warning and the modules list is empty`() { val project = fixture.getSut(testProjectDir.root) project.detectSentryAndroidSdk( "releaseRuntimeClasspath", "release", - fixture.sdkStateHolderProvider + fixture.sentryModulesServiceProvider ) - - assertTrue { fixture.getSdkState() == SentryAndroidSdkState.MISSING } + assertTrue { fixture.getModules().isEmpty() } assertTrue { fixture.logger.capturedMessage == "[sentry] Unable to find configuration releaseRuntimeClasspath for variant release." @@ -90,7 +89,7 @@ class SentryAndroidSdkCheckerTest { } @Test - fun `sentry-android is not in the dependencies - logs a warning and returns MISSING state`() { + fun `sentry-android is not in the dependencies - modules list is empty`() { val sqliteDep = mock { whenever(mock.moduleVersion).thenReturn( DefaultModuleVersionIdentifier.newId("androidx.sqlite", "sqlite", "2.1.0") @@ -101,18 +100,14 @@ class SentryAndroidSdkCheckerTest { project.detectSentryAndroidSdk( fixture.configurationName, fixture.variantName, - fixture.sdkStateHolderProvider + fixture.sentryModulesServiceProvider ) - assertTrue { fixture.getSdkState() == SentryAndroidSdkState.MISSING } - assertTrue { - fixture.logger.capturedMessage == - "[sentry] sentry-android dependency was not found." - } + assertTrue { fixture.getModules().isEmpty() } } @Test - fun `sentry-android as a local dependency - logs a info and returns MISSING state`() { + fun `sentry-android as a local dependency - module's version is omitted`() { val sentryAndroidDep = mock { whenever(mock.moduleVersion).thenReturn( // this is the case when sentry-android is a local dependency @@ -128,19 +123,22 @@ class SentryAndroidSdkCheckerTest { project.detectSentryAndroidSdk( fixture.configurationName, fixture.variantName, - fixture.sdkStateHolderProvider + fixture.sentryModulesServiceProvider ) - assertTrue { fixture.getSdkState() == SentryAndroidSdkState.MISSING } + assertTrue { + fixture.getModules().size == 1 && + fixture.getModules()["sentry-android-core"] == SemVer() + } assertTrue { fixture.logger.capturedMessage == - "[sentry] Detected sentry-android MISSING for version: unspecified, " + - "variant: debug, config: debugRuntimeClasspath" + "[sentry] Detected Sentry modules {sentry-android-core=0.0.0} for variant: debug," + + " config: debugRuntimeClasspath" } } @Test - fun `sentry-android performance version - logs a info and returns PERFORMANCE state`() { + fun `sentry-android performance version - logs a info and persists module in build service`() { val sentryAndroidDep = mock { whenever(mock.moduleVersion).thenReturn( DefaultModuleVersionIdentifier.newId( @@ -155,19 +153,22 @@ class SentryAndroidSdkCheckerTest { project.detectSentryAndroidSdk( fixture.configurationName, fixture.variantName, - fixture.sdkStateHolderProvider + fixture.sentryModulesServiceProvider ) - assertTrue { fixture.getSdkState() == SentryAndroidSdkState.PERFORMANCE } + assertTrue { + fixture.getModules().size == 1 && + fixture.getModules()["sentry-android-core"] == SemVer(4, 1, 0) + } assertTrue { fixture.logger.capturedMessage == - "[sentry] Detected sentry-android PERFORMANCE for version: 4.1.0, " + - "variant: debug, config: debugRuntimeClasspath" + "[sentry] Detected Sentry modules {sentry-android-core=4.1.0} for variant: debug," + + " config: debugRuntimeClasspath" } } @Test - fun `sentry-android transitive - logs a info and returns FILE_IO state`() { + fun `sentry-android transitive - logs a info and persists both modules in build service`() { val firstLevelDep = mock { whenever(mock.moduleVersion).thenReturn( DefaultModuleVersionIdentifier.newId( @@ -186,22 +187,37 @@ class SentryAndroidSdkCheckerTest { ) ) } + val okHttpDep = mock { + whenever(mock.moduleVersion).thenReturn( + DefaultModuleVersionIdentifier.newId( + "io.sentry", + "sentry-android-okhttp", + "6.0.0" + ) + ) + } val project = fixture.getSut( testProjectDir.root, - dependencies = setOf(firstLevelDep, transitiveSentryDep) + dependencies = setOf(firstLevelDep, transitiveSentryDep, okHttpDep) ) project.detectSentryAndroidSdk( fixture.configurationName, fixture.variantName, - fixture.sdkStateHolderProvider + fixture.sentryModulesServiceProvider ) - assertTrue { fixture.getSdkState() == SentryAndroidSdkState.FILE_IO } + assertTrue { + fixture.getModules().size == 3 && + fixture.getModules()["sentry-android"] == SemVer(5, 5, 0) && + fixture.getModules()["sentry-android-core"] == SemVer(5, 5, 0) && + fixture.getModules()["sentry-android-okhttp"] == SemVer(6, 0, 0) + } assertTrue { fixture.logger.capturedMessage == - "[sentry] Detected sentry-android FILE_IO for version: 5.5.0, " + - "variant: debug, config: debugRuntimeClasspath" + "[sentry] Detected Sentry modules {sentry-android=5.5.0, " + + "sentry-android-core=5.5.0, sentry-android-okhttp=6.0.0} for variant: debug," + + " config: debugRuntimeClasspath" } } }