From 0cf14905d06d0f6d68b3b3a2c6afa353bf086698 Mon Sep 17 00:00:00 2001 From: jonathanmos <48201295+jonathanmos@users.noreply.github.com> Date: Tue, 22 Oct 2024 13:44:36 +0300 Subject: [PATCH] RUM-6375: Add check whether core is still active --- dd-sdk-android-core/api/apiSurface | 1 + .../api/dd-sdk-android-core.api | 1 + .../kotlin/com/datadog/android/api/SdkCore.kt | 6 +++ .../android/core/internal/DatadogCore.kt | 2 + .../core/internal/NoOpInternalSdkCore.kt | 2 + .../datadog/android/core/DatadogCoreTest.kt | 28 ++++++++++++++ .../android/sessionreplay/SessionReplay.kt | 2 +- .../sessionreplay/SessionReplayTest.kt | 38 +++++++++++++++++++ 8 files changed, 79 insertions(+), 1 deletion(-) diff --git a/dd-sdk-android-core/api/apiSurface b/dd-sdk-android-core/api/apiSurface index 0647cc4ae0..adce3a9d62 100644 --- a/dd-sdk-android-core/api/apiSurface +++ b/dd-sdk-android-core/api/apiSurface @@ -51,6 +51,7 @@ interface com.datadog.android.api.SdkCore val name: String val time: com.datadog.android.api.context.TimeInfo val service: String + fun isCoreActive(): Boolean fun setTrackingConsent(com.datadog.android.privacy.TrackingConsent) fun setUserInfo(String? = null, String? = null, String? = null, Map = emptyMap()) fun addUserProperties(Map) diff --git a/dd-sdk-android-core/api/dd-sdk-android-core.api b/dd-sdk-android-core/api/dd-sdk-android-core.api index e0191e8d44..225d17131b 100644 --- a/dd-sdk-android-core/api/dd-sdk-android-core.api +++ b/dd-sdk-android-core/api/dd-sdk-android-core.api @@ -116,6 +116,7 @@ public abstract interface class com/datadog/android/api/SdkCore { public abstract fun getName ()Ljava/lang/String; public abstract fun getService ()Ljava/lang/String; public abstract fun getTime ()Lcom/datadog/android/api/context/TimeInfo; + public abstract fun isCoreActive ()Z public abstract fun setTrackingConsent (Lcom/datadog/android/privacy/TrackingConsent;)V public abstract fun setUserInfo (Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;Ljava/util/Map;)V } diff --git a/dd-sdk-android-core/src/main/kotlin/com/datadog/android/api/SdkCore.kt b/dd-sdk-android-core/src/main/kotlin/com/datadog/android/api/SdkCore.kt index dd70f39fe1..fd6914d5bc 100644 --- a/dd-sdk-android-core/src/main/kotlin/com/datadog/android/api/SdkCore.kt +++ b/dd-sdk-android-core/src/main/kotlin/com/datadog/android/api/SdkCore.kt @@ -32,6 +32,12 @@ interface SdkCore { */ val service: String + /** + * Returns true if the core is active. + */ + @AnyThread + fun isCoreActive(): Boolean + /** * Sets the tracking consent regarding the data collection for this instance of the Datadog SDK. * diff --git a/dd-sdk-android-core/src/main/kotlin/com/datadog/android/core/internal/DatadogCore.kt b/dd-sdk-android-core/src/main/kotlin/com/datadog/android/core/internal/DatadogCore.kt index e056805021..e9b65d99bc 100644 --- a/dd-sdk-android-core/src/main/kotlin/com/datadog/android/core/internal/DatadogCore.kt +++ b/dd-sdk-android-core/src/main/kotlin/com/datadog/android/core/internal/DatadogCore.kt @@ -266,6 +266,8 @@ internal class DatadogCore( return coreFeature.createScheduledExecutorService(executorContext) } + override fun isCoreActive(): Boolean = isActive + // endregion // region InternalSdkCore diff --git a/dd-sdk-android-core/src/main/kotlin/com/datadog/android/core/internal/NoOpInternalSdkCore.kt b/dd-sdk-android-core/src/main/kotlin/com/datadog/android/core/internal/NoOpInternalSdkCore.kt index 4b1b1d40f8..e57d2a3554 100644 --- a/dd-sdk-android-core/src/main/kotlin/com/datadog/android/core/internal/NoOpInternalSdkCore.kt +++ b/dd-sdk-android-core/src/main/kotlin/com/datadog/android/core/internal/NoOpInternalSdkCore.kt @@ -89,6 +89,8 @@ internal object NoOpInternalSdkCore : InternalSdkCore { override fun clearAllData() = Unit + override fun isCoreActive(): Boolean = false + // endregion // region FeatureSdkCore diff --git a/dd-sdk-android-core/src/test/kotlin/com/datadog/android/core/DatadogCoreTest.kt b/dd-sdk-android-core/src/test/kotlin/com/datadog/android/core/DatadogCoreTest.kt index 010a48bd58..4291d9d310 100644 --- a/dd-sdk-android-core/src/test/kotlin/com/datadog/android/core/DatadogCoreTest.kt +++ b/dd-sdk-android-core/src/test/kotlin/com/datadog/android/core/DatadogCoreTest.kt @@ -885,6 +885,34 @@ internal class DatadogCoreTest { } } + @Test + fun `M return false W isActiveCore() { CoreFeature inactive }`() { + // Given + val mockCoreFeature = mock() + whenever(mockCoreFeature.initialized).thenReturn(AtomicBoolean(false)) + testedCore.coreFeature = mockCoreFeature + + // When + val isActive = testedCore.isCoreActive() + + // Then + assertThat(isActive).isFalse() + } + + @Test + fun `M return true W isActiveCore() { CoreFeature active }`() { + // Given + val mockCoreFeature = mock() + whenever(mockCoreFeature.initialized).thenReturn(AtomicBoolean(true)) + testedCore.coreFeature = mockCoreFeature + + // When + val isActive = testedCore.isCoreActive() + + // Then + assertThat(isActive).isTrue() + } + class ErrorRecordingRunnable( private val collector: MutableList, private val delegate: Runnable diff --git a/features/dd-sdk-android-session-replay/src/main/kotlin/com/datadog/android/sessionreplay/SessionReplay.kt b/features/dd-sdk-android-session-replay/src/main/kotlin/com/datadog/android/sessionreplay/SessionReplay.kt index 188672eff7..c8d169b738 100644 --- a/features/dd-sdk-android-session-replay/src/main/kotlin/com/datadog/android/sessionreplay/SessionReplay.kt +++ b/features/dd-sdk-android-session-replay/src/main/kotlin/com/datadog/android/sessionreplay/SessionReplay.kt @@ -103,7 +103,7 @@ object SessionReplay { } private fun isAlreadyRegistered() = - currentRegisteredCore?.get() != null + currentRegisteredCore?.get()?.isCoreActive() == true private fun logAlreadyRegisteredWarning(internalLogger: InternalLogger) = internalLogger.log( diff --git a/features/dd-sdk-android-session-replay/src/test/kotlin/com/datadog/android/sessionreplay/SessionReplayTest.kt b/features/dd-sdk-android-session-replay/src/test/kotlin/com/datadog/android/sessionreplay/SessionReplayTest.kt index bfa39220a6..9425609026 100644 --- a/features/dd-sdk-android-session-replay/src/test/kotlin/com/datadog/android/sessionreplay/SessionReplayTest.kt +++ b/features/dd-sdk-android-session-replay/src/test/kotlin/com/datadog/android/sessionreplay/SessionReplayTest.kt @@ -132,6 +132,7 @@ internal class SessionReplayTest { @Mock mockInternalLogger: InternalLogger ) { // Given + whenever(mockCore1.isCoreActive()).thenReturn(true) whenever(mockCore1.internalLogger).thenReturn(mockInternalLogger) whenever(mockCore2.internalLogger).thenReturn(mockInternalLogger) val fakeSessionReplayConfigurationWithMockRequirement = fakeSessionReplayConfiguration.copy( @@ -159,5 +160,42 @@ internal class SessionReplayTest { targets = listOf(InternalLogger.Target.MAINTAINER, InternalLogger.Target.TELEMETRY), message = IS_ALREADY_REGISTERED_WARNING ) + assertThat(SessionReplay.currentRegisteredCore?.get()).isEqualTo(mockCore1) + } + + @Test + fun `M allow changing cores W enable { Session Replay already enabled but old core inactive }`( + @Forgery fakeSessionReplayConfiguration: SessionReplayConfiguration, + @Mock mockCore1: FeatureSdkCore, + @Mock mockCore2: FeatureSdkCore, + @Mock mockInternalLogger: InternalLogger + ) { + // Given + whenever(mockCore1.internalLogger).thenReturn(mockInternalLogger) + whenever(mockCore2.internalLogger).thenReturn(mockInternalLogger) + val fakeSessionReplayConfigurationWithMockRequirement = fakeSessionReplayConfiguration.copy( + systemRequirementsConfiguration = mockSystemRequirementsConfiguration + ) + whenever( + mockSystemRequirementsConfiguration.runIfRequirementsMet(any(), any()) + ) doAnswer { + it.getArgument<() -> Unit>(1).invoke() + } + whenever(mockCore1.isCoreActive()).thenReturn(true) + SessionReplay.enable( + sessionReplayConfiguration = fakeSessionReplayConfigurationWithMockRequirement, + sdkCore = mockCore1 + ) + assertThat(SessionReplay.currentRegisteredCore?.get()).isEqualTo(mockCore1) + + // When + whenever(mockCore1.isCoreActive()).thenReturn(false) + SessionReplay.enable( + sessionReplayConfiguration = fakeSessionReplayConfigurationWithMockRequirement, + sdkCore = mockCore2 + ) + + // Then + assertThat(SessionReplay.currentRegisteredCore?.get()).isEqualTo(mockCore2) } }