From 32ed64e0e1fc2d8a4123e636b43de6869b2d0a46 Mon Sep 17 00:00:00 2001 From: louiszawadzki Date: Thu, 31 Aug 2023 14:07:32 +0200 Subject: [PATCH 01/28] Update Android SDK to v2 --- example/android/build.gradle | 3 +- packages/core/android/build.gradle | 5 +- packages/core/android/gradle.properties | 2 +- .../datadog/reactnative/DatadogSDKWrapper.kt | 26 ++-- .../com/datadog/reactnative/DatadogWrapper.kt | 9 -- .../reactnative/DdLogsImplementation.kt | 3 +- .../reactnative/DdRumImplementation.kt | 24 +-- .../reactnative/DdSdkConfigurationExt.kt | 2 +- .../reactnative/DdSdkImplementation.kt | 138 +++++++++--------- .../reactnative/DdTraceImplementation.kt | 12 +- 10 files changed, 113 insertions(+), 111 deletions(-) diff --git a/example/android/build.gradle b/example/android/build.gradle index 4dcd21c1c..0aa14077a 100644 --- a/example/android/build.gradle +++ b/example/android/build.gradle @@ -2,7 +2,6 @@ buildscript { ext { - RNNKotlinVersion = "1.5.31" buildToolsVersion = "33.0.0" minSdkVersion = 21 compileSdkVersion = 33 @@ -16,7 +15,7 @@ buildscript { mavenCentral() } dependencies { - classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:1.5.31" + classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:1.7.21" classpath("com.android.tools.build:gradle:7.3.1") classpath("com.facebook.react:react-native-gradle-plugin") } diff --git a/packages/core/android/build.gradle b/packages/core/android/build.gradle index 493864754..f2aff0433 100644 --- a/packages/core/android/build.gradle +++ b/packages/core/android/build.gradle @@ -159,7 +159,10 @@ dependencies { implementation "org.jetbrains.kotlin:kotlin-stdlib:$kotlin_version" compileOnly "com.squareup.okhttp3:okhttp:3.12.13" - implementation "com.datadoghq:dd-sdk-android:1.19.2" + implementation "com.datadoghq:dd-sdk-android-rum:2.0.0" + implementation "com.datadoghq:dd-sdk-android-logs:2.0.0" + implementation "com.datadoghq:dd-sdk-android-trace:2.0.0" + implementation "com.datadoghq:dd-sdk-android-webview:2.0.0" testImplementation "org.junit.platform:junit-platform-launcher:1.6.2" testImplementation "org.junit.jupiter:junit-jupiter-api:5.6.2" testImplementation "org.junit.jupiter:junit-jupiter-engine:5.6.2" diff --git a/packages/core/android/gradle.properties b/packages/core/android/gradle.properties index 0401e18b4..4f16df59e 100644 --- a/packages/core/android/gradle.properties +++ b/packages/core/android/gradle.properties @@ -1,4 +1,4 @@ -DdSdkReactNative_kotlinVersion=1.6.21 +DdSdkReactNative_kotlinVersion=1.7.21 DdSdkReactNative_compileSdkVersion=31 DdSdkReactNative_buildToolsVersion=31.0.0 DdSdkReactNative_targetSdkVersion=31 diff --git a/packages/core/android/src/main/kotlin/com/datadog/reactnative/DatadogSDKWrapper.kt b/packages/core/android/src/main/kotlin/com/datadog/reactnative/DatadogSDKWrapper.kt index 8a501fecd..7918dcb52 100644 --- a/packages/core/android/src/main/kotlin/com/datadog/reactnative/DatadogSDKWrapper.kt +++ b/packages/core/android/src/main/kotlin/com/datadog/reactnative/DatadogSDKWrapper.kt @@ -9,10 +9,9 @@ package com.datadog.reactnative import android.content.Context import com.datadog.android.Datadog import com.datadog.android.core.configuration.Configuration -import com.datadog.android.core.configuration.Credentials import com.datadog.android.privacy.TrackingConsent -import com.datadog.android.rum.GlobalRum -import com.datadog.android.rum.RumMonitor +import com.datadog.android.rum.GlobalRumMonitor +import com.datadog.android.webview.WebViewTracking internal class DatadogSDKWrapper : DatadogWrapper { @@ -22,11 +21,10 @@ internal class DatadogSDKWrapper : DatadogWrapper { override fun initialize( context: Context, - credentials: Credentials, configuration: Configuration, consent: TrackingConsent ) { - Datadog.initialize(context, credentials, configuration, consent) + Datadog.initialize(context, configuration, consent) } override fun setUserInfo( @@ -38,13 +36,9 @@ internal class DatadogSDKWrapper : DatadogWrapper { Datadog.setUserInfo(id, name, email, extraInfo) } - override fun registerRumMonitor(rumMonitor: RumMonitor) { - GlobalRum.registerIfAbsent(rumMonitor) - } - override fun addRumGlobalAttributes(attributes: Map) { attributes.forEach { - GlobalRum.addAttribute(it.key, it.value) + GlobalRumMonitor.get().addAttribute(it.key, it.value) } } @@ -53,19 +47,23 @@ internal class DatadogSDKWrapper : DatadogWrapper { } override fun telemetryDebug(message: String) { - Datadog._internal._telemetry.debug(message) + // TODO: store instance of proxy to avoid creating one every time + Datadog._internalProxy()._telemetry.debug(message) } override fun telemetryError(message: String, stack: String?, kind: String?) { - Datadog._internal._telemetry.error(message, stack, kind) + // TODO: store instance of proxy to avoid creating one every time + Datadog._internalProxy()._telemetry.error(message, stack, kind) } override fun telemetryError(message: String, throwable: Throwable?) { - Datadog._internal._telemetry.error(message, throwable) + // TODO: store instance of proxy to avoid creating one every time + Datadog._internalProxy()._telemetry.error(message, throwable) } override fun consumeWebviewEvent(message: String) { - Datadog._internal.consumeWebviewEvent(message) + // TODO: store instance of proxy to avoid creating one every time + WebViewTracking._InternalWebViewProxy(Datadog.getInstance()).consumeWebviewEvent(message) } override fun isInitialized(): Boolean { diff --git a/packages/core/android/src/main/kotlin/com/datadog/reactnative/DatadogWrapper.kt b/packages/core/android/src/main/kotlin/com/datadog/reactnative/DatadogWrapper.kt index 3c39e7303..c568082e7 100644 --- a/packages/core/android/src/main/kotlin/com/datadog/reactnative/DatadogWrapper.kt +++ b/packages/core/android/src/main/kotlin/com/datadog/reactnative/DatadogWrapper.kt @@ -8,7 +8,6 @@ package com.datadog.reactnative import android.content.Context import com.datadog.android.core.configuration.Configuration -import com.datadog.android.core.configuration.Credentials import com.datadog.android.privacy.TrackingConsent import com.datadog.android.rum.RumMonitor import java.lang.IllegalArgumentException @@ -45,7 +44,6 @@ interface DatadogWrapper { */ fun initialize( context: Context, - credentials: Credentials, configuration: Configuration, consent: TrackingConsent ) @@ -66,13 +64,6 @@ interface DatadogWrapper { extraInfo: Map ) - /** - * Registers a given monitor in [GlobalRum]. - * - * @param rumMonitor to register - */ - fun registerRumMonitor(rumMonitor: RumMonitor) - /** * Adds global attributes. * diff --git a/packages/core/android/src/main/kotlin/com/datadog/reactnative/DdLogsImplementation.kt b/packages/core/android/src/main/kotlin/com/datadog/reactnative/DdLogsImplementation.kt index 5dbcf41c8..f57b00ff8 100644 --- a/packages/core/android/src/main/kotlin/com/datadog/reactnative/DdLogsImplementation.kt +++ b/packages/core/android/src/main/kotlin/com/datadog/reactnative/DdLogsImplementation.kt @@ -20,9 +20,8 @@ class DdLogsImplementation( ) { private val reactNativeLogger: Logger by lazy { logger ?: Logger.Builder() - .setDatadogLogsEnabled(true) .setLogcatLogsEnabled(true) - .setLoggerName("DdLogs") + .setName("DdLogs") .build() } diff --git a/packages/core/android/src/main/kotlin/com/datadog/reactnative/DdRumImplementation.kt b/packages/core/android/src/main/kotlin/com/datadog/reactnative/DdRumImplementation.kt index 4fba8f88a..f5d3b58fa 100644 --- a/packages/core/android/src/main/kotlin/com/datadog/reactnative/DdRumImplementation.kt +++ b/packages/core/android/src/main/kotlin/com/datadog/reactnative/DdRumImplementation.kt @@ -6,7 +6,7 @@ package com.datadog.reactnative -import com.datadog.android.rum.GlobalRum +import com.datadog.android.rum.GlobalRumMonitor import com.datadog.android.rum.RumActionType import com.datadog.android.rum.RumAttributes import com.datadog.android.rum.RumErrorSource @@ -37,7 +37,7 @@ class DdRumImplementation { val attributes = context.toHashMap().toMutableMap().apply { put(RumAttributes.INTERNAL_TIMESTAMP, timestampMs.toLong()) } - GlobalRum.get().startView( + GlobalRumMonitor.get().startView( key = key, name = name, attributes = attributes @@ -55,7 +55,7 @@ class DdRumImplementation { val attributes = context.toHashMap().toMutableMap().apply { put(RumAttributes.INTERNAL_TIMESTAMP, timestampMs.toLong()) } - GlobalRum.get().stopView( + GlobalRumMonitor.get().stopView( key = key, attributes = attributes ) @@ -79,7 +79,7 @@ class DdRumImplementation { val attributes = context.toHashMap().toMutableMap().apply { put(RumAttributes.INTERNAL_TIMESTAMP, timestampMs.toLong()) } - GlobalRum.get().startUserAction( + GlobalRumMonitor.get().startAction( type = type.asRumActionType(), name = name, attributes = attributes @@ -104,7 +104,7 @@ class DdRumImplementation { val attributes = context.toHashMap().toMutableMap().apply { put(RumAttributes.INTERNAL_TIMESTAMP, timestampMs.toLong()) } - GlobalRum.get().stopUserAction( + GlobalRumMonitor.get().stopAction( type = type.asRumActionType(), name = name, attributes = attributes @@ -129,7 +129,7 @@ class DdRumImplementation { val attributes = context.toHashMap().toMutableMap().apply { put(RumAttributes.INTERNAL_TIMESTAMP, timestampMs.toLong()) } - GlobalRum.get().addUserAction( + GlobalRumMonitor.get().addAction( type = type.asRumActionType(), name = name, attributes = attributes @@ -157,7 +157,7 @@ class DdRumImplementation { val attributes = context.toHashMap().toMutableMap().apply { put(RumAttributes.INTERNAL_TIMESTAMP, timestampMs.toLong()) } - GlobalRum.get().startResource( + GlobalRumMonitor.get().startResource( key = key, method = method, url = url, @@ -193,7 +193,7 @@ class DdRumImplementation { } else { size.toLong() } - GlobalRum.get().stopResource( + GlobalRumMonitor.get().stopResource( key = key, statusCode = statusCode.toInt(), kind = kind.asRumResourceKind(), @@ -223,7 +223,7 @@ class DdRumImplementation { val attributes = context.toHashMap().toMutableMap().apply { put(RumAttributes.INTERNAL_TIMESTAMP, timestampMs.toLong()) } - GlobalRum.get().addErrorWithStacktrace( + GlobalRumMonitor.get().addErrorWithStacktrace( message = message, source = source.asErrorSource(), stacktrace = stacktrace, @@ -237,7 +237,7 @@ class DdRumImplementation { * @param name The name of the new custom timing attribute. Timings can be nested up to 8 levels deep. Names using more than 8 levels will be sanitized by SDK. */ fun addTiming(name: String, promise: Promise) { - GlobalRum.get().addTiming(name) + GlobalRumMonitor.get().addTiming(name) promise.resolve(null) } @@ -245,7 +245,7 @@ class DdRumImplementation { * Stops the current RUM Session. */ fun stopSession(promise: Promise) { - GlobalRum.get().stopSession() + GlobalRumMonitor.get().stopSession() promise.resolve(null) } @@ -258,7 +258,7 @@ class DdRumImplementation { fun addFeatureFlagEvaluation(name: String, value: ReadableMap, promise: Promise) { val value = value.toHashMap()["value"] if (value != null) { - GlobalRum.get().addFeatureFlagEvaluation(name, value) + GlobalRumMonitor.get().addFeatureFlagEvaluation(name, value) } promise.resolve(null) } diff --git a/packages/core/android/src/main/kotlin/com/datadog/reactnative/DdSdkConfigurationExt.kt b/packages/core/android/src/main/kotlin/com/datadog/reactnative/DdSdkConfigurationExt.kt index 23e2593c9..c2ed552bb 100644 --- a/packages/core/android/src/main/kotlin/com/datadog/reactnative/DdSdkConfigurationExt.kt +++ b/packages/core/android/src/main/kotlin/com/datadog/reactnative/DdSdkConfigurationExt.kt @@ -6,7 +6,7 @@ package com.datadog.reactnative -import com.datadog.android.tracing.TracingHeaderType +import com.datadog.android.trace.TracingHeaderType import com.facebook.react.bridge.ReadableArray import com.facebook.react.bridge.ReadableMap import com.facebook.react.bridge.WritableNativeMap diff --git a/packages/core/android/src/main/kotlin/com/datadog/reactnative/DdSdkImplementation.kt b/packages/core/android/src/main/kotlin/com/datadog/reactnative/DdSdkImplementation.kt index 3adcb9306..d3459c75d 100644 --- a/packages/core/android/src/main/kotlin/com/datadog/reactnative/DdSdkImplementation.kt +++ b/packages/core/android/src/main/kotlin/com/datadog/reactnative/DdSdkImplementation.kt @@ -11,22 +11,26 @@ import android.content.pm.PackageManager import android.util.Log import android.view.Choreographer import com.datadog.android.DatadogSite -import com.datadog.android._InternalProxy import com.datadog.android.core.configuration.BatchSize import com.datadog.android.core.configuration.Configuration -import com.datadog.android.core.configuration.Credentials import com.datadog.android.core.configuration.UploadFrequency -import com.datadog.android.core.configuration.VitalsUpdateFrequency import com.datadog.android.event.EventMapper +import com.datadog.android.log.Logs +import com.datadog.android.log.LogsConfiguration import com.datadog.android.privacy.TrackingConsent -import com.datadog.android.rum.GlobalRum -import com.datadog.android.rum.RumMonitor +import com.datadog.android.rum.configuration.VitalsUpdateFrequency +import com.datadog.android.rum.GlobalRumMonitor +import com.datadog.android.rum.Rum +import com.datadog.android.rum.RumConfiguration import com.datadog.android.rum.RumPerformanceMetric +import com.datadog.android.rum._RumInternalProxy import com.datadog.android.rum.model.ActionEvent import com.datadog.android.rum.model.ResourceEvent import com.datadog.android.rum.tracking.ActivityViewTrackingStrategy import com.datadog.android.telemetry.model.TelemetryConfigurationEvent -import com.datadog.android.tracing.TracingHeaderType +import com.datadog.android.trace.Trace +import com.datadog.android.trace.TraceConfiguration +import com.datadog.android.trace.TracingHeaderType import com.facebook.react.bridge.Promise import com.facebook.react.bridge.ReactApplicationContext import com.facebook.react.bridge.ReadableArray @@ -54,16 +58,21 @@ class DdSdkImplementation( */ fun initialize(configuration: ReadableMap, promise: Promise) { val ddSdkConfiguration = configuration.asDdSdkConfiguration() - val credentials = buildCredentials(ddSdkConfiguration) - val nativeConfiguration = buildConfiguration(ddSdkConfiguration) + val sdkConfiguration = buildSDKConfiguration(ddSdkConfiguration) + val rumConfiguration = buildRUMConfiguration(ddSdkConfiguration) val trackingConsent = buildTrackingConsent(ddSdkConfiguration.trackingConsent) configureSdkVerbosity(ddSdkConfiguration) - datadog.initialize(appContext, credentials, nativeConfiguration, trackingConsent) + datadog.initialize(appContext, sdkConfiguration, trackingConsent) - datadog.registerRumMonitor(RumMonitor.Builder().build()) + Rum.enable(rumConfiguration) monitorJsRefreshRate(ddSdkConfiguration) + + Trace.enable(TraceConfiguration.Builder().build()) + + Logs.enable(LogsConfiguration.Builder().build()) + initialized.set(true) promise.resolve(null) @@ -171,49 +180,24 @@ class DdSdkImplementation( } @Suppress("ComplexMethod", "LongMethod", "UnsafeCallOnNullableType") - private fun buildConfiguration(configuration: DdSdkConfiguration): Configuration { - val additionalConfig = configuration.additionalConfig?.toMutableMap() - - val versionSuffix = configuration.additionalConfig?.get(DD_VERSION_SUFFIX) as? String - if (versionSuffix != null && additionalConfig != null) { - val defaultVersion = getDefaultAppVersion() - additionalConfig.put(DD_VERSION, defaultVersion + versionSuffix) - } - + private fun buildRUMConfiguration(configuration: DdSdkConfiguration): RumConfiguration { val configBuilder = - Configuration.Builder( - logsEnabled = true, - tracesEnabled = true, - crashReportsEnabled = configuration.nativeCrashReportEnabled - ?: false, - rumEnabled = true + RumConfiguration.Builder( + applicationId = configuration.applicationId!! ) - .setAdditionalConfiguration( - additionalConfig?.filterValues { it != null }?.mapValues { - it.value!! - } - ?: emptyMap() - ) if (configuration.sampleRate != null) { - configBuilder.sampleRumSessions(configuration.sampleRate.toFloat()) + configBuilder.setSessionSampleRate(configuration.sampleRate.toFloat()) } configBuilder.trackFrustrations(configuration.trackFrustrations ?: true) - configBuilder.trackBackgroundRumEvents(configuration.trackBackgroundEvents ?: false) + configBuilder.trackBackgroundEvents(configuration.trackBackgroundEvents ?: false) - configBuilder.useSite(buildSite(configuration.site)) configBuilder.setVitalsUpdateFrequency( buildVitalUpdateFrequency(configuration.vitalsUpdateFrequency) ) - configBuilder.setUploadFrequency( - buildUploadFrequency(configuration.uploadFrequency) - ) - configBuilder.setBatchSize( - buildBatchSize(configuration.batchSize) - ) val telemetrySampleRate = (configuration.telemetrySampleRate as? Number)?.toFloat() - telemetrySampleRate?.let { configBuilder.sampleTelemetry(it) } + telemetrySampleRate?.let { configBuilder.setTelemetrySampleRate(it) } val longTask = (configuration.nativeLongTaskThresholdMs as? Number)?.toLong() if (longTask != null) { @@ -231,25 +215,10 @@ class DdSdkImplementation( val interactionTracking = configuration.additionalConfig?.get(DD_NATIVE_INTERACTION_TRACKING) as? Boolean if (interactionTracking == false) { - configBuilder.disableInteractionTracking() - } - - @Suppress("UNCHECKED_CAST") - val firstPartyHosts = - (configuration.additionalConfig?.get(DD_FIRST_PARTY_HOSTS) as? ReadableArray) - ?.toArrayList() as? - List - if (firstPartyHosts != null) { - val firstPartyHostsWithHeaderTypes = buildFirstPartyHosts(firstPartyHosts) - - configBuilder.setFirstPartyHostsWithHeaderType(firstPartyHostsWithHeaderTypes) - } - - buildProxyConfiguration(configuration)?.let { (proxy, authenticator) -> - configBuilder.setProxy(proxy, authenticator) + configBuilder.disableUserInteractionTracking() } - configBuilder.setRumResourceEventMapper( + configBuilder.setResourceEventMapper( object : EventMapper { override fun map(event: ResourceEvent): ResourceEvent? { if (event.context?.additionalProperties?.containsKey(DD_DROP_RESOURCE) == @@ -262,7 +231,7 @@ class DdSdkImplementation( } ) - configBuilder.setRumActionEventMapper( + configBuilder.setActionEventMapper( object : EventMapper { override fun map(event: ActionEvent): ActionEvent? { if (event.context?.additionalProperties?.containsKey(DD_DROP_ACTION) == true @@ -274,7 +243,7 @@ class DdSdkImplementation( } ) - _InternalProxy.setTelemetryConfigurationEventMapper( + _RumInternalProxy.setTelemetryConfigurationEventMapper( configBuilder, object : EventMapper { override fun map( @@ -341,15 +310,50 @@ class DdSdkImplementation( return firstPartyHostsWithHeaderTypes } - private fun buildCredentials(configuration: DdSdkConfiguration): Credentials { + private fun buildSDKConfiguration(configuration: DdSdkConfiguration): Configuration { val serviceName = configuration.additionalConfig?.get(DD_SERVICE_NAME) as? String - return Credentials( + val configBuilder = Configuration.Builder( clientToken = configuration.clientToken, - envName = configuration.env, - rumApplicationId = configuration.applicationId, + env = configuration.env, variant = "", - serviceName = serviceName + service = serviceName + ) + + val additionalConfig = configuration.additionalConfig?.toMutableMap() + val versionSuffix = configuration.additionalConfig?.get(DD_VERSION_SUFFIX) as? String + if (versionSuffix != null && additionalConfig != null) { + val defaultVersion = getDefaultAppVersion() + additionalConfig.put(DD_VERSION, defaultVersion + versionSuffix) + } + configBuilder.setAdditionalConfiguration( + additionalConfig?.filterValues { it != null }?.mapValues { + it.value!! + } + ?: emptyMap() + ) + + configBuilder.useSite(buildSite(configuration.site)) + configBuilder.setUploadFrequency( + buildUploadFrequency(configuration.uploadFrequency) + ) + configBuilder.setBatchSize( + buildBatchSize(configuration.batchSize) ) + + buildProxyConfiguration(configuration)?.let { (proxy, authenticator) -> + configBuilder.setProxy(proxy, authenticator) + } + + val firstPartyHosts = + (configuration.additionalConfig?.get(DD_FIRST_PARTY_HOSTS) as? ReadableArray) + ?.toArrayList() as? + List + if (firstPartyHosts != null) { + val firstPartyHostsWithHeaderTypes = buildFirstPartyHosts(firstPartyHosts) + configBuilder.setFirstPartyHostsWithHeaderType(firstPartyHostsWithHeaderTypes) + } + + return configBuilder.build() } internal fun buildTrackingConsent(trackingConsent: String?): TrackingConsent { @@ -489,7 +493,7 @@ class DdSdkImplementation( return { if (jsRefreshRateMonitoringEnabled && it > 0.0) { - GlobalRum.get() + GlobalRumMonitor.get() ._getInternal() ?.updatePerformanceMetric(RumPerformanceMetric.JS_FRAME_TIME, it) } @@ -499,7 +503,7 @@ class DdSdkImplementation( ddSdkConfiguration.longTaskThresholdMs?.toLong() ?: 0L ) ) { - GlobalRum.get()._getInternal()?.addLongTask(it.toLong(), "javascript") + GlobalRumMonitor.get()._getInternal()?.addLongTask(it.toLong(), "javascript") } } } diff --git a/packages/core/android/src/main/kotlin/com/datadog/reactnative/DdTraceImplementation.kt b/packages/core/android/src/main/kotlin/com/datadog/reactnative/DdTraceImplementation.kt index c69b26ebe..7f47221f2 100644 --- a/packages/core/android/src/main/kotlin/com/datadog/reactnative/DdTraceImplementation.kt +++ b/packages/core/android/src/main/kotlin/com/datadog/reactnative/DdTraceImplementation.kt @@ -6,18 +6,26 @@ package com.datadog.reactnative -import com.datadog.android.tracing.AndroidTracer +import com.datadog.android.trace.AndroidTracer +import com.datadog.android.trace.Trace +import com.datadog.android.trace.TraceConfiguration import com.facebook.react.bridge.Promise import com.facebook.react.bridge.ReadableMap import io.opentracing.Span import io.opentracing.Tracer +import io.opentracing.util.GlobalTracer import java.util.concurrent.TimeUnit /** * The entry point to use Datadog's Trace feature. */ class DdTraceImplementation( - private val tracerProvider: () -> Tracer = { AndroidTracer.Builder().build() } + private val tracerProvider: () -> Tracer = { + val tracer = AndroidTracer.Builder().build() + GlobalTracer.registerIfAbsent(tracer) + + GlobalTracer.get() + } ) { private val spanMap: MutableMap = mutableMapOf() From b066d6c7d2c3f1165e73944babc2fa06ff0c7bd6 Mon Sep 17 00:00:00 2001 From: louiszawadzki Date: Thu, 31 Aug 2023 15:42:13 +0200 Subject: [PATCH 02/28] Extract features enablement to Datadog Wrapper --- .../datadog/reactnative/DatadogSDKWrapper.kt | 18 +++++++++++ .../com/datadog/reactnative/DatadogWrapper.kt | 30 +++++++++++++++++++ .../reactnative/DdSdkImplementation.kt | 9 ++---- 3 files changed, 51 insertions(+), 6 deletions(-) diff --git a/packages/core/android/src/main/kotlin/com/datadog/reactnative/DatadogSDKWrapper.kt b/packages/core/android/src/main/kotlin/com/datadog/reactnative/DatadogSDKWrapper.kt index 7918dcb52..d20a5d586 100644 --- a/packages/core/android/src/main/kotlin/com/datadog/reactnative/DatadogSDKWrapper.kt +++ b/packages/core/android/src/main/kotlin/com/datadog/reactnative/DatadogSDKWrapper.kt @@ -9,8 +9,14 @@ package com.datadog.reactnative import android.content.Context import com.datadog.android.Datadog import com.datadog.android.core.configuration.Configuration +import com.datadog.android.log.Logs +import com.datadog.android.log.LogsConfiguration import com.datadog.android.privacy.TrackingConsent import com.datadog.android.rum.GlobalRumMonitor +import com.datadog.android.rum.Rum +import com.datadog.android.rum.RumConfiguration +import com.datadog.android.trace.Trace +import com.datadog.android.trace.TraceConfiguration import com.datadog.android.webview.WebViewTracking internal class DatadogSDKWrapper : DatadogWrapper { @@ -27,6 +33,18 @@ internal class DatadogSDKWrapper : DatadogWrapper { Datadog.initialize(context, configuration, consent) } + override fun enableRum(configuration: RumConfiguration) { + Rum.enable(configuration) + } + + override fun enableLogs(configuration: LogsConfiguration) { + Logs.enable(configuration) + } + + override fun enableTrace(configuration: TraceConfiguration) { + Trace.enable(configuration) + } + override fun setUserInfo( id: String?, name: String?, diff --git a/packages/core/android/src/main/kotlin/com/datadog/reactnative/DatadogWrapper.kt b/packages/core/android/src/main/kotlin/com/datadog/reactnative/DatadogWrapper.kt index c568082e7..a0fdcd847 100644 --- a/packages/core/android/src/main/kotlin/com/datadog/reactnative/DatadogWrapper.kt +++ b/packages/core/android/src/main/kotlin/com/datadog/reactnative/DatadogWrapper.kt @@ -8,8 +8,11 @@ package com.datadog.reactnative import android.content.Context import com.datadog.android.core.configuration.Configuration +import com.datadog.android.log.LogsConfiguration import com.datadog.android.privacy.TrackingConsent +import com.datadog.android.rum.RumConfiguration import com.datadog.android.rum.RumMonitor +import com.datadog.android.trace.TraceConfiguration import java.lang.IllegalArgumentException /** @@ -48,6 +51,33 @@ interface DatadogWrapper { consent: TrackingConsent ) + /** + * Enables the RUM feature of the SDK. + * + * @param configuration the configuration for the RUM feature + */ + fun enableRum( + configuration: RumConfiguration + ) + + /** + * Enables the Logs feature of the SDK. + * + * @param configuration the configuration for the Logs feature + */ + fun enableLogs( + configuration: LogsConfiguration + ) + + /** + * Enables the Trace feature of the SDK. + * + * @param configuration the configuration for the Trace feature + */ + fun enableTrace( + configuration: TraceConfiguration + ) + /** * Sets the user information. * diff --git a/packages/core/android/src/main/kotlin/com/datadog/reactnative/DdSdkImplementation.kt b/packages/core/android/src/main/kotlin/com/datadog/reactnative/DdSdkImplementation.kt index d3459c75d..88e42e75a 100644 --- a/packages/core/android/src/main/kotlin/com/datadog/reactnative/DdSdkImplementation.kt +++ b/packages/core/android/src/main/kotlin/com/datadog/reactnative/DdSdkImplementation.kt @@ -15,12 +15,10 @@ import com.datadog.android.core.configuration.BatchSize import com.datadog.android.core.configuration.Configuration import com.datadog.android.core.configuration.UploadFrequency import com.datadog.android.event.EventMapper -import com.datadog.android.log.Logs import com.datadog.android.log.LogsConfiguration import com.datadog.android.privacy.TrackingConsent import com.datadog.android.rum.configuration.VitalsUpdateFrequency import com.datadog.android.rum.GlobalRumMonitor -import com.datadog.android.rum.Rum import com.datadog.android.rum.RumConfiguration import com.datadog.android.rum.RumPerformanceMetric import com.datadog.android.rum._RumInternalProxy @@ -28,7 +26,6 @@ import com.datadog.android.rum.model.ActionEvent import com.datadog.android.rum.model.ResourceEvent import com.datadog.android.rum.tracking.ActivityViewTrackingStrategy import com.datadog.android.telemetry.model.TelemetryConfigurationEvent -import com.datadog.android.trace.Trace import com.datadog.android.trace.TraceConfiguration import com.datadog.android.trace.TracingHeaderType import com.facebook.react.bridge.Promise @@ -66,12 +63,12 @@ class DdSdkImplementation( datadog.initialize(appContext, sdkConfiguration, trackingConsent) - Rum.enable(rumConfiguration) + datadog.enableRum(rumConfiguration) monitorJsRefreshRate(ddSdkConfiguration) - Trace.enable(TraceConfiguration.Builder().build()) + datadog.enableTrace(TraceConfiguration.Builder().build()) - Logs.enable(LogsConfiguration.Builder().build()) + datadog.enableLogs(LogsConfiguration.Builder().build()) initialized.set(true) From 45341904c300c8fb5da7cb23b1d39f191a87fcee Mon Sep 17 00:00:00 2001 From: louiszawadzki Date: Thu, 31 Aug 2023 17:26:44 +0200 Subject: [PATCH 03/28] Fix NoOpViewTrackingStrategy after v2 --- .../kotlin/com/datadog/reactnative/NoOpViewTrackingStrategy.kt | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/packages/core/android/src/main/kotlin/com/datadog/reactnative/NoOpViewTrackingStrategy.kt b/packages/core/android/src/main/kotlin/com/datadog/reactnative/NoOpViewTrackingStrategy.kt index 198827a61..929857f0a 100644 --- a/packages/core/android/src/main/kotlin/com/datadog/reactnative/NoOpViewTrackingStrategy.kt +++ b/packages/core/android/src/main/kotlin/com/datadog/reactnative/NoOpViewTrackingStrategy.kt @@ -7,13 +7,14 @@ package com.datadog.reactnative import android.content.Context +import com.datadog.android.api.SdkCore import com.datadog.android.rum.tracking.ViewTrackingStrategy /** * No-op implementation of the [ViewTrackingStrategy]. */ object NoOpViewTrackingStrategy : ViewTrackingStrategy { - override fun register(context: Context) { + override fun register(sdkCore: SdkCore, context: Context) { // No-op } From 94fd15a4c728909dbdd4d6bb38d2e58f629c42f3 Mon Sep 17 00:00:00 2001 From: louiszawadzki Date: Thu, 31 Aug 2023 17:33:17 +0200 Subject: [PATCH 04/28] Fix Kotlin upgrade errors --- .../kotlin/com/datadog/reactnative/DdRumImplementation.kt | 6 +++--- .../kotlin/com/datadog/reactnative/DdSdkImplementation.kt | 7 ++++--- 2 files changed, 7 insertions(+), 6 deletions(-) diff --git a/packages/core/android/src/main/kotlin/com/datadog/reactnative/DdRumImplementation.kt b/packages/core/android/src/main/kotlin/com/datadog/reactnative/DdRumImplementation.kt index f5d3b58fa..0d5d2c00c 100644 --- a/packages/core/android/src/main/kotlin/com/datadog/reactnative/DdRumImplementation.kt +++ b/packages/core/android/src/main/kotlin/com/datadog/reactnative/DdRumImplementation.kt @@ -253,10 +253,10 @@ class DdRumImplementation { * Adds result of evaluating a feature flag to the view. * Feature flag evaluations are local to the active view and are cleared when the view is stopped. * @param name The name of the feature flag - * @param value The value the feature flag evaluated to, encapsulated in a Map + * @param valueAsMap The value the feature flag evaluated to, encapsulated in a Map */ - fun addFeatureFlagEvaluation(name: String, value: ReadableMap, promise: Promise) { - val value = value.toHashMap()["value"] + fun addFeatureFlagEvaluation(name: String, valueAsMap: ReadableMap, promise: Promise) { + val value = valueAsMap.toHashMap()["value"] if (value != null) { GlobalRumMonitor.get().addFeatureFlagEvaluation(name, value) } diff --git a/packages/core/android/src/main/kotlin/com/datadog/reactnative/DdSdkImplementation.kt b/packages/core/android/src/main/kotlin/com/datadog/reactnative/DdSdkImplementation.kt index 88e42e75a..78840e58a 100644 --- a/packages/core/android/src/main/kotlin/com/datadog/reactnative/DdSdkImplementation.kt +++ b/packages/core/android/src/main/kotlin/com/datadog/reactnative/DdSdkImplementation.kt @@ -171,7 +171,8 @@ class DdSdkImplementation( return packageInfo?.let { // we need to use the deprecated method because getLongVersionCode method is only // available from API 28 and above - @Suppress("DEPRECATION") it.versionName ?: it.versionCode.toString() + @Suppress("DEPRECATION") + it.versionName ?: it.versionCode.toString() } ?: DEFAULT_APP_VERSION } @@ -341,6 +342,7 @@ class DdSdkImplementation( configBuilder.setProxy(proxy, authenticator) } + @Suppress("UNCHECKED_CAST") val firstPartyHosts = (configuration.additionalConfig?.get(DD_FIRST_PARTY_HOSTS) as? ReadableArray) ?.toArrayList() as? @@ -436,8 +438,7 @@ class DdSdkImplementation( } private fun buildUploadFrequency(uploadFrequency: String?): UploadFrequency { - val uploadFrequency = uploadFrequency?.lowercase(Locale.US) - return when (uploadFrequency) { + return when (uploadFrequency?.lowercase(Locale.US)) { "rare" -> UploadFrequency.RARE "average" -> UploadFrequency.AVERAGE "frequent" -> UploadFrequency.FREQUENT From a951a4844a61ca937335f13a32c4ec4e52222fa0 Mon Sep 17 00:00:00 2001 From: louiszawadzki Date: Fri, 1 Sep 2023 13:47:33 +0200 Subject: [PATCH 05/28] Get RUM monitor from DD Wrapper --- .../datadog/reactnative/DatadogSDKWrapper.kt | 7 +++++- .../com/datadog/reactnative/DatadogWrapper.kt | 6 +++++ .../reactnative/DdRumImplementation.kt | 25 +++++++++---------- .../reactnative/DdSdkImplementation.kt | 5 ++-- 4 files changed, 26 insertions(+), 17 deletions(-) diff --git a/packages/core/android/src/main/kotlin/com/datadog/reactnative/DatadogSDKWrapper.kt b/packages/core/android/src/main/kotlin/com/datadog/reactnative/DatadogSDKWrapper.kt index d20a5d586..f6870d890 100644 --- a/packages/core/android/src/main/kotlin/com/datadog/reactnative/DatadogSDKWrapper.kt +++ b/packages/core/android/src/main/kotlin/com/datadog/reactnative/DatadogSDKWrapper.kt @@ -15,6 +15,7 @@ import com.datadog.android.privacy.TrackingConsent import com.datadog.android.rum.GlobalRumMonitor import com.datadog.android.rum.Rum import com.datadog.android.rum.RumConfiguration +import com.datadog.android.rum.RumMonitor import com.datadog.android.trace.Trace import com.datadog.android.trace.TraceConfiguration import com.datadog.android.webview.WebViewTracking @@ -56,7 +57,7 @@ internal class DatadogSDKWrapper : DatadogWrapper { override fun addRumGlobalAttributes(attributes: Map) { attributes.forEach { - GlobalRumMonitor.get().addAttribute(it.key, it.value) + this.getRumMonitor().addAttribute(it.key, it.value) } } @@ -87,4 +88,8 @@ internal class DatadogSDKWrapper : DatadogWrapper { override fun isInitialized(): Boolean { return Datadog.isInitialized() } + + override fun getRumMonitor(): RumMonitor { + return GlobalRumMonitor.get() + } } diff --git a/packages/core/android/src/main/kotlin/com/datadog/reactnative/DatadogWrapper.kt b/packages/core/android/src/main/kotlin/com/datadog/reactnative/DatadogWrapper.kt index a0fdcd847..94b9071c4 100644 --- a/packages/core/android/src/main/kotlin/com/datadog/reactnative/DatadogWrapper.kt +++ b/packages/core/android/src/main/kotlin/com/datadog/reactnative/DatadogWrapper.kt @@ -10,6 +10,7 @@ import android.content.Context import com.datadog.android.core.configuration.Configuration import com.datadog.android.log.LogsConfiguration import com.datadog.android.privacy.TrackingConsent +import com.datadog.android.rum.GlobalRumMonitor import com.datadog.android.rum.RumConfiguration import com.datadog.android.rum.RumMonitor import com.datadog.android.trace.TraceConfiguration @@ -130,4 +131,9 @@ interface DatadogWrapper { * Returns whether the SDK is initialized. */ fun isInitialized(): Boolean + + /** + * Returns the RUM Monitor for the default SDK core. + */ + fun getRumMonitor(): RumMonitor } diff --git a/packages/core/android/src/main/kotlin/com/datadog/reactnative/DdRumImplementation.kt b/packages/core/android/src/main/kotlin/com/datadog/reactnative/DdRumImplementation.kt index 0d5d2c00c..3764248d0 100644 --- a/packages/core/android/src/main/kotlin/com/datadog/reactnative/DdRumImplementation.kt +++ b/packages/core/android/src/main/kotlin/com/datadog/reactnative/DdRumImplementation.kt @@ -6,7 +6,6 @@ package com.datadog.reactnative -import com.datadog.android.rum.GlobalRumMonitor import com.datadog.android.rum.RumActionType import com.datadog.android.rum.RumAttributes import com.datadog.android.rum.RumErrorSource @@ -19,7 +18,7 @@ import java.util.Locale * The entry point to use Datadog's RUM feature. */ @Suppress("TooManyFunctions") -class DdRumImplementation { +class DdRumImplementation(private val datadog: DatadogWrapper = DatadogSDKWrapper()) { /** * Start tracking a RUM View. * @param key The view unique key identifier. @@ -37,7 +36,7 @@ class DdRumImplementation { val attributes = context.toHashMap().toMutableMap().apply { put(RumAttributes.INTERNAL_TIMESTAMP, timestampMs.toLong()) } - GlobalRumMonitor.get().startView( + datadog.getRumMonitor().startView( key = key, name = name, attributes = attributes @@ -55,7 +54,7 @@ class DdRumImplementation { val attributes = context.toHashMap().toMutableMap().apply { put(RumAttributes.INTERNAL_TIMESTAMP, timestampMs.toLong()) } - GlobalRumMonitor.get().stopView( + datadog.getRumMonitor().stopView( key = key, attributes = attributes ) @@ -79,7 +78,7 @@ class DdRumImplementation { val attributes = context.toHashMap().toMutableMap().apply { put(RumAttributes.INTERNAL_TIMESTAMP, timestampMs.toLong()) } - GlobalRumMonitor.get().startAction( + datadog.getRumMonitor().startAction( type = type.asRumActionType(), name = name, attributes = attributes @@ -104,7 +103,7 @@ class DdRumImplementation { val attributes = context.toHashMap().toMutableMap().apply { put(RumAttributes.INTERNAL_TIMESTAMP, timestampMs.toLong()) } - GlobalRumMonitor.get().stopAction( + datadog.getRumMonitor().stopAction( type = type.asRumActionType(), name = name, attributes = attributes @@ -129,7 +128,7 @@ class DdRumImplementation { val attributes = context.toHashMap().toMutableMap().apply { put(RumAttributes.INTERNAL_TIMESTAMP, timestampMs.toLong()) } - GlobalRumMonitor.get().addAction( + datadog.getRumMonitor().addAction( type = type.asRumActionType(), name = name, attributes = attributes @@ -157,7 +156,7 @@ class DdRumImplementation { val attributes = context.toHashMap().toMutableMap().apply { put(RumAttributes.INTERNAL_TIMESTAMP, timestampMs.toLong()) } - GlobalRumMonitor.get().startResource( + datadog.getRumMonitor().startResource( key = key, method = method, url = url, @@ -193,7 +192,7 @@ class DdRumImplementation { } else { size.toLong() } - GlobalRumMonitor.get().stopResource( + datadog.getRumMonitor().stopResource( key = key, statusCode = statusCode.toInt(), kind = kind.asRumResourceKind(), @@ -223,7 +222,7 @@ class DdRumImplementation { val attributes = context.toHashMap().toMutableMap().apply { put(RumAttributes.INTERNAL_TIMESTAMP, timestampMs.toLong()) } - GlobalRumMonitor.get().addErrorWithStacktrace( + datadog.getRumMonitor().addErrorWithStacktrace( message = message, source = source.asErrorSource(), stacktrace = stacktrace, @@ -237,7 +236,7 @@ class DdRumImplementation { * @param name The name of the new custom timing attribute. Timings can be nested up to 8 levels deep. Names using more than 8 levels will be sanitized by SDK. */ fun addTiming(name: String, promise: Promise) { - GlobalRumMonitor.get().addTiming(name) + datadog.getRumMonitor().addTiming(name) promise.resolve(null) } @@ -245,7 +244,7 @@ class DdRumImplementation { * Stops the current RUM Session. */ fun stopSession(promise: Promise) { - GlobalRumMonitor.get().stopSession() + datadog.getRumMonitor().stopSession() promise.resolve(null) } @@ -258,7 +257,7 @@ class DdRumImplementation { fun addFeatureFlagEvaluation(name: String, valueAsMap: ReadableMap, promise: Promise) { val value = valueAsMap.toHashMap()["value"] if (value != null) { - GlobalRumMonitor.get().addFeatureFlagEvaluation(name, value) + datadog.getRumMonitor().addFeatureFlagEvaluation(name, value) } promise.resolve(null) } diff --git a/packages/core/android/src/main/kotlin/com/datadog/reactnative/DdSdkImplementation.kt b/packages/core/android/src/main/kotlin/com/datadog/reactnative/DdSdkImplementation.kt index 78840e58a..e26d3c62a 100644 --- a/packages/core/android/src/main/kotlin/com/datadog/reactnative/DdSdkImplementation.kt +++ b/packages/core/android/src/main/kotlin/com/datadog/reactnative/DdSdkImplementation.kt @@ -18,7 +18,6 @@ import com.datadog.android.event.EventMapper import com.datadog.android.log.LogsConfiguration import com.datadog.android.privacy.TrackingConsent import com.datadog.android.rum.configuration.VitalsUpdateFrequency -import com.datadog.android.rum.GlobalRumMonitor import com.datadog.android.rum.RumConfiguration import com.datadog.android.rum.RumPerformanceMetric import com.datadog.android.rum._RumInternalProxy @@ -491,7 +490,7 @@ class DdSdkImplementation( return { if (jsRefreshRateMonitoringEnabled && it > 0.0) { - GlobalRumMonitor.get() + datadog.getRumMonitor() ._getInternal() ?.updatePerformanceMetric(RumPerformanceMetric.JS_FRAME_TIME, it) } @@ -501,7 +500,7 @@ class DdSdkImplementation( ddSdkConfiguration.longTaskThresholdMs?.toLong() ?: 0L ) ) { - GlobalRumMonitor.get()._getInternal()?.addLongTask(it.toLong(), "javascript") + datadog.getRumMonitor()._getInternal()?.addLongTask(it.toLong(), "javascript") } } } From 2a022083f20d16a0c4d74252baaca6569f7f9aae Mon Sep 17 00:00:00 2001 From: louiszawadzki Date: Fri, 1 Sep 2023 16:58:27 +0200 Subject: [PATCH 06/28] Make applicationId mandatory in android config --- .../main/kotlin/com/datadog/reactnative/DdSdkConfiguration.kt | 2 +- .../kotlin/com/datadog/reactnative/DdSdkConfigurationExt.kt | 4 ++-- .../kotlin/com/datadog/reactnative/DdSdkImplementation.kt | 3 ++- .../tools/unit/forge/DdSdkConfigurationForgeryFactory.kt | 2 +- 4 files changed, 6 insertions(+), 5 deletions(-) diff --git a/packages/core/android/src/main/kotlin/com/datadog/reactnative/DdSdkConfiguration.kt b/packages/core/android/src/main/kotlin/com/datadog/reactnative/DdSdkConfiguration.kt index a3f8f667b..87db41ad5 100644 --- a/packages/core/android/src/main/kotlin/com/datadog/reactnative/DdSdkConfiguration.kt +++ b/packages/core/android/src/main/kotlin/com/datadog/reactnative/DdSdkConfiguration.kt @@ -29,7 +29,7 @@ package com.datadog.reactnative data class DdSdkConfiguration( val clientToken: String, val env: String, - val applicationId: String? = null, + val applicationId: String, val nativeCrashReportEnabled: Boolean? = null, val nativeLongTaskThresholdMs: Double? = null, val longTaskThresholdMs: Double? = null, diff --git a/packages/core/android/src/main/kotlin/com/datadog/reactnative/DdSdkConfigurationExt.kt b/packages/core/android/src/main/kotlin/com/datadog/reactnative/DdSdkConfigurationExt.kt index c2ed552bb..f1507f190 100644 --- a/packages/core/android/src/main/kotlin/com/datadog/reactnative/DdSdkConfigurationExt.kt +++ b/packages/core/android/src/main/kotlin/com/datadog/reactnative/DdSdkConfigurationExt.kt @@ -15,7 +15,7 @@ internal fun ReadableMap.asDdSdkConfiguration(): DdSdkConfiguration { return DdSdkConfiguration( clientToken = getString("clientToken").orEmpty(), env = getString("env").orEmpty(), - applicationId = getString("applicationId"), + applicationId = getString("applicationId").orEmpty(), nativeCrashReportEnabled = getBoolean("nativeCrashReportEnabled"), nativeLongTaskThresholdMs = getDouble("nativeLongTaskThresholdMs"), longTaskThresholdMs = getDouble("longTaskThresholdMs"), @@ -63,7 +63,7 @@ internal fun DdSdkConfiguration.toReadableMap(): ReadableMap { val map = WritableNativeMap() map.putString("clientToken", clientToken) map.putString("env", env) - applicationId?.let { map.putString("applicationId", it) } + map.putString("applicationId", applicationId) nativeCrashReportEnabled?.let { map.putBoolean("nativeCrashReportEnabled", it) } nativeLongTaskThresholdMs?.let { map.putDouble("nativeLongTaskThresholdMs", it) } longTaskThresholdMs?.let { map.putDouble("longTaskThresholdMs", it) } diff --git a/packages/core/android/src/main/kotlin/com/datadog/reactnative/DdSdkImplementation.kt b/packages/core/android/src/main/kotlin/com/datadog/reactnative/DdSdkImplementation.kt index e26d3c62a..56d433dde 100644 --- a/packages/core/android/src/main/kotlin/com/datadog/reactnative/DdSdkImplementation.kt +++ b/packages/core/android/src/main/kotlin/com/datadog/reactnative/DdSdkImplementation.kt @@ -180,7 +180,7 @@ class DdSdkImplementation( private fun buildRUMConfiguration(configuration: DdSdkConfiguration): RumConfiguration { val configBuilder = RumConfiguration.Builder( - applicationId = configuration.applicationId!! + applicationId = configuration.applicationId ) if (configuration.sampleRate != null) { configBuilder.setSessionSampleRate(configuration.sampleRate.toFloat()) @@ -329,6 +329,7 @@ class DdSdkImplementation( ?: emptyMap() ) + configBuilder.setCrashReportsEnabled(configuration.nativeCrashReportEnabled ?: false) configBuilder.useSite(buildSite(configuration.site)) configBuilder.setUploadFrequency( buildUploadFrequency(configuration.uploadFrequency) diff --git a/packages/core/android/src/test/kotlin/com/datadog/tools/unit/forge/DdSdkConfigurationForgeryFactory.kt b/packages/core/android/src/test/kotlin/com/datadog/tools/unit/forge/DdSdkConfigurationForgeryFactory.kt index adb0e2587..6ca158254 100644 --- a/packages/core/android/src/test/kotlin/com/datadog/tools/unit/forge/DdSdkConfigurationForgeryFactory.kt +++ b/packages/core/android/src/test/kotlin/com/datadog/tools/unit/forge/DdSdkConfigurationForgeryFactory.kt @@ -17,7 +17,7 @@ class DdSdkConfigurationForgeryFactory : ForgeryFactory { return DdSdkConfiguration( clientToken = forge.aStringMatching("pub[a-f0-9]{32}"), env = forge.anAlphabeticalString(), - applicationId = forge.aNullable { getForgery().toString() }, + applicationId = forge.getForgery().toString(), nativeCrashReportEnabled = forge.aNullable { aBool() }, nativeLongTaskThresholdMs = forge.aNullable { aDouble(100.0, 5000.0) }, longTaskThresholdMs = forge.aDouble(0.0, 100.0), From d7a280a9f942d57379909756301a4ed4cc27dde3 Mon Sep 17 00:00:00 2001 From: louiszawadzki Date: Thu, 31 Aug 2023 17:40:53 +0200 Subject: [PATCH 07/28] Fix tests after v2 upgrade --- .../com/datadog/reactnative/DdRumTest.kt | 34 +- .../com/datadog/reactnative/DdSdkTest.kt | 1256 +++++++++-------- .../tools/unit/DdSdkConfigurationExt.kt | 2 +- .../com/datadog/tools/unit/MockRumMonitor.kt | 49 + ...lemetryConfigurationEventForgeryFactory.kt | 1 + 5 files changed, 697 insertions(+), 645 deletions(-) create mode 100644 packages/core/android/src/test/kotlin/com/datadog/tools/unit/MockRumMonitor.kt diff --git a/packages/core/android/src/test/kotlin/com/datadog/reactnative/DdRumTest.kt b/packages/core/android/src/test/kotlin/com/datadog/reactnative/DdRumTest.kt index e1f12c5a5..a328cecbc 100644 --- a/packages/core/android/src/test/kotlin/com/datadog/reactnative/DdRumTest.kt +++ b/packages/core/android/src/test/kotlin/com/datadog/reactnative/DdRumTest.kt @@ -6,19 +6,15 @@ package com.datadog.reactnative -import com.datadog.android.rum.GlobalRum -import com.datadog.android.rum.RumActionType -import com.datadog.android.rum.RumAttributes -import com.datadog.android.rum.RumErrorSource -import com.datadog.android.rum.RumMonitor -import com.datadog.android.rum.RumResourceKind +import com.datadog.android.api.SdkCore +import com.datadog.android.rum.* import com.datadog.tools.unit.forge.BaseConfigurator -import com.datadog.tools.unit.getStaticValue import com.datadog.tools.unit.setStaticValue import com.datadog.tools.unit.toReadableMap import com.facebook.react.bridge.Promise -import com.nhaarman.mockitokotlin2.mock +import com.nhaarman.mockitokotlin2.doReturn import com.nhaarman.mockitokotlin2.verify +import com.nhaarman.mockitokotlin2.whenever import fr.xgouchet.elmyr.Forge import fr.xgouchet.elmyr.annotation.BoolForgery import fr.xgouchet.elmyr.annotation.DoubleForgery @@ -29,7 +25,6 @@ import fr.xgouchet.elmyr.annotation.StringForgeryType import fr.xgouchet.elmyr.junit5.ForgeConfiguration import fr.xgouchet.elmyr.junit5.ForgeExtension import java.util.Date -import java.util.concurrent.atomic.AtomicBoolean import org.junit.jupiter.api.AfterEach import org.junit.jupiter.api.BeforeEach import org.junit.jupiter.api.Test @@ -55,6 +50,9 @@ internal class DdRumTest { @Mock lateinit var mockRumMonitor: RumMonitor + @Mock + lateinit var mockDatadog: DatadogWrapper + @Mock lateinit var mockPromise: Promise @@ -65,7 +63,7 @@ internal class DdRumTest { @BeforeEach fun `set up`(forge: Forge) { - GlobalRum.registerIfAbsent(mockRumMonitor) + whenever(mockDatadog.getRumMonitor()) doReturn mockRumMonitor fakeContext = forge.aMap { anAlphabeticalString() to aNullable { @@ -79,13 +77,11 @@ internal class DdRumTest { } } - testedDdRum = DdRumImplementation() + testedDdRum = DdRumImplementation(mockDatadog) } @AfterEach fun `tear down`() { - GlobalRum.javaClass.setStaticValue("monitor", mock()) - GlobalRum.javaClass.getStaticValue("isRegistered").set(false) } @Test @@ -138,7 +134,7 @@ internal class DdRumTest { ) // Then - verify(mockRumMonitor).addUserAction(type, name, updatedContext) + verify(mockRumMonitor).addAction(type, name, updatedContext) } @Test @@ -155,7 +151,7 @@ internal class DdRumTest { testedDdRum.addAction(type, name, fakeContext.toReadableMap(), fakeTimestamp, mockPromise) // Then - verify(mockRumMonitor).addUserAction(RumActionType.CUSTOM, name, updatedContext) + verify(mockRumMonitor).addAction(RumActionType.CUSTOM, name, updatedContext) } @Test @@ -175,7 +171,7 @@ internal class DdRumTest { ) // Then - verify(mockRumMonitor).startUserAction(type, name, updatedContext) + verify(mockRumMonitor).startAction(type, name, updatedContext) } @Test @@ -192,7 +188,7 @@ internal class DdRumTest { testedDdRum.startAction(type, name, fakeContext.toReadableMap(), fakeTimestamp, mockPromise) // Then - verify(mockRumMonitor).startUserAction(RumActionType.CUSTOM, name, updatedContext) + verify(mockRumMonitor).startAction(RumActionType.CUSTOM, name, updatedContext) } @Test @@ -212,7 +208,7 @@ internal class DdRumTest { ) // Then - verify(mockRumMonitor).stopUserAction(type, name, updatedContext) + verify(mockRumMonitor).stopAction(type, name, updatedContext) } @Test @@ -229,7 +225,7 @@ internal class DdRumTest { testedDdRum.stopAction(type, name, fakeContext.toReadableMap(), fakeTimestamp, mockPromise) // Then - verify(mockRumMonitor).stopUserAction(RumActionType.CUSTOM, name, updatedContext) + verify(mockRumMonitor).stopAction(RumActionType.CUSTOM, name, updatedContext) } @Test diff --git a/packages/core/android/src/test/kotlin/com/datadog/reactnative/DdSdkTest.kt b/packages/core/android/src/test/kotlin/com/datadog/reactnative/DdSdkTest.kt index 6ec62d4f6..e83a8a77a 100644 --- a/packages/core/android/src/test/kotlin/com/datadog/reactnative/DdSdkTest.kt +++ b/packages/core/android/src/test/kotlin/com/datadog/reactnative/DdSdkTest.kt @@ -12,28 +12,21 @@ import android.view.Choreographer import com.datadog.android.DatadogSite import com.datadog.android.core.configuration.BatchSize import com.datadog.android.core.configuration.Configuration -import com.datadog.android.core.configuration.Credentials import com.datadog.android.core.configuration.UploadFrequency -import com.datadog.android.core.configuration.VitalsUpdateFrequency import com.datadog.android.event.EventMapper -import com.datadog.android.plugin.DatadogPlugin +import com.datadog.android.log.LogsConfiguration import com.datadog.android.privacy.TrackingConsent -import com.datadog.android.rum.GlobalRum -import com.datadog.android.rum.RumMonitor -import com.datadog.android.rum.RumPerformanceMetric -import com.datadog.android.rum._RumInternalProxy +import com.datadog.android.rum.* +import com.datadog.android.rum.configuration.VitalsUpdateFrequency import com.datadog.android.rum.model.ActionEvent import com.datadog.android.rum.model.ResourceEvent import com.datadog.android.rum.tracking.ActivityViewTrackingStrategy import com.datadog.android.telemetry.model.TelemetryConfigurationEvent -import com.datadog.android.tracing.TracingHeaderType +import com.datadog.android.trace.TraceConfiguration +import com.datadog.android.trace.TracingHeaderType +import com.datadog.tools.unit.* import com.datadog.tools.unit.GenericAssert.Companion.assertThat import com.datadog.tools.unit.forge.BaseConfigurator -import com.datadog.tools.unit.getStaticValue -import com.datadog.tools.unit.setStaticValue -import com.datadog.tools.unit.toReadableArray -import com.datadog.tools.unit.toReadableJavaOnlyMap -import com.datadog.tools.unit.toReadableMap import com.facebook.react.bridge.Promise import com.facebook.react.bridge.ReactApplicationContext import com.facebook.react.bridge.ReadableMap @@ -111,7 +104,7 @@ internal class DdSdkTest { lateinit var mockContext: ReactApplicationContext @Mock - lateinit var mockRumMonitor: RumMonitor + lateinit var mockRumMonitor: MockRumMonitor @Mock lateinit var mockRumInternalProxy: _RumInternalProxy @@ -133,7 +126,7 @@ internal class DdSdkTest { @BeforeEach fun `set up`() { - GlobalRum.registerIfAbsent(mockRumMonitor) + whenever(mockDatadog.getRumMonitor()) doReturn mockRumMonitor whenever(mockRumMonitor._getInternal()) doReturn mockRumInternalProxy doNothing().whenever(mockChoreographer).postFrameCallback(any()) @@ -156,8 +149,6 @@ internal class DdSdkTest { @AfterEach fun `tear down`() { GlobalState.globalAttributes.clear() - GlobalRum.javaClass.setStaticValue("monitor", mock()) - GlobalRum.javaClass.getStaticValue("isRegistered").set(false) } // region initialize / nativeCrashReportEnabled @@ -166,8 +157,10 @@ internal class DdSdkTest { fun `𝕄 initialize native SDK 𝕎 initialize() {nativeCrashReportEnabled=true}`() { // Given val bridgeConfiguration = fakeConfiguration.copy(nativeCrashReportEnabled = true) - val credentialCaptor = argumentCaptor() - val configCaptor = argumentCaptor() + val sdkConfigCaptor = argumentCaptor() + val rumConfigCaptor = argumentCaptor() + val logsConfigCaptor = argumentCaptor() + val traceConfigCaptor = argumentCaptor() // When testedBridgeSdk.initialize(bridgeConfiguration.toReadableJavaOnlyMap(), mockPromise) @@ -176,46 +169,38 @@ internal class DdSdkTest { inOrder(mockDatadog) { verify(mockDatadog).initialize( same(mockContext), - credentialCaptor.capture(), - configCaptor.capture(), + sdkConfigCaptor.capture(), any() ) - verify(mockDatadog).registerRumMonitor(any()) + verify(mockDatadog).enableRum(rumConfigCaptor.capture()) + verify(mockDatadog).enableTrace(traceConfigCaptor.capture()) + verify(mockDatadog).enableLogs(logsConfigCaptor.capture()) } - assertThat(configCaptor.firstValue) + assertThat(sdkConfigCaptor.firstValue) .hasField("coreConfig") { it.hasFieldEqualTo("needsClearTextHttp", false) it.hasFieldEqualTo("firstPartyHostsWithHeaderTypes", emptyMap()) } - .hasField("logsConfig") { - it.hasFieldEqualTo("plugins", emptyList()) - } - .hasField("tracesConfig") { - it.hasFieldEqualTo("plugins", emptyList()) - } - .hasField("crashReportConfig") { - it.hasFieldEqualTo("plugins", emptyList()) - } - .hasField("rumConfig") { - it.hasFieldEqualTo("plugins", emptyList()) - } + .hasFieldEqualTo("clientToken", fakeConfiguration.clientToken) + .hasFieldEqualTo("env", fakeConfiguration.env) + .hasFieldEqualTo("variant", "") + .hasFieldEqualTo("crashReportsEnabled", true) .hasFieldEqualTo( "additionalConfig", fakeConfiguration.additionalConfig?.filterValues { it != null }.orEmpty() ) - val credentials = credentialCaptor.firstValue - assertThat(credentials.clientToken).isEqualTo(fakeConfiguration.clientToken) - assertThat(credentials.envName).isEqualTo(fakeConfiguration.env) - assertThat(credentials.rumApplicationId).isEqualTo(fakeConfiguration.applicationId) - assertThat(credentials.variant).isEqualTo("") + assertThat(rumConfigCaptor.firstValue) + .hasFieldEqualTo("applicationId", fakeConfiguration.applicationId) } @Test fun `𝕄 initialize native SDK 𝕎 initialize() {nativeCrashReportEnabled=false}`() { // Given fakeConfiguration = fakeConfiguration.copy(nativeCrashReportEnabled = false, site = null) - val credentialCaptor = argumentCaptor() - val configCaptor = argumentCaptor() + val sdkConfigCaptor = argumentCaptor() + val rumConfigCaptor = argumentCaptor() + val logsConfigCaptor = argumentCaptor() + val traceConfigCaptor = argumentCaptor() // When testedBridgeSdk.initialize(fakeConfiguration.toReadableJavaOnlyMap(), mockPromise) @@ -224,44 +209,38 @@ internal class DdSdkTest { inOrder(mockDatadog) { verify(mockDatadog).initialize( same(mockContext), - credentialCaptor.capture(), - configCaptor.capture(), + sdkConfigCaptor.capture(), any() ) - verify(mockDatadog).registerRumMonitor(any()) + verify(mockDatadog).enableRum(rumConfigCaptor.capture()) + verify(mockDatadog).enableTrace(traceConfigCaptor.capture()) + verify(mockDatadog).enableLogs(logsConfigCaptor.capture()) } - assertThat(configCaptor.firstValue) + assertThat(sdkConfigCaptor.firstValue) .hasField("coreConfig") { it.hasFieldEqualTo("needsClearTextHttp", false) it.hasFieldEqualTo("firstPartyHostsWithHeaderTypes", emptyMap()) } - .hasField("logsConfig") { - it.hasFieldEqualTo("plugins", emptyList()) - } - .hasField("tracesConfig") { - it.hasFieldEqualTo("plugins", emptyList()) - } - .hasFieldEqualTo("crashReportConfig", null) - .hasField("rumConfig") { - it.hasFieldEqualTo("plugins", emptyList()) - } + .hasFieldEqualTo("clientToken", fakeConfiguration.clientToken) + .hasFieldEqualTo("env", fakeConfiguration.env) + .hasFieldEqualTo("variant", "") + .hasFieldEqualTo("crashReportsEnabled", false) .hasFieldEqualTo( "additionalConfig", fakeConfiguration.additionalConfig?.filterValues { it != null }.orEmpty() ) - val credentials = credentialCaptor.firstValue - assertThat(credentials.clientToken).isEqualTo(fakeConfiguration.clientToken) - assertThat(credentials.envName).isEqualTo(fakeConfiguration.env) - assertThat(credentials.rumApplicationId).isEqualTo(fakeConfiguration.applicationId) - assertThat(credentials.variant).isEqualTo("") + assertThat(rumConfigCaptor.firstValue) + .hasFieldEqualTo("applicationId", fakeConfiguration.applicationId) } @Test fun `𝕄 initialize native SDK 𝕎 initialize() {nativeCrashReportEnabled=null}`() { // Given fakeConfiguration = fakeConfiguration.copy(nativeCrashReportEnabled = false, site = null) - val credentialCaptor = argumentCaptor() - val configCaptor = argumentCaptor() + val sdkConfigCaptor = argumentCaptor() + val rumConfigCaptor = argumentCaptor() + val logsConfigCaptor = argumentCaptor() + val traceConfigCaptor = argumentCaptor() // When testedBridgeSdk.initialize(fakeConfiguration.toReadableJavaOnlyMap(), mockPromise) @@ -270,36 +249,28 @@ internal class DdSdkTest { inOrder(mockDatadog) { verify(mockDatadog).initialize( same(mockContext), - credentialCaptor.capture(), - configCaptor.capture(), + sdkConfigCaptor.capture(), any() ) - verify(mockDatadog).registerRumMonitor(any()) + verify(mockDatadog).enableRum(rumConfigCaptor.capture()) + verify(mockDatadog).enableTrace(traceConfigCaptor.capture()) + verify(mockDatadog).enableLogs(logsConfigCaptor.capture()) } - assertThat(configCaptor.firstValue) + assertThat(sdkConfigCaptor.firstValue) .hasField("coreConfig") { it.hasFieldEqualTo("needsClearTextHttp", false) it.hasFieldEqualTo("firstPartyHostsWithHeaderTypes", emptyMap()) } - .hasField("logsConfig") { - it.hasFieldEqualTo("plugins", emptyList()) - } - .hasField("tracesConfig") { - it.hasFieldEqualTo("plugins", emptyList()) - } - .hasFieldEqualTo("crashReportConfig", null) - .hasField("rumConfig") { - it.hasFieldEqualTo("plugins", emptyList()) - } + .hasFieldEqualTo("clientToken", fakeConfiguration.clientToken) + .hasFieldEqualTo("env", fakeConfiguration.env) + .hasFieldEqualTo("variant", "") + .hasFieldEqualTo("crashReportsEnabled", false) .hasFieldEqualTo( "additionalConfig", fakeConfiguration.additionalConfig?.filterValues { it != null }.orEmpty() ) - val credentials = credentialCaptor.firstValue - assertThat(credentials.clientToken).isEqualTo(fakeConfiguration.clientToken) - assertThat(credentials.envName).isEqualTo(fakeConfiguration.env) - assertThat(credentials.rumApplicationId).isEqualTo(fakeConfiguration.applicationId) - assertThat(credentials.variant).isEqualTo("") + assertThat(rumConfigCaptor.firstValue) + .hasFieldEqualTo("applicationId", fakeConfiguration.applicationId) } // endregion @@ -309,8 +280,10 @@ internal class DdSdkTest { @Test fun `𝕄 initialize native with sample rate SDK 𝕎 initialize() {}`() { // Given - val credentialCaptor = argumentCaptor() - val configCaptor = argumentCaptor() + val sdkConfigCaptor = argumentCaptor() + val rumConfigCaptor = argumentCaptor() + val logsConfigCaptor = argumentCaptor() + val traceConfigCaptor = argumentCaptor() val expectedRumSampleRate = fakeConfiguration.sampleRate?.toFloat() ?: 100f // When @@ -320,36 +293,31 @@ internal class DdSdkTest { inOrder(mockDatadog) { verify(mockDatadog).initialize( same(mockContext), - credentialCaptor.capture(), - configCaptor.capture(), + sdkConfigCaptor.capture(), any() ) - verify(mockDatadog).registerRumMonitor(any()) + verify(mockDatadog).enableRum(rumConfigCaptor.capture()) + verify(mockDatadog).enableTrace(traceConfigCaptor.capture()) + verify(mockDatadog).enableLogs(logsConfigCaptor.capture()) } - assertThat(configCaptor.firstValue) + assertThat(sdkConfigCaptor.firstValue) .hasField("coreConfig") { it.hasFieldEqualTo("needsClearTextHttp", false) it.hasFieldEqualTo("firstPartyHostsWithHeaderTypes", emptyMap()) } - .hasField("logsConfig") { - it.hasFieldEqualTo("plugins", emptyList()) - } - .hasField("tracesConfig") { - it.hasFieldEqualTo("plugins", emptyList()) - } - .hasField("rumConfig") { - it.hasFieldEqualTo("plugins", emptyList()) - it.hasFieldEqualTo("samplingRate", expectedRumSampleRate) - } + .hasFieldEqualTo("clientToken", fakeConfiguration.clientToken) + .hasFieldEqualTo("env", fakeConfiguration.env) + .hasFieldEqualTo("variant", "") .hasFieldEqualTo( "additionalConfig", fakeConfiguration.additionalConfig?.filterValues { it != null }.orEmpty() ) - val credentials = credentialCaptor.firstValue - assertThat(credentials.clientToken).isEqualTo(fakeConfiguration.clientToken) - assertThat(credentials.envName).isEqualTo(fakeConfiguration.env) - assertThat(credentials.rumApplicationId).isEqualTo(fakeConfiguration.applicationId) - assertThat(credentials.variant).isEqualTo("") + assertThat(rumConfigCaptor.firstValue) + .hasFieldEqualTo("applicationId", fakeConfiguration.applicationId) + .hasField("featureConfiguration") { + it.hasFieldEqualTo("sampleRate", expectedRumSampleRate) + } + } // endregion @@ -359,8 +327,10 @@ internal class DdSdkTest { @Test fun `𝕄 initialize native with telemetry sample rate SDK 𝕎 initialize() {}`() { // Given - val credentialCaptor = argumentCaptor() - val configCaptor = argumentCaptor() + val sdkConfigCaptor = argumentCaptor() + val rumConfigCaptor = argumentCaptor() + val logsConfigCaptor = argumentCaptor() + val traceConfigCaptor = argumentCaptor() val expectedTelemetrySampleRate = fakeConfiguration.telemetrySampleRate?.toFloat() ?: 20f // When @@ -370,36 +340,30 @@ internal class DdSdkTest { inOrder(mockDatadog) { verify(mockDatadog).initialize( same(mockContext), - credentialCaptor.capture(), - configCaptor.capture(), + sdkConfigCaptor.capture(), any() ) - verify(mockDatadog).registerRumMonitor(any()) + verify(mockDatadog).enableRum(rumConfigCaptor.capture()) + verify(mockDatadog).enableTrace(traceConfigCaptor.capture()) + verify(mockDatadog).enableLogs(logsConfigCaptor.capture()) } - assertThat(configCaptor.firstValue) + assertThat(sdkConfigCaptor.firstValue) .hasField("coreConfig") { it.hasFieldEqualTo("needsClearTextHttp", false) it.hasFieldEqualTo("firstPartyHostsWithHeaderTypes", emptyMap()) } - .hasField("logsConfig") { - it.hasFieldEqualTo("plugins", emptyList()) - } - .hasField("tracesConfig") { - it.hasFieldEqualTo("plugins", emptyList()) - } - .hasField("rumConfig") { - it.hasFieldEqualTo("plugins", emptyList()) - it.hasFieldEqualTo("telemetrySamplingRate", expectedTelemetrySampleRate) - } + .hasFieldEqualTo("clientToken", fakeConfiguration.clientToken) + .hasFieldEqualTo("env", fakeConfiguration.env) + .hasFieldEqualTo("variant", "") .hasFieldEqualTo( "additionalConfig", fakeConfiguration.additionalConfig?.filterValues { it != null }.orEmpty() ) - val credentials = credentialCaptor.firstValue - assertThat(credentials.clientToken).isEqualTo(fakeConfiguration.clientToken) - assertThat(credentials.envName).isEqualTo(fakeConfiguration.env) - assertThat(credentials.rumApplicationId).isEqualTo(fakeConfiguration.applicationId) - assertThat(credentials.variant).isEqualTo("") + assertThat(rumConfigCaptor.firstValue) + .hasFieldEqualTo("applicationId", fakeConfiguration.applicationId) + .hasField("featureConfiguration") { + it.hasFieldEqualTo("telemetrySampleRate", expectedTelemetrySampleRate) + } } // endregion @@ -410,8 +374,10 @@ internal class DdSdkTest { fun `𝕄 initialize native SDK 𝕎 initialize() {additionalConfig=null}`() { // Given fakeConfiguration = fakeConfiguration.copy(additionalConfig = null) - val credentialCaptor = argumentCaptor() - val configCaptor = argumentCaptor() + val sdkConfigCaptor = argumentCaptor() + val rumConfigCaptor = argumentCaptor() + val logsConfigCaptor = argumentCaptor() + val traceConfigCaptor = argumentCaptor() // When testedBridgeSdk.initialize(fakeConfiguration.toReadableJavaOnlyMap(), mockPromise) @@ -420,39 +386,33 @@ internal class DdSdkTest { inOrder(mockDatadog) { verify(mockDatadog).initialize( same(mockContext), - credentialCaptor.capture(), - configCaptor.capture(), + sdkConfigCaptor.capture(), any() ) - verify(mockDatadog).registerRumMonitor(any()) + verify(mockDatadog).enableRum(rumConfigCaptor.capture()) + verify(mockDatadog).enableTrace(traceConfigCaptor.capture()) + verify(mockDatadog).enableLogs(logsConfigCaptor.capture()) } - assertThat(configCaptor.firstValue) + assertThat(sdkConfigCaptor.firstValue) .hasField("coreConfig") { it.hasFieldEqualTo("needsClearTextHttp", false) it.hasFieldEqualTo("firstPartyHostsWithHeaderTypes", emptyMap()) } - .hasField("logsConfig") { - it.hasFieldEqualTo("plugins", emptyList()) - } - .hasField("tracesConfig") { - it.hasFieldEqualTo("plugins", emptyList()) - } - .hasField("rumConfig") { - it.hasFieldEqualTo("plugins", emptyList()) - } + .hasFieldEqualTo("clientToken", fakeConfiguration.clientToken) + .hasFieldEqualTo("env", fakeConfiguration.env) + .hasFieldEqualTo("variant", "") .hasFieldEqualTo("additionalConfig", emptyMap()) - val credentials = credentialCaptor.firstValue - assertThat(credentials.clientToken).isEqualTo(fakeConfiguration.clientToken) - assertThat(credentials.envName).isEqualTo(fakeConfiguration.env) - assertThat(credentials.rumApplicationId).isEqualTo(fakeConfiguration.applicationId) - assertThat(credentials.variant).isEqualTo("") + assertThat(rumConfigCaptor.firstValue) + .hasFieldEqualTo("applicationId", fakeConfiguration.applicationId) } @Test fun `𝕄 initialize native SDK 𝕎 initialize() {additionalConfig=nonNull}`() { // Given - val credentialCaptor = argumentCaptor() - val configCaptor = argumentCaptor() + val sdkConfigCaptor = argumentCaptor() + val rumConfigCaptor = argumentCaptor() + val logsConfigCaptor = argumentCaptor() + val traceConfigCaptor = argumentCaptor() // When testedBridgeSdk.initialize(fakeConfiguration.toReadableJavaOnlyMap(), mockPromise) @@ -461,35 +421,27 @@ internal class DdSdkTest { inOrder(mockDatadog) { verify(mockDatadog).initialize( same(mockContext), - credentialCaptor.capture(), - configCaptor.capture(), + sdkConfigCaptor.capture(), any() ) - verify(mockDatadog).registerRumMonitor(any()) + verify(mockDatadog).enableRum(rumConfigCaptor.capture()) + verify(mockDatadog).enableTrace(traceConfigCaptor.capture()) + verify(mockDatadog).enableLogs(logsConfigCaptor.capture()) } - assertThat(configCaptor.firstValue) + assertThat(sdkConfigCaptor.firstValue) .hasField("coreConfig") { it.hasFieldEqualTo("needsClearTextHttp", false) it.hasFieldEqualTo("firstPartyHostsWithHeaderTypes", emptyMap()) } - .hasField("logsConfig") { - it.hasFieldEqualTo("plugins", emptyList()) - } - .hasField("tracesConfig") { - it.hasFieldEqualTo("plugins", emptyList()) - } - .hasField("rumConfig") { - it.hasFieldEqualTo("plugins", emptyList()) - } + .hasFieldEqualTo("clientToken", fakeConfiguration.clientToken) + .hasFieldEqualTo("env", fakeConfiguration.env) + .hasFieldEqualTo("variant", "") .hasFieldEqualTo( "additionalConfig", fakeConfiguration.additionalConfig?.filterValues { it != null }.orEmpty() ) - val credentials = credentialCaptor.firstValue - assertThat(credentials.clientToken).isEqualTo(fakeConfiguration.clientToken) - assertThat(credentials.envName).isEqualTo(fakeConfiguration.env) - assertThat(credentials.rumApplicationId).isEqualTo(fakeConfiguration.applicationId) - assertThat(credentials.variant).isEqualTo("") + assertThat(rumConfigCaptor.firstValue) + .hasFieldEqualTo("applicationId", fakeConfiguration.applicationId) } // endregion @@ -502,8 +454,10 @@ internal class DdSdkTest { ) { // Given fakeConfiguration = fakeConfiguration.copy(site = null, nativeCrashReportEnabled = true) - val credentialCaptor = argumentCaptor() - val configCaptor = argumentCaptor() + val sdkConfigCaptor = argumentCaptor() + val rumConfigCaptor = argumentCaptor() + val logsConfigCaptor = argumentCaptor() + val traceConfigCaptor = argumentCaptor() // When testedBridgeSdk.initialize(fakeConfiguration.toReadableJavaOnlyMap(), mockPromise) @@ -512,42 +466,28 @@ internal class DdSdkTest { inOrder(mockDatadog) { verify(mockDatadog).initialize( same(mockContext), - credentialCaptor.capture(), - configCaptor.capture(), + sdkConfigCaptor.capture(), any() ) - verify(mockDatadog).registerRumMonitor(any()) + verify(mockDatadog).enableRum(rumConfigCaptor.capture()) + verify(mockDatadog).enableTrace(traceConfigCaptor.capture()) + verify(mockDatadog).enableLogs(logsConfigCaptor.capture()) } - assertThat(configCaptor.firstValue) + assertThat(sdkConfigCaptor.firstValue) .hasField("coreConfig") { it.hasFieldEqualTo("needsClearTextHttp", false) it.hasFieldEqualTo("firstPartyHostsWithHeaderTypes", emptyMap()) + it.hasFieldEqualTo("site", DatadogSite.US1) } - .hasField("logsConfig") { - it.hasFieldEqualTo("endpointUrl", DatadogSite.US1.intakeEndpoint) - it.hasFieldEqualTo("plugins", emptyList()) - } - .hasField("tracesConfig") { - it.hasFieldEqualTo("endpointUrl", DatadogSite.US1.intakeEndpoint) - it.hasFieldEqualTo("plugins", emptyList()) - } - .hasField("rumConfig") { - it.hasFieldEqualTo("endpointUrl", DatadogSite.US1.intakeEndpoint) - it.hasFieldEqualTo("plugins", emptyList()) - } - .hasField("crashReportConfig") { - it.hasFieldEqualTo("endpointUrl", DatadogSite.US1.intakeEndpoint) - it.hasFieldEqualTo("plugins", emptyList()) - } + .hasFieldEqualTo("clientToken", fakeConfiguration.clientToken) + .hasFieldEqualTo("env", fakeConfiguration.env) + .hasFieldEqualTo("variant", "") .hasFieldEqualTo( "additionalConfig", fakeConfiguration.additionalConfig?.filterValues { it != null }.orEmpty() ) - val credentials = credentialCaptor.firstValue - assertThat(credentials.clientToken).isEqualTo(fakeConfiguration.clientToken) - assertThat(credentials.envName).isEqualTo(fakeConfiguration.env) - assertThat(credentials.rumApplicationId).isEqualTo(fakeConfiguration.applicationId) - assertThat(credentials.variant).isEqualTo("") + assertThat(rumConfigCaptor.firstValue) + .hasFieldEqualTo("applicationId", fakeConfiguration.applicationId) } @Test @@ -557,8 +497,10 @@ internal class DdSdkTest { // Given val site = forge.randomizeCase("us1") fakeConfiguration = fakeConfiguration.copy(site = site, nativeCrashReportEnabled = true) - val credentialCaptor = argumentCaptor() - val configCaptor = argumentCaptor() + val sdkConfigCaptor = argumentCaptor() + val rumConfigCaptor = argumentCaptor() + val logsConfigCaptor = argumentCaptor() + val traceConfigCaptor = argumentCaptor() // When testedBridgeSdk.initialize(fakeConfiguration.toReadableJavaOnlyMap(), mockPromise) @@ -567,42 +509,28 @@ internal class DdSdkTest { inOrder(mockDatadog) { verify(mockDatadog).initialize( same(mockContext), - credentialCaptor.capture(), - configCaptor.capture(), + sdkConfigCaptor.capture(), any() ) - verify(mockDatadog).registerRumMonitor(any()) + verify(mockDatadog).enableRum(rumConfigCaptor.capture()) + verify(mockDatadog).enableTrace(traceConfigCaptor.capture()) + verify(mockDatadog).enableLogs(logsConfigCaptor.capture()) } - assertThat(configCaptor.firstValue) + assertThat(sdkConfigCaptor.firstValue) .hasField("coreConfig") { it.hasFieldEqualTo("needsClearTextHttp", false) it.hasFieldEqualTo("firstPartyHostsWithHeaderTypes", emptyMap()) + it.hasFieldEqualTo("site", DatadogSite.US1) } - .hasField("logsConfig") { - it.hasFieldEqualTo("endpointUrl", DatadogSite.US1.intakeEndpoint) - it.hasFieldEqualTo("plugins", emptyList()) - } - .hasField("tracesConfig") { - it.hasFieldEqualTo("endpointUrl", DatadogSite.US1.intakeEndpoint) - it.hasFieldEqualTo("plugins", emptyList()) - } - .hasField("rumConfig") { - it.hasFieldEqualTo("endpointUrl", DatadogSite.US1.intakeEndpoint) - it.hasFieldEqualTo("plugins", emptyList()) - } - .hasField("crashReportConfig") { - it.hasFieldEqualTo("endpointUrl", DatadogSite.US1.intakeEndpoint) - it.hasFieldEqualTo("plugins", emptyList()) - } + .hasFieldEqualTo("clientToken", fakeConfiguration.clientToken) + .hasFieldEqualTo("env", fakeConfiguration.env) + .hasFieldEqualTo("variant", "") .hasFieldEqualTo( "additionalConfig", fakeConfiguration.additionalConfig?.filterValues { it != null }.orEmpty() ) - val credentials = credentialCaptor.firstValue - assertThat(credentials.clientToken).isEqualTo(fakeConfiguration.clientToken) - assertThat(credentials.envName).isEqualTo(fakeConfiguration.env) - assertThat(credentials.rumApplicationId).isEqualTo(fakeConfiguration.applicationId) - assertThat(credentials.variant).isEqualTo("") + assertThat(rumConfigCaptor.firstValue) + .hasFieldEqualTo("applicationId", fakeConfiguration.applicationId) } @Test @@ -612,8 +540,10 @@ internal class DdSdkTest { // Given val site = forge.randomizeCase("us3") fakeConfiguration = fakeConfiguration.copy(site = site, nativeCrashReportEnabled = true) - val credentialCaptor = argumentCaptor() - val configCaptor = argumentCaptor() + val sdkConfigCaptor = argumentCaptor() + val rumConfigCaptor = argumentCaptor() + val logsConfigCaptor = argumentCaptor() + val traceConfigCaptor = argumentCaptor() // When testedBridgeSdk.initialize(fakeConfiguration.toReadableJavaOnlyMap(), mockPromise) @@ -622,42 +552,28 @@ internal class DdSdkTest { inOrder(mockDatadog) { verify(mockDatadog).initialize( same(mockContext), - credentialCaptor.capture(), - configCaptor.capture(), + sdkConfigCaptor.capture(), any() ) - verify(mockDatadog).registerRumMonitor(any()) + verify(mockDatadog).enableRum(rumConfigCaptor.capture()) + verify(mockDatadog).enableTrace(traceConfigCaptor.capture()) + verify(mockDatadog).enableLogs(logsConfigCaptor.capture()) } - assertThat(configCaptor.firstValue) + assertThat(sdkConfigCaptor.firstValue) .hasField("coreConfig") { it.hasFieldEqualTo("needsClearTextHttp", false) it.hasFieldEqualTo("firstPartyHostsWithHeaderTypes", emptyMap()) + it.hasFieldEqualTo("site", DatadogSite.US3) } - .hasField("logsConfig") { - it.hasFieldEqualTo("endpointUrl", DatadogSite.US3.intakeEndpoint) - it.hasFieldEqualTo("plugins", emptyList()) - } - .hasField("tracesConfig") { - it.hasFieldEqualTo("endpointUrl", DatadogSite.US3.intakeEndpoint) - it.hasFieldEqualTo("plugins", emptyList()) - } - .hasField("rumConfig") { - it.hasFieldEqualTo("endpointUrl", DatadogSite.US3.intakeEndpoint) - it.hasFieldEqualTo("plugins", emptyList()) - } - .hasField("crashReportConfig") { - it.hasFieldEqualTo("endpointUrl", DatadogSite.US3.intakeEndpoint) - it.hasFieldEqualTo("plugins", emptyList()) - } + .hasFieldEqualTo("clientToken", fakeConfiguration.clientToken) + .hasFieldEqualTo("env", fakeConfiguration.env) + .hasFieldEqualTo("variant", "") .hasFieldEqualTo( "additionalConfig", fakeConfiguration.additionalConfig?.filterValues { it != null }.orEmpty() ) - val credentials = credentialCaptor.firstValue - assertThat(credentials.clientToken).isEqualTo(fakeConfiguration.clientToken) - assertThat(credentials.envName).isEqualTo(fakeConfiguration.env) - assertThat(credentials.rumApplicationId).isEqualTo(fakeConfiguration.applicationId) - assertThat(credentials.variant).isEqualTo("") + assertThat(rumConfigCaptor.firstValue) + .hasFieldEqualTo("applicationId", fakeConfiguration.applicationId) } @Test @@ -667,8 +583,10 @@ internal class DdSdkTest { // Given val site = forge.randomizeCase("us5") fakeConfiguration = fakeConfiguration.copy(site = site, nativeCrashReportEnabled = true) - val credentialCaptor = argumentCaptor() - val configCaptor = argumentCaptor() + val sdkConfigCaptor = argumentCaptor() + val rumConfigCaptor = argumentCaptor() + val logsConfigCaptor = argumentCaptor() + val traceConfigCaptor = argumentCaptor() // When testedBridgeSdk.initialize(fakeConfiguration.toReadableJavaOnlyMap(), mockPromise) @@ -677,42 +595,28 @@ internal class DdSdkTest { inOrder(mockDatadog) { verify(mockDatadog).initialize( same(mockContext), - credentialCaptor.capture(), - configCaptor.capture(), + sdkConfigCaptor.capture(), any() ) - verify(mockDatadog).registerRumMonitor(any()) + verify(mockDatadog).enableRum(rumConfigCaptor.capture()) + verify(mockDatadog).enableTrace(traceConfigCaptor.capture()) + verify(mockDatadog).enableLogs(logsConfigCaptor.capture()) } - assertThat(configCaptor.firstValue) + assertThat(sdkConfigCaptor.firstValue) .hasField("coreConfig") { it.hasFieldEqualTo("needsClearTextHttp", false) it.hasFieldEqualTo("firstPartyHostsWithHeaderTypes", emptyMap()) + it.hasFieldEqualTo("site", DatadogSite.US5) } - .hasField("logsConfig") { - it.hasFieldEqualTo("endpointUrl", DatadogSite.US5.intakeEndpoint) - it.hasFieldEqualTo("plugins", emptyList()) - } - .hasField("tracesConfig") { - it.hasFieldEqualTo("endpointUrl", DatadogSite.US5.intakeEndpoint) - it.hasFieldEqualTo("plugins", emptyList()) - } - .hasField("rumConfig") { - it.hasFieldEqualTo("endpointUrl", DatadogSite.US5.intakeEndpoint) - it.hasFieldEqualTo("plugins", emptyList()) - } - .hasField("crashReportConfig") { - it.hasFieldEqualTo("endpointUrl", DatadogSite.US5.intakeEndpoint) - it.hasFieldEqualTo("plugins", emptyList()) - } + .hasFieldEqualTo("clientToken", fakeConfiguration.clientToken) + .hasFieldEqualTo("env", fakeConfiguration.env) + .hasFieldEqualTo("variant", "") .hasFieldEqualTo( "additionalConfig", fakeConfiguration.additionalConfig?.filterValues { it != null }.orEmpty() ) - val credentials = credentialCaptor.firstValue - assertThat(credentials.clientToken).isEqualTo(fakeConfiguration.clientToken) - assertThat(credentials.envName).isEqualTo(fakeConfiguration.env) - assertThat(credentials.rumApplicationId).isEqualTo(fakeConfiguration.applicationId) - assertThat(credentials.variant).isEqualTo("") + assertThat(rumConfigCaptor.firstValue) + .hasFieldEqualTo("applicationId", fakeConfiguration.applicationId) } @Test @@ -722,8 +626,10 @@ internal class DdSdkTest { // Given val site = forge.randomizeCase("us1_fed") fakeConfiguration = fakeConfiguration.copy(site = site, nativeCrashReportEnabled = true) - val credentialCaptor = argumentCaptor() - val configCaptor = argumentCaptor() + val sdkConfigCaptor = argumentCaptor() + val rumConfigCaptor = argumentCaptor() + val logsConfigCaptor = argumentCaptor() + val traceConfigCaptor = argumentCaptor() // When testedBridgeSdk.initialize(fakeConfiguration.toReadableJavaOnlyMap(), mockPromise) @@ -732,42 +638,28 @@ internal class DdSdkTest { inOrder(mockDatadog) { verify(mockDatadog).initialize( same(mockContext), - credentialCaptor.capture(), - configCaptor.capture(), + sdkConfigCaptor.capture(), any() ) - verify(mockDatadog).registerRumMonitor(any()) + verify(mockDatadog).enableRum(rumConfigCaptor.capture()) + verify(mockDatadog).enableTrace(traceConfigCaptor.capture()) + verify(mockDatadog).enableLogs(logsConfigCaptor.capture()) } - assertThat(configCaptor.firstValue) + assertThat(sdkConfigCaptor.firstValue) .hasField("coreConfig") { it.hasFieldEqualTo("needsClearTextHttp", false) it.hasFieldEqualTo("firstPartyHostsWithHeaderTypes", emptyMap()) + it.hasFieldEqualTo("site", DatadogSite.US1_FED) } - .hasField("logsConfig") { - it.hasFieldEqualTo("endpointUrl", DatadogSite.US1_FED.intakeEndpoint) - it.hasFieldEqualTo("plugins", emptyList()) - } - .hasField("tracesConfig") { - it.hasFieldEqualTo("endpointUrl", DatadogSite.US1_FED.intakeEndpoint) - it.hasFieldEqualTo("plugins", emptyList()) - } - .hasField("rumConfig") { - it.hasFieldEqualTo("endpointUrl", DatadogSite.US1_FED.intakeEndpoint) - it.hasFieldEqualTo("plugins", emptyList()) - } - .hasField("crashReportConfig") { - it.hasFieldEqualTo("endpointUrl", DatadogSite.US1_FED.intakeEndpoint) - it.hasFieldEqualTo("plugins", emptyList()) - } + .hasFieldEqualTo("clientToken", fakeConfiguration.clientToken) + .hasFieldEqualTo("env", fakeConfiguration.env) + .hasFieldEqualTo("variant", "") .hasFieldEqualTo( "additionalConfig", fakeConfiguration.additionalConfig?.filterValues { it != null }.orEmpty() ) - val credentials = credentialCaptor.firstValue - assertThat(credentials.clientToken).isEqualTo(fakeConfiguration.clientToken) - assertThat(credentials.envName).isEqualTo(fakeConfiguration.env) - assertThat(credentials.rumApplicationId).isEqualTo(fakeConfiguration.applicationId) - assertThat(credentials.variant).isEqualTo("") + assertThat(rumConfigCaptor.firstValue) + .hasFieldEqualTo("applicationId", fakeConfiguration.applicationId) } @Test @@ -777,8 +669,10 @@ internal class DdSdkTest { // Given val site = forge.randomizeCase("eu1") fakeConfiguration = fakeConfiguration.copy(site = site, nativeCrashReportEnabled = true) - val credentialCaptor = argumentCaptor() - val configCaptor = argumentCaptor() + val sdkConfigCaptor = argumentCaptor() + val rumConfigCaptor = argumentCaptor() + val logsConfigCaptor = argumentCaptor() + val traceConfigCaptor = argumentCaptor() // When testedBridgeSdk.initialize(fakeConfiguration.toReadableJavaOnlyMap(), mockPromise) @@ -787,42 +681,28 @@ internal class DdSdkTest { inOrder(mockDatadog) { verify(mockDatadog).initialize( same(mockContext), - credentialCaptor.capture(), - configCaptor.capture(), + sdkConfigCaptor.capture(), any() ) - verify(mockDatadog).registerRumMonitor(any()) + verify(mockDatadog).enableRum(rumConfigCaptor.capture()) + verify(mockDatadog).enableTrace(traceConfigCaptor.capture()) + verify(mockDatadog).enableLogs(logsConfigCaptor.capture()) } - assertThat(configCaptor.firstValue) + assertThat(sdkConfigCaptor.firstValue) .hasField("coreConfig") { it.hasFieldEqualTo("needsClearTextHttp", false) it.hasFieldEqualTo("firstPartyHostsWithHeaderTypes", emptyMap()) + it.hasFieldEqualTo("site", DatadogSite.EU1) } - .hasField("logsConfig") { - it.hasFieldEqualTo("endpointUrl", DatadogSite.EU1.intakeEndpoint) - it.hasFieldEqualTo("plugins", emptyList()) - } - .hasField("tracesConfig") { - it.hasFieldEqualTo("endpointUrl", DatadogSite.EU1.intakeEndpoint) - it.hasFieldEqualTo("plugins", emptyList()) - } - .hasField("rumConfig") { - it.hasFieldEqualTo("endpointUrl", DatadogSite.EU1.intakeEndpoint) - it.hasFieldEqualTo("plugins", emptyList()) - } - .hasField("crashReportConfig") { - it.hasFieldEqualTo("endpointUrl", DatadogSite.EU1.intakeEndpoint) - it.hasFieldEqualTo("plugins", emptyList()) - } + .hasFieldEqualTo("clientToken", fakeConfiguration.clientToken) + .hasFieldEqualTo("env", fakeConfiguration.env) + .hasFieldEqualTo("variant", "") .hasFieldEqualTo( "additionalConfig", fakeConfiguration.additionalConfig?.filterValues { it != null }.orEmpty() ) - val credentials = credentialCaptor.firstValue - assertThat(credentials.clientToken).isEqualTo(fakeConfiguration.clientToken) - assertThat(credentials.envName).isEqualTo(fakeConfiguration.env) - assertThat(credentials.rumApplicationId).isEqualTo(fakeConfiguration.applicationId) - assertThat(credentials.variant).isEqualTo("") + assertThat(rumConfigCaptor.firstValue) + .hasFieldEqualTo("applicationId", fakeConfiguration.applicationId) } @Test @@ -832,8 +712,10 @@ internal class DdSdkTest { // Given val site = forge.randomizeCase("ap1") fakeConfiguration = fakeConfiguration.copy(site = site, nativeCrashReportEnabled = true) - val credentialCaptor = argumentCaptor() - val configCaptor = argumentCaptor() + val sdkConfigCaptor = argumentCaptor() + val rumConfigCaptor = argumentCaptor() + val logsConfigCaptor = argumentCaptor() + val traceConfigCaptor = argumentCaptor() // When testedBridgeSdk.initialize(fakeConfiguration.toReadableJavaOnlyMap(), mockPromise) @@ -842,42 +724,28 @@ internal class DdSdkTest { inOrder(mockDatadog) { verify(mockDatadog).initialize( same(mockContext), - credentialCaptor.capture(), - configCaptor.capture(), + sdkConfigCaptor.capture(), any() ) - verify(mockDatadog).registerRumMonitor(any()) + verify(mockDatadog).enableRum(rumConfigCaptor.capture()) + verify(mockDatadog).enableTrace(traceConfigCaptor.capture()) + verify(mockDatadog).enableLogs(logsConfigCaptor.capture()) } - assertThat(configCaptor.firstValue) + assertThat(sdkConfigCaptor.firstValue) .hasField("coreConfig") { it.hasFieldEqualTo("needsClearTextHttp", false) it.hasFieldEqualTo("firstPartyHostsWithHeaderTypes", emptyMap()) + it.hasFieldEqualTo("site", DatadogSite.AP1) } - .hasField("logsConfig") { - it.hasFieldEqualTo("endpointUrl", DatadogSite.AP1.intakeEndpoint) - it.hasFieldEqualTo("plugins", emptyList()) - } - .hasField("tracesConfig") { - it.hasFieldEqualTo("endpointUrl", DatadogSite.AP1.intakeEndpoint) - it.hasFieldEqualTo("plugins", emptyList()) - } - .hasField("rumConfig") { - it.hasFieldEqualTo("endpointUrl", DatadogSite.AP1.intakeEndpoint) - it.hasFieldEqualTo("plugins", emptyList()) - } - .hasField("crashReportConfig") { - it.hasFieldEqualTo("endpointUrl", DatadogSite.AP1.intakeEndpoint) - it.hasFieldEqualTo("plugins", emptyList()) - } + .hasFieldEqualTo("clientToken", fakeConfiguration.clientToken) + .hasFieldEqualTo("env", fakeConfiguration.env) + .hasFieldEqualTo("variant", "") .hasFieldEqualTo( "additionalConfig", fakeConfiguration.additionalConfig?.filterValues { it != null }.orEmpty() ) - val credentials = credentialCaptor.firstValue - assertThat(credentials.clientToken).isEqualTo(fakeConfiguration.clientToken) - assertThat(credentials.envName).isEqualTo(fakeConfiguration.env) - assertThat(credentials.rumApplicationId).isEqualTo(fakeConfiguration.applicationId) - assertThat(credentials.variant).isEqualTo("") + assertThat(rumConfigCaptor.firstValue) + .hasFieldEqualTo("applicationId", fakeConfiguration.applicationId) } // endregion @@ -888,8 +756,10 @@ internal class DdSdkTest { fun `𝕄 initialize native SDK 𝕎 initialize() {trackingConsent=null}`() { // Given fakeConfiguration = fakeConfiguration.copy(trackingConsent = null) - val credentialCaptor = argumentCaptor() - val configCaptor = argumentCaptor() + val sdkConfigCaptor = argumentCaptor() + val rumConfigCaptor = argumentCaptor() + val logsConfigCaptor = argumentCaptor() + val traceConfigCaptor = argumentCaptor() // When testedBridgeSdk.initialize(fakeConfiguration.toReadableJavaOnlyMap(), mockPromise) @@ -898,11 +768,12 @@ internal class DdSdkTest { inOrder(mockDatadog) { verify(mockDatadog).initialize( same(mockContext), - credentialCaptor.capture(), - configCaptor.capture(), + sdkConfigCaptor.capture(), eq(TrackingConsent.PENDING) ) - verify(mockDatadog).registerRumMonitor(any()) + verify(mockDatadog).enableRum(rumConfigCaptor.capture()) + verify(mockDatadog).enableTrace(traceConfigCaptor.capture()) + verify(mockDatadog).enableLogs(logsConfigCaptor.capture()) } } @@ -913,8 +784,10 @@ internal class DdSdkTest { // Given val consent = forge.randomizeCase("PENDING") fakeConfiguration = fakeConfiguration.copy(trackingConsent = consent) - val credentialCaptor = argumentCaptor() - val configCaptor = argumentCaptor() + val sdkConfigCaptor = argumentCaptor() + val rumConfigCaptor = argumentCaptor() + val logsConfigCaptor = argumentCaptor() + val traceConfigCaptor = argumentCaptor() // When testedBridgeSdk.initialize(fakeConfiguration.toReadableJavaOnlyMap(), mockPromise) @@ -923,11 +796,12 @@ internal class DdSdkTest { inOrder(mockDatadog) { verify(mockDatadog).initialize( same(mockContext), - credentialCaptor.capture(), - configCaptor.capture(), + sdkConfigCaptor.capture(), eq(TrackingConsent.PENDING) ) - verify(mockDatadog).registerRumMonitor(any()) + verify(mockDatadog).enableRum(rumConfigCaptor.capture()) + verify(mockDatadog).enableTrace(traceConfigCaptor.capture()) + verify(mockDatadog).enableLogs(logsConfigCaptor.capture()) } } @@ -938,8 +812,10 @@ internal class DdSdkTest { // Given val consent = forge.randomizeCase("GRANTED") fakeConfiguration = fakeConfiguration.copy(trackingConsent = consent) - val credentialCaptor = argumentCaptor() - val configCaptor = argumentCaptor() + val sdkConfigCaptor = argumentCaptor() + val rumConfigCaptor = argumentCaptor() + val logsConfigCaptor = argumentCaptor() + val traceConfigCaptor = argumentCaptor() // When testedBridgeSdk.initialize(fakeConfiguration.toReadableJavaOnlyMap(), mockPromise) @@ -948,11 +824,12 @@ internal class DdSdkTest { inOrder(mockDatadog) { verify(mockDatadog).initialize( same(mockContext), - credentialCaptor.capture(), - configCaptor.capture(), + sdkConfigCaptor.capture(), eq(TrackingConsent.GRANTED) ) - verify(mockDatadog).registerRumMonitor(any()) + verify(mockDatadog).enableRum(rumConfigCaptor.capture()) + verify(mockDatadog).enableTrace(traceConfigCaptor.capture()) + verify(mockDatadog).enableLogs(logsConfigCaptor.capture()) } } @@ -963,8 +840,10 @@ internal class DdSdkTest { // Given val consent = forge.randomizeCase("NOT_GRANTED") fakeConfiguration = fakeConfiguration.copy(trackingConsent = consent) - val credentialCaptor = argumentCaptor() - val configCaptor = argumentCaptor() + val sdkConfigCaptor = argumentCaptor() + val rumConfigCaptor = argumentCaptor() + val logsConfigCaptor = argumentCaptor() + val traceConfigCaptor = argumentCaptor() // When testedBridgeSdk.initialize(fakeConfiguration.toReadableJavaOnlyMap(), mockPromise) @@ -973,11 +852,12 @@ internal class DdSdkTest { inOrder(mockDatadog) { verify(mockDatadog).initialize( same(mockContext), - credentialCaptor.capture(), - configCaptor.capture(), + sdkConfigCaptor.capture(), eq(TrackingConsent.NOT_GRANTED) ) - verify(mockDatadog).registerRumMonitor(any()) + verify(mockDatadog).enableRum(rumConfigCaptor.capture()) + verify(mockDatadog).enableTrace(traceConfigCaptor.capture()) + verify(mockDatadog).enableLogs(logsConfigCaptor.capture()) } } @@ -989,8 +869,10 @@ internal class DdSdkTest { ) { // Given val bridgeConfiguration = configuration.copy(additionalConfig = null) - val credentialCaptor = argumentCaptor() - val configCaptor = argumentCaptor() + val sdkConfigCaptor = argumentCaptor() + val rumConfigCaptor = argumentCaptor() + val logsConfigCaptor = argumentCaptor() + val traceConfigCaptor = argumentCaptor() // When testedBridgeSdk.initialize(bridgeConfiguration.toReadableJavaOnlyMap(), mockPromise) @@ -999,14 +881,15 @@ internal class DdSdkTest { inOrder(mockDatadog) { verify(mockDatadog).initialize( same(mockContext), - credentialCaptor.capture(), - configCaptor.capture(), - eq(configuration.trackingConsent.asTrackingConsent()) + sdkConfigCaptor.capture(), + any() ) - verify(mockDatadog).registerRumMonitor(any()) + verify(mockDatadog).enableRum(rumConfigCaptor.capture()) + verify(mockDatadog).enableTrace(traceConfigCaptor.capture()) + verify(mockDatadog).enableLogs(logsConfigCaptor.capture()) } - assertThat(configCaptor.firstValue) - .hasField("rumConfig") { + assertThat(rumConfigCaptor.firstValue) + .hasField("featureConfiguration") { it.hasFieldEqualTo("viewTrackingStrategy", NoOpViewTrackingStrategy) } } @@ -1021,8 +904,10 @@ internal class DdSdkTest { DdSdkImplementation.DD_NATIVE_VIEW_TRACKING to false ) ) - val credentialCaptor = argumentCaptor() - val configCaptor = argumentCaptor() + val sdkConfigCaptor = argumentCaptor() + val rumConfigCaptor = argumentCaptor() + val logsConfigCaptor = argumentCaptor() + val traceConfigCaptor = argumentCaptor() // When testedBridgeSdk.initialize(bridgeConfiguration.toReadableJavaOnlyMap(), mockPromise) @@ -1031,14 +916,15 @@ internal class DdSdkTest { inOrder(mockDatadog) { verify(mockDatadog).initialize( same(mockContext), - credentialCaptor.capture(), - configCaptor.capture(), - eq(configuration.trackingConsent.asTrackingConsent()) + sdkConfigCaptor.capture(), + any() ) - verify(mockDatadog).registerRumMonitor(any()) + verify(mockDatadog).enableRum(rumConfigCaptor.capture()) + verify(mockDatadog).enableTrace(traceConfigCaptor.capture()) + verify(mockDatadog).enableLogs(logsConfigCaptor.capture()) } - assertThat(configCaptor.firstValue) - .hasField("rumConfig") { + assertThat(rumConfigCaptor.firstValue) + .hasField("featureConfiguration") { it.hasFieldEqualTo("viewTrackingStrategy", NoOpViewTrackingStrategy) } } @@ -1053,8 +939,10 @@ internal class DdSdkTest { DdSdkImplementation.DD_NATIVE_VIEW_TRACKING to true ) ) - val credentialCaptor = argumentCaptor() - val configCaptor = argumentCaptor() + val sdkConfigCaptor = argumentCaptor() + val rumConfigCaptor = argumentCaptor() + val logsConfigCaptor = argumentCaptor() + val traceConfigCaptor = argumentCaptor() // When testedBridgeSdk.initialize(bridgeConfiguration.toReadableJavaOnlyMap(), mockPromise) @@ -1063,14 +951,15 @@ internal class DdSdkTest { inOrder(mockDatadog) { verify(mockDatadog).initialize( same(mockContext), - credentialCaptor.capture(), - configCaptor.capture(), - eq(configuration.trackingConsent.asTrackingConsent()) + sdkConfigCaptor.capture(), + any() ) - verify(mockDatadog).registerRumMonitor(any()) + verify(mockDatadog).enableRum(rumConfigCaptor.capture()) + verify(mockDatadog).enableTrace(traceConfigCaptor.capture()) + verify(mockDatadog).enableLogs(logsConfigCaptor.capture()) } - assertThat(configCaptor.firstValue) - .hasField("rumConfig") { + assertThat(rumConfigCaptor.firstValue) + .hasField("featureConfiguration") { it.hasFieldEqualTo("viewTrackingStrategy", ActivityViewTrackingStrategy(false)) } } @@ -1085,8 +974,10 @@ internal class DdSdkTest { DdSdkImplementation.DD_NATIVE_INTERACTION_TRACKING to false ) ) - val credentialCaptor = argumentCaptor() - val configCaptor = argumentCaptor() + val sdkConfigCaptor = argumentCaptor() + val rumConfigCaptor = argumentCaptor() + val logsConfigCaptor = argumentCaptor() + val traceConfigCaptor = argumentCaptor() // When testedBridgeSdk.initialize(bridgeConfiguration.toReadableJavaOnlyMap(), mockPromise) @@ -1095,18 +986,16 @@ internal class DdSdkTest { inOrder(mockDatadog) { verify(mockDatadog).initialize( same(mockContext), - credentialCaptor.capture(), - configCaptor.capture(), - eq(configuration.trackingConsent.asTrackingConsent()) + sdkConfigCaptor.capture(), + any() ) - verify(mockDatadog).registerRumMonitor(any()) + verify(mockDatadog).enableRum(rumConfigCaptor.capture()) + verify(mockDatadog).enableTrace(traceConfigCaptor.capture()) + verify(mockDatadog).enableLogs(logsConfigCaptor.capture()) } - assertThat(configCaptor.firstValue) - .hasField("rumConfig") { - it.hasFieldWithClass( - "userActionTrackingStrategy", - "com.datadog.android.rum.internal.tracking.NoOpUserActionTrackingStrategy" - ) + assertThat(rumConfigCaptor.firstValue) + .hasField("featureConfiguration") { + it.hasFieldEqualTo("viewTrackingStrategy", NoOpViewTrackingStrategy) } } @@ -1118,8 +1007,10 @@ internal class DdSdkTest { val bridgeConfiguration = configuration.copy( trackFrustrations = true ) - val credentialCaptor = argumentCaptor() - val configCaptor = argumentCaptor() + val sdkConfigCaptor = argumentCaptor() + val rumConfigCaptor = argumentCaptor() + val logsConfigCaptor = argumentCaptor() + val traceConfigCaptor = argumentCaptor() // When testedBridgeSdk.initialize(bridgeConfiguration.toReadableJavaOnlyMap(), mockPromise) @@ -1128,18 +1019,16 @@ internal class DdSdkTest { inOrder(mockDatadog) { verify(mockDatadog).initialize( same(mockContext), - credentialCaptor.capture(), - configCaptor.capture(), - eq(configuration.trackingConsent.asTrackingConsent()) + sdkConfigCaptor.capture(), + any() ) - verify(mockDatadog).registerRumMonitor(any()) + verify(mockDatadog).enableRum(rumConfigCaptor.capture()) + verify(mockDatadog).enableTrace(traceConfigCaptor.capture()) + verify(mockDatadog).enableLogs(logsConfigCaptor.capture()) } - assertThat(configCaptor.firstValue) - .hasField("rumConfig") { - it.hasFieldEqualTo( - "trackFrustrations", - true - ) + assertThat(rumConfigCaptor.firstValue) + .hasField("featureConfiguration") { + it.hasFieldEqualTo("trackFrustrations", true) } } @@ -1151,8 +1040,10 @@ internal class DdSdkTest { val bridgeConfiguration = configuration.copy( trackFrustrations = false ) - val credentialCaptor = argumentCaptor() - val configCaptor = argumentCaptor() + val sdkConfigCaptor = argumentCaptor() + val rumConfigCaptor = argumentCaptor() + val logsConfigCaptor = argumentCaptor() + val traceConfigCaptor = argumentCaptor() // When testedBridgeSdk.initialize(bridgeConfiguration.toReadableJavaOnlyMap(), mockPromise) @@ -1161,18 +1052,16 @@ internal class DdSdkTest { inOrder(mockDatadog) { verify(mockDatadog).initialize( same(mockContext), - credentialCaptor.capture(), - configCaptor.capture(), - eq(configuration.trackingConsent.asTrackingConsent()) + sdkConfigCaptor.capture(), + any() ) - verify(mockDatadog).registerRumMonitor(any()) + verify(mockDatadog).enableRum(rumConfigCaptor.capture()) + verify(mockDatadog).enableTrace(traceConfigCaptor.capture()) + verify(mockDatadog).enableLogs(logsConfigCaptor.capture()) } - assertThat(configCaptor.firstValue) - .hasField("rumConfig") { - it.hasFieldEqualTo( - "trackFrustrations", - false - ) + assertThat(rumConfigCaptor.firstValue) + .hasField("featureConfiguration") { + it.hasFieldEqualTo("trackFrustrations", false) } } @@ -1186,8 +1075,10 @@ internal class DdSdkTest { DdSdkImplementation.DD_NATIVE_INTERACTION_TRACKING to true ) ) - val credentialCaptor = argumentCaptor() - val configCaptor = argumentCaptor() + val sdkConfigCaptor = argumentCaptor() + val rumConfigCaptor = argumentCaptor() + val logsConfigCaptor = argumentCaptor() + val traceConfigCaptor = argumentCaptor() // When testedBridgeSdk.initialize(bridgeConfiguration.toReadableJavaOnlyMap(), mockPromise) @@ -1196,19 +1087,16 @@ internal class DdSdkTest { inOrder(mockDatadog) { verify(mockDatadog).initialize( same(mockContext), - credentialCaptor.capture(), - configCaptor.capture(), - eq(configuration.trackingConsent.asTrackingConsent()) - ) - verify(mockDatadog).registerRumMonitor(any()) - } - assertThat(configCaptor.firstValue) - .hasField("rumConfig") { - it.hasFieldWithClass( - "userActionTrackingStrategy", - "com.datadog.android.rum.internal" + - ".instrumentation.UserActionTrackingStrategyLegacy" - ) + sdkConfigCaptor.capture(), + any() + ) + verify(mockDatadog).enableRum(rumConfigCaptor.capture()) + verify(mockDatadog).enableTrace(traceConfigCaptor.capture()) + verify(mockDatadog).enableLogs(logsConfigCaptor.capture()) + } + assertThat(rumConfigCaptor.firstValue) + .hasField("featureConfiguration") { + it.hasFieldEqualTo("userActionTracking", true) } } @@ -1222,8 +1110,10 @@ internal class DdSdkTest { DdSdkImplementation.DD_NATIVE_INTERACTION_TRACKING to null ) ) - val credentialCaptor = argumentCaptor() - val configCaptor = argumentCaptor() + val sdkConfigCaptor = argumentCaptor() + val rumConfigCaptor = argumentCaptor() + val logsConfigCaptor = argumentCaptor() + val traceConfigCaptor = argumentCaptor() // When testedBridgeSdk.initialize(bridgeConfiguration.toReadableJavaOnlyMap(), mockPromise) @@ -1232,19 +1122,16 @@ internal class DdSdkTest { inOrder(mockDatadog) { verify(mockDatadog).initialize( same(mockContext), - credentialCaptor.capture(), - configCaptor.capture(), - eq(configuration.trackingConsent.asTrackingConsent()) - ) - verify(mockDatadog).registerRumMonitor(any()) - } - assertThat(configCaptor.firstValue) - .hasField("rumConfig") { - it.hasFieldWithClass( - "userActionTrackingStrategy", - "com.datadog.android.rum.internal" + - ".instrumentation.UserActionTrackingStrategyLegacy" - ) + sdkConfigCaptor.capture(), + any() + ) + verify(mockDatadog).enableRum(rumConfigCaptor.capture()) + verify(mockDatadog).enableTrace(traceConfigCaptor.capture()) + verify(mockDatadog).enableLogs(logsConfigCaptor.capture()) + } + assertThat(rumConfigCaptor.firstValue) + .hasField("featureConfiguration") { + it.hasFieldEqualTo("userActionTracking", true) } } @Test @@ -1303,20 +1190,40 @@ internal class DdSdkTest { DdSdkImplementation.DD_SERVICE_NAME to serviceName ) ) - val credentialCaptor = argumentCaptor() - val configCaptor = argumentCaptor() + val sdkConfigCaptor = argumentCaptor() + val rumConfigCaptor = argumentCaptor() + val logsConfigCaptor = argumentCaptor() + val traceConfigCaptor = argumentCaptor() // When testedBridgeSdk.initialize(bridgeConfiguration.toReadableJavaOnlyMap(), mockPromise) // Then - verify(mockDatadog).initialize( - same(mockContext), - credentialCaptor.capture(), - configCaptor.capture(), - eq(configuration.trackingConsent.asTrackingConsent()) - ) - assertThat(credentialCaptor.firstValue.serviceName).isEqualTo(serviceName) + inOrder(mockDatadog) { + verify(mockDatadog).initialize( + same(mockContext), + sdkConfigCaptor.capture(), + any() + ) + verify(mockDatadog).enableRum(rumConfigCaptor.capture()) + verify(mockDatadog).enableTrace(traceConfigCaptor.capture()) + verify(mockDatadog).enableLogs(logsConfigCaptor.capture()) + } + assertThat(sdkConfigCaptor.firstValue) + .hasField("coreConfig") { + it.hasFieldEqualTo("needsClearTextHttp", false) + it.hasFieldEqualTo("firstPartyHostsWithHeaderTypes", emptyMap()) + } + .hasFieldEqualTo("clientToken", bridgeConfiguration.clientToken) + .hasFieldEqualTo("env", bridgeConfiguration.env) + .hasFieldEqualTo("variant", "") + .hasFieldEqualTo("service", serviceName) + .hasFieldEqualTo( + "additionalConfig", + bridgeConfiguration.additionalConfig?.filterValues { it != null }.orEmpty() + ) + assertThat(rumConfigCaptor.firstValue) + .hasFieldEqualTo("applicationId", bridgeConfiguration.applicationId) } @Test @@ -1330,26 +1237,32 @@ internal class DdSdkTest { val bridgeConfiguration = configuration.copy( nativeLongTaskThresholdMs = threshold ) - val credentialCaptor = argumentCaptor() - val configCaptor = argumentCaptor() + val sdkConfigCaptor = argumentCaptor() + val rumConfigCaptor = argumentCaptor() + val logsConfigCaptor = argumentCaptor() + val traceConfigCaptor = argumentCaptor() // When testedBridgeSdk.initialize(bridgeConfiguration.toReadableJavaOnlyMap(), mockPromise) // Then - verify(mockDatadog).initialize( - same(mockContext), - credentialCaptor.capture(), - configCaptor.capture(), - eq(configuration.trackingConsent.asTrackingConsent()) - ) - assertThat(configCaptor.firstValue) - .hasField("rumConfig") { rumConfig -> + inOrder(mockDatadog) { + verify(mockDatadog).initialize( + same(mockContext), + sdkConfigCaptor.capture(), + any() + ) + verify(mockDatadog).enableRum(rumConfigCaptor.capture()) + verify(mockDatadog).enableTrace(traceConfigCaptor.capture()) + verify(mockDatadog).enableLogs(logsConfigCaptor.capture()) + } + assertThat(rumConfigCaptor.firstValue) + .hasField("featureConfiguration") { rumConfig -> rumConfig.hasField("longTaskTrackingStrategy") { longTaskTrackingStrategy -> longTaskTrackingStrategy .isInstanceOf( "com.datadog.android.rum.internal.instrumentation." + - "MainLooperLongTaskStrategy" + "MainLooperLongTaskStrategy" ) .hasFieldEqualTo("thresholdMs", threshold.toLong()) } @@ -1365,21 +1278,27 @@ internal class DdSdkTest { val bridgeConfiguration = configuration.copy( nativeLongTaskThresholdMs = 0.0 ) - val credentialCaptor = argumentCaptor() - val configCaptor = argumentCaptor() + val sdkConfigCaptor = argumentCaptor() + val rumConfigCaptor = argumentCaptor() + val logsConfigCaptor = argumentCaptor() + val traceConfigCaptor = argumentCaptor() // When testedBridgeSdk.initialize(bridgeConfiguration.toReadableJavaOnlyMap(), mockPromise) // Then - verify(mockDatadog).initialize( - same(mockContext), - credentialCaptor.capture(), - configCaptor.capture(), - eq(configuration.trackingConsent.asTrackingConsent()) - ) - assertThat(configCaptor.firstValue) - .hasField("rumConfig") { rumConfig -> + inOrder(mockDatadog) { + verify(mockDatadog).initialize( + same(mockContext), + sdkConfigCaptor.capture(), + any() + ) + verify(mockDatadog).enableRum(rumConfigCaptor.capture()) + verify(mockDatadog).enableTrace(traceConfigCaptor.capture()) + verify(mockDatadog).enableLogs(logsConfigCaptor.capture()) + } + assertThat(rumConfigCaptor.firstValue) + .hasField("featureConfiguration") { rumConfig -> rumConfig.doesNotHaveField("longTaskTrackingStrategy") } } @@ -1422,19 +1341,26 @@ internal class DdSdkTest { DdSdkImplementation.DD_FIRST_PARTY_HOSTS to firstPartyHosts.toReadableArray() ) ) - val configCaptor = argumentCaptor() + val sdkConfigCaptor = argumentCaptor() + val rumConfigCaptor = argumentCaptor() + val logsConfigCaptor = argumentCaptor() + val traceConfigCaptor = argumentCaptor() // When testedBridgeSdk.initialize(bridgeConfiguration.toReadableJavaOnlyMap(), mockPromise) // Then - verify(mockDatadog).initialize( - same(mockContext), - any(), - configCaptor.capture(), - eq(configuration.trackingConsent.asTrackingConsent()) - ) - assertThat(configCaptor.firstValue) + inOrder(mockDatadog) { + verify(mockDatadog).initialize( + same(mockContext), + sdkConfigCaptor.capture(), + any() + ) + verify(mockDatadog).enableRum(rumConfigCaptor.capture()) + verify(mockDatadog).enableTrace(traceConfigCaptor.capture()) + verify(mockDatadog).enableLogs(logsConfigCaptor.capture()) + } + assertThat(sdkConfigCaptor.firstValue) .hasField("coreConfig") { coreConfig -> coreConfig.hasFieldEqualTo( "firstPartyHostsWithHeaderTypes", @@ -1476,19 +1402,26 @@ internal class DdSdkTest { DdSdkImplementation.DD_FIRST_PARTY_HOSTS to firstPartyHosts.toReadableArray() ) ) - val configCaptor = argumentCaptor() + val sdkConfigCaptor = argumentCaptor() + val rumConfigCaptor = argumentCaptor() + val logsConfigCaptor = argumentCaptor() + val traceConfigCaptor = argumentCaptor() // When testedBridgeSdk.initialize(bridgeConfiguration.toReadableJavaOnlyMap(), mockPromise) // Then - verify(mockDatadog).initialize( - same(mockContext), - any(), - configCaptor.capture(), - eq(configuration.trackingConsent.asTrackingConsent()) - ) - assertThat(configCaptor.firstValue) + inOrder(mockDatadog) { + verify(mockDatadog).initialize( + same(mockContext), + sdkConfigCaptor.capture(), + any() + ) + verify(mockDatadog).enableRum(rumConfigCaptor.capture()) + verify(mockDatadog).enableTrace(traceConfigCaptor.capture()) + verify(mockDatadog).enableLogs(logsConfigCaptor.capture()) + } + assertThat(sdkConfigCaptor.firstValue) .hasField("coreConfig") { coreConfig -> coreConfig.hasFieldEqualTo( "firstPartyHostsWithHeaderTypes", @@ -1537,19 +1470,26 @@ internal class DdSdkTest { DdSdkImplementation.DD_FIRST_PARTY_HOSTS to firstPartyHosts.toReadableArray() ) ) - val configCaptor = argumentCaptor() + val sdkConfigCaptor = argumentCaptor() + val rumConfigCaptor = argumentCaptor() + val logsConfigCaptor = argumentCaptor() + val traceConfigCaptor = argumentCaptor() // When testedBridgeSdk.initialize(bridgeConfiguration.toReadableJavaOnlyMap(), mockPromise) // Then - verify(mockDatadog).initialize( - same(mockContext), - any(), - configCaptor.capture(), - eq(configuration.trackingConsent.asTrackingConsent()) - ) - assertThat(configCaptor.firstValue) + inOrder(mockDatadog) { + verify(mockDatadog).initialize( + same(mockContext), + sdkConfigCaptor.capture(), + any() + ) + verify(mockDatadog).enableRum(rumConfigCaptor.capture()) + verify(mockDatadog).enableTrace(traceConfigCaptor.capture()) + verify(mockDatadog).enableLogs(logsConfigCaptor.capture()) + } + assertThat(sdkConfigCaptor.firstValue) .hasField("coreConfig") { coreConfig -> coreConfig.hasFieldEqualTo( "firstPartyHostsWithHeaderTypes", @@ -1569,8 +1509,10 @@ internal class DdSdkTest { val bridgeConfiguration = configuration.copy( uploadFrequency = input, ) - val credentialCaptor = argumentCaptor() - val configCaptor = argumentCaptor() + val sdkConfigCaptor = argumentCaptor() + val rumConfigCaptor = argumentCaptor() + val logsConfigCaptor = argumentCaptor() + val traceConfigCaptor = argumentCaptor() // When testedBridgeSdk.initialize(bridgeConfiguration.toReadableJavaOnlyMap(), mockPromise) @@ -1579,15 +1521,19 @@ internal class DdSdkTest { inOrder(mockDatadog) { verify(mockDatadog).initialize( same(mockContext), - credentialCaptor.capture(), - configCaptor.capture(), - eq(configuration.trackingConsent.asTrackingConsent()) + sdkConfigCaptor.capture(), + any() ) - verify(mockDatadog).registerRumMonitor(any()) + verify(mockDatadog).enableRum(rumConfigCaptor.capture()) + verify(mockDatadog).enableTrace(traceConfigCaptor.capture()) + verify(mockDatadog).enableLogs(logsConfigCaptor.capture()) } - assertThat(configCaptor.firstValue) - .hasField("coreConfig") { - it.hasFieldEqualTo("uploadFrequency", expectedUploadFrequency) + assertThat(sdkConfigCaptor.firstValue) + .hasField("coreConfig") { coreConfig -> + coreConfig.hasFieldEqualTo( + "uploadFrequency", + expectedUploadFrequency + ) } } @@ -1602,8 +1548,10 @@ internal class DdSdkTest { val bridgeConfiguration = configuration.copy( batchSize = input, ) - val credentialCaptor = argumentCaptor() - val configCaptor = argumentCaptor() + val sdkConfigCaptor = argumentCaptor() + val rumConfigCaptor = argumentCaptor() + val logsConfigCaptor = argumentCaptor() + val traceConfigCaptor = argumentCaptor() // When testedBridgeSdk.initialize(bridgeConfiguration.toReadableJavaOnlyMap(), mockPromise) @@ -1612,15 +1560,19 @@ internal class DdSdkTest { inOrder(mockDatadog) { verify(mockDatadog).initialize( same(mockContext), - credentialCaptor.capture(), - configCaptor.capture(), - eq(configuration.trackingConsent.asTrackingConsent()) + sdkConfigCaptor.capture(), + any() ) - verify(mockDatadog).registerRumMonitor(any()) + verify(mockDatadog).enableRum(rumConfigCaptor.capture()) + verify(mockDatadog).enableTrace(traceConfigCaptor.capture()) + verify(mockDatadog).enableLogs(logsConfigCaptor.capture()) } - assertThat(configCaptor.firstValue) - .hasField("coreConfig") { - it.hasFieldEqualTo("batchSize", expectedBatchSize) + assertThat(sdkConfigCaptor.firstValue) + .hasField("coreConfig") { coreConfig -> + coreConfig.hasFieldEqualTo( + "batchSize", + expectedBatchSize + ) } } @@ -1634,8 +1586,10 @@ internal class DdSdkTest { val bridgeConfiguration = configuration.copy( trackBackgroundEvents = trackBackgroundEvents, ) - val credentialCaptor = argumentCaptor() - val configCaptor = argumentCaptor() + val sdkConfigCaptor = argumentCaptor() + val rumConfigCaptor = argumentCaptor() + val logsConfigCaptor = argumentCaptor() + val traceConfigCaptor = argumentCaptor() // When testedBridgeSdk.initialize(bridgeConfiguration.toReadableJavaOnlyMap(), mockPromise) @@ -1644,14 +1598,15 @@ internal class DdSdkTest { inOrder(mockDatadog) { verify(mockDatadog).initialize( same(mockContext), - credentialCaptor.capture(), - configCaptor.capture(), - eq(configuration.trackingConsent.asTrackingConsent()) + sdkConfigCaptor.capture(), + any() ) - verify(mockDatadog).registerRumMonitor(any()) + verify(mockDatadog).enableRum(rumConfigCaptor.capture()) + verify(mockDatadog).enableTrace(traceConfigCaptor.capture()) + verify(mockDatadog).enableLogs(logsConfigCaptor.capture()) } - assertThat(configCaptor.firstValue) - .hasField("rumConfig") { + assertThat(rumConfigCaptor.firstValue) + .hasField("featureConfiguration") { it.hasFieldEqualTo("backgroundEventTracking", trackBackgroundEvents ?: false) } } @@ -1664,8 +1619,10 @@ internal class DdSdkTest { val bridgeConfiguration = configuration.copy( vitalsUpdateFrequency = "RARE" ) - val credentialCaptor = argumentCaptor() - val configCaptor = argumentCaptor() + val sdkConfigCaptor = argumentCaptor() + val rumConfigCaptor = argumentCaptor() + val logsConfigCaptor = argumentCaptor() + val traceConfigCaptor = argumentCaptor() // When testedBridgeSdk.initialize(bridgeConfiguration.toReadableJavaOnlyMap(), mockPromise) @@ -1674,14 +1631,15 @@ internal class DdSdkTest { inOrder(mockDatadog) { verify(mockDatadog).initialize( same(mockContext), - credentialCaptor.capture(), - configCaptor.capture(), - eq(configuration.trackingConsent.asTrackingConsent()) + sdkConfigCaptor.capture(), + any() ) - verify(mockDatadog).registerRumMonitor(any()) + verify(mockDatadog).enableRum(rumConfigCaptor.capture()) + verify(mockDatadog).enableTrace(traceConfigCaptor.capture()) + verify(mockDatadog).enableLogs(logsConfigCaptor.capture()) } - assertThat(configCaptor.firstValue) - .hasField("rumConfig") { + assertThat(rumConfigCaptor.firstValue) + .hasField("featureConfiguration") { it.hasFieldEqualTo("vitalsMonitorUpdateFrequency", VitalsUpdateFrequency.RARE) } argumentCaptor { @@ -1700,8 +1658,10 @@ internal class DdSdkTest { vitalsUpdateFrequency = "NEVER", longTaskThresholdMs = 0.0 ) - val credentialCaptor = argumentCaptor() - val configCaptor = argumentCaptor() + val sdkConfigCaptor = argumentCaptor() + val rumConfigCaptor = argumentCaptor() + val logsConfigCaptor = argumentCaptor() + val traceConfigCaptor = argumentCaptor() // When testedBridgeSdk.initialize(bridgeConfiguration.toReadableJavaOnlyMap(), mockPromise) @@ -1710,14 +1670,15 @@ internal class DdSdkTest { inOrder(mockDatadog) { verify(mockDatadog).initialize( same(mockContext), - credentialCaptor.capture(), - configCaptor.capture(), - eq(configuration.trackingConsent.asTrackingConsent()) + sdkConfigCaptor.capture(), + any() ) - verify(mockDatadog).registerRumMonitor(any()) + verify(mockDatadog).enableRum(rumConfigCaptor.capture()) + verify(mockDatadog).enableTrace(traceConfigCaptor.capture()) + verify(mockDatadog).enableLogs(logsConfigCaptor.capture()) } - assertThat(configCaptor.firstValue) - .hasField("rumConfig") { + assertThat(rumConfigCaptor.firstValue) + .hasField("featureConfiguration") { it.hasFieldEqualTo("vitalsMonitorUpdateFrequency", VitalsUpdateFrequency.NEVER) } verifyZeroInteractions(mockChoreographer) @@ -1736,8 +1697,10 @@ internal class DdSdkTest { vitalsUpdateFrequency = fakeFrequency, longTaskThresholdMs = 0.0 ) - val credentialCaptor = argumentCaptor() - val configCaptor = argumentCaptor() + val sdkConfigCaptor = argumentCaptor() + val rumConfigCaptor = argumentCaptor() + val logsConfigCaptor = argumentCaptor() + val traceConfigCaptor = argumentCaptor() val frameDurationNs = threshold + frameDurationOverThreshold // When @@ -1747,14 +1710,15 @@ internal class DdSdkTest { inOrder(mockDatadog) { verify(mockDatadog).initialize( same(mockContext), - credentialCaptor.capture(), - configCaptor.capture(), - eq(configuration.trackingConsent.asTrackingConsent()) + sdkConfigCaptor.capture(), + any() ) - verify(mockDatadog).registerRumMonitor(any()) + verify(mockDatadog).enableRum(rumConfigCaptor.capture()) + verify(mockDatadog).enableTrace(traceConfigCaptor.capture()) + verify(mockDatadog).enableLogs(logsConfigCaptor.capture()) } - assertThat(configCaptor.firstValue) - .hasField("rumConfig") { + assertThat(rumConfigCaptor.firstValue) + .hasField("featureConfiguration") { it.hasFieldEqualTo("vitalsMonitorUpdateFrequency", VitalsUpdateFrequency.AVERAGE) } argumentCaptor { @@ -1866,19 +1830,26 @@ internal class DdSdkTest { DdSdkImplementation.DD_VERSION_SUFFIX to versionSuffix ) ) - val configCaptor = argumentCaptor() + val sdkConfigCaptor = argumentCaptor() + val rumConfigCaptor = argumentCaptor() + val logsConfigCaptor = argumentCaptor() + val traceConfigCaptor = argumentCaptor() // When testedBridgeSdk.initialize(bridgeConfiguration.toReadableJavaOnlyMap(), mockPromise) // Then - verify(mockDatadog).initialize( - same(mockContext), - any(), - configCaptor.capture(), - eq(configuration.trackingConsent.asTrackingConsent()) - ) - assertThat(configCaptor.firstValue) + inOrder(mockDatadog) { + verify(mockDatadog).initialize( + same(mockContext), + sdkConfigCaptor.capture(), + any() + ) + verify(mockDatadog).enableRum(rumConfigCaptor.capture()) + verify(mockDatadog).enableTrace(traceConfigCaptor.capture()) + verify(mockDatadog).enableLogs(logsConfigCaptor.capture()) + } + assertThat(sdkConfigCaptor.firstValue) .hasFieldEqualTo( "additionalConfig", mapOf( @@ -1919,22 +1890,29 @@ internal class DdSdkTest { reactNativeVersion = reactNativeVersion ) ) - val configCaptor = argumentCaptor() + val sdkConfigCaptor = argumentCaptor() + val rumConfigCaptor = argumentCaptor() + val logsConfigCaptor = argumentCaptor() + val traceConfigCaptor = argumentCaptor() // When testedBridgeSdk.initialize(bridgeConfiguration.toReadableJavaOnlyMap(), mockPromise) // Then - verify(mockDatadog).initialize( - same(mockContext), - any(), - configCaptor.capture(), - eq(configuration.trackingConsent.asTrackingConsent()) - ) - assertThat(configCaptor.firstValue) - .hasField("rumConfig") { + inOrder(mockDatadog) { + verify(mockDatadog).initialize( + same(mockContext), + sdkConfigCaptor.capture(), + any() + ) + verify(mockDatadog).enableRum(rumConfigCaptor.capture()) + verify(mockDatadog).enableTrace(traceConfigCaptor.capture()) + verify(mockDatadog).enableLogs(logsConfigCaptor.capture()) + } + assertThat(rumConfigCaptor.firstValue) + .hasField("featureConfiguration") { val configurationMapper = it - .getActualValue>("rumEventMapper") + .getActualValue>("telemetryConfigurationMapper") val result = configurationMapper.map(telemetryConfigurationEvent)!! assertThat(result.telemetry.configuration.trackNativeErrors!!).isEqualTo( trackNativeErrors @@ -1967,22 +1945,29 @@ internal class DdSdkTest { @Forgery resourceEvent: ResourceEvent, ) { // Given - val configCaptor = argumentCaptor() + val sdkConfigCaptor = argumentCaptor() + val rumConfigCaptor = argumentCaptor() + val logsConfigCaptor = argumentCaptor() + val traceConfigCaptor = argumentCaptor() // When testedBridgeSdk.initialize(fakeConfiguration.toReadableJavaOnlyMap(), mockPromise) // Then - verify(mockDatadog).initialize( - same(mockContext), - any(), - configCaptor.capture(), - any() - ) - assertThat(configCaptor.firstValue) - .hasField("rumConfig") { + inOrder(mockDatadog) { + verify(mockDatadog).initialize( + same(mockContext), + sdkConfigCaptor.capture(), + any() + ) + verify(mockDatadog).enableRum(rumConfigCaptor.capture()) + verify(mockDatadog).enableTrace(traceConfigCaptor.capture()) + verify(mockDatadog).enableLogs(logsConfigCaptor.capture()) + } + assertThat(rumConfigCaptor.firstValue) + .hasField("featureConfiguration") { val resourceMapper = it - .getActualValue>("rumEventMapper") + .getActualValue>("resourceEventMapper") val notDroppedEvent = resourceMapper.map(resourceEvent) assertThat(notDroppedEvent).isNotNull } @@ -1993,23 +1978,30 @@ internal class DdSdkTest { @Forgery resourceEvent: ResourceEvent, ) { // Given - val configCaptor = argumentCaptor() + val sdkConfigCaptor = argumentCaptor() + val rumConfigCaptor = argumentCaptor() + val logsConfigCaptor = argumentCaptor() + val traceConfigCaptor = argumentCaptor() resourceEvent.context?.additionalProperties?.put("_dd.resource.drop_resource", true) // When testedBridgeSdk.initialize(fakeConfiguration.toReadableJavaOnlyMap(), mockPromise) // Then - verify(mockDatadog).initialize( - same(mockContext), - any(), - configCaptor.capture(), - any() - ) - assertThat(configCaptor.firstValue) - .hasField("rumConfig") { + inOrder(mockDatadog) { + verify(mockDatadog).initialize( + same(mockContext), + sdkConfigCaptor.capture(), + any() + ) + verify(mockDatadog).enableRum(rumConfigCaptor.capture()) + verify(mockDatadog).enableTrace(traceConfigCaptor.capture()) + verify(mockDatadog).enableLogs(logsConfigCaptor.capture()) + } + assertThat(rumConfigCaptor.firstValue) + .hasField("featureConfiguration") { val resourceMapper = it - .getActualValue>("rumEventMapper") + .getActualValue>("resourceEventMapper") val droppedEvent = resourceMapper.map(resourceEvent) assertThat(droppedEvent).isNull() } @@ -2024,22 +2016,29 @@ internal class DdSdkTest { @Forgery actionEvent: ActionEvent, ) { // Given - val configCaptor = argumentCaptor() + val sdkConfigCaptor = argumentCaptor() + val rumConfigCaptor = argumentCaptor() + val logsConfigCaptor = argumentCaptor() + val traceConfigCaptor = argumentCaptor() // When testedBridgeSdk.initialize(fakeConfiguration.toReadableJavaOnlyMap(), mockPromise) // Then - verify(mockDatadog).initialize( - same(mockContext), - any(), - configCaptor.capture(), - any() - ) - assertThat(configCaptor.firstValue) - .hasField("rumConfig") { + inOrder(mockDatadog) { + verify(mockDatadog).initialize( + same(mockContext), + sdkConfigCaptor.capture(), + any() + ) + verify(mockDatadog).enableRum(rumConfigCaptor.capture()) + verify(mockDatadog).enableTrace(traceConfigCaptor.capture()) + verify(mockDatadog).enableLogs(logsConfigCaptor.capture()) + } + assertThat(rumConfigCaptor.firstValue) + .hasField("featureConfiguration") { val actionMapper = it - .getActualValue>("rumEventMapper") + .getActualValue>("actionEventMapper") val notDroppedEvent = actionMapper.map(actionEvent) assertThat(notDroppedEvent).isNotNull } @@ -2050,23 +2049,30 @@ internal class DdSdkTest { @Forgery actionEvent: ActionEvent, ) { // Given - val configCaptor = argumentCaptor() + val sdkConfigCaptor = argumentCaptor() + val rumConfigCaptor = argumentCaptor() + val logsConfigCaptor = argumentCaptor() + val traceConfigCaptor = argumentCaptor() actionEvent.context?.additionalProperties?.put("_dd.action.drop_action", true) // When testedBridgeSdk.initialize(fakeConfiguration.toReadableJavaOnlyMap(), mockPromise) // Then - verify(mockDatadog).initialize( - same(mockContext), - any(), - configCaptor.capture(), - any() - ) - assertThat(configCaptor.firstValue) - .hasField("rumConfig") { + inOrder(mockDatadog) { + verify(mockDatadog).initialize( + same(mockContext), + sdkConfigCaptor.capture(), + any() + ) + verify(mockDatadog).enableRum(rumConfigCaptor.capture()) + verify(mockDatadog).enableTrace(traceConfigCaptor.capture()) + verify(mockDatadog).enableLogs(logsConfigCaptor.capture()) + } + assertThat(rumConfigCaptor.firstValue) + .hasField("featureConfiguration") { val actionMapper = it - .getActualValue>("rumEventMapper") + .getActualValue>("actionEventMapper") val droppedEvent = actionMapper.map(actionEvent) assertThat(droppedEvent).isNull() } diff --git a/packages/core/android/src/test/kotlin/com/datadog/tools/unit/DdSdkConfigurationExt.kt b/packages/core/android/src/test/kotlin/com/datadog/tools/unit/DdSdkConfigurationExt.kt index 6e4e61b7e..ec19003cc 100644 --- a/packages/core/android/src/test/kotlin/com/datadog/tools/unit/DdSdkConfigurationExt.kt +++ b/packages/core/android/src/test/kotlin/com/datadog/tools/unit/DdSdkConfigurationExt.kt @@ -8,7 +8,7 @@ package com.datadog.tools.unit import com.datadog.android.core.configuration.BatchSize import com.datadog.android.core.configuration.UploadFrequency -import com.datadog.android.core.configuration.VitalsUpdateFrequency +import com.datadog.android.rum.configuration.VitalsUpdateFrequency import com.datadog.reactnative.ConfigurationForTelemetry import com.datadog.reactnative.DdSdkConfiguration import com.facebook.react.bridge.ReadableMap diff --git a/packages/core/android/src/test/kotlin/com/datadog/tools/unit/MockRumMonitor.kt b/packages/core/android/src/test/kotlin/com/datadog/tools/unit/MockRumMonitor.kt new file mode 100644 index 000000000..46d39b825 --- /dev/null +++ b/packages/core/android/src/test/kotlin/com/datadog/tools/unit/MockRumMonitor.kt @@ -0,0 +1,49 @@ +package com.datadog.tools.unit + +import com.datadog.android.rum.RumMonitor + +class MockRumMonitor: RumMonitor { + override var debug = false + + override fun _getInternal(): com.datadog.android.rum._RumInternalProxy? { + return null + } + + override fun addAction(type: com.datadog.android.rum.RumActionType, name: kotlin.String, attributes: kotlin.collections.Map): kotlin.Unit {} + + override fun addAttribute(key: kotlin.String, value: kotlin.Any?): kotlin.Unit {} + + override fun addError(message: kotlin.String, source: com.datadog.android.rum.RumErrorSource, throwable: kotlin.Throwable?, attributes: kotlin.collections.Map): kotlin.Unit {} + + override fun addErrorWithStacktrace(message: kotlin.String, source: com.datadog.android.rum.RumErrorSource, stacktrace: kotlin.String?, attributes: kotlin.collections.Map): kotlin.Unit {} + + override fun addFeatureFlagEvaluation(name: kotlin.String, value: kotlin.Any): kotlin.Unit {} + + override fun addTiming(name: kotlin.String): kotlin.Unit {} + + override fun clearAttributes(): kotlin.Unit {} + + override fun getAttributes(): kotlin.collections.Map { + return mapOf() + } + + override fun removeAttribute(key: kotlin.String): kotlin.Unit {} + + override fun startAction(type: com.datadog.android.rum.RumActionType, name: kotlin.String, attributes: kotlin.collections.Map): kotlin.Unit {} + + override fun startResource(key: kotlin.String, method: kotlin.String, url: kotlin.String, attributes: kotlin.collections.Map): kotlin.Unit {} + + override fun startView(key: kotlin.Any, name: kotlin.String, attributes: kotlin.collections.Map): kotlin.Unit {} + + override fun stopAction(type: com.datadog.android.rum.RumActionType, name: kotlin.String, attributes: kotlin.collections.Map): kotlin.Unit {} + + override fun stopResource(key: kotlin.String, statusCode: kotlin.Int?, size: kotlin.Long?, kind: com.datadog.android.rum.RumResourceKind, attributes: kotlin.collections.Map): kotlin.Unit {} + + override fun stopResourceWithError(key: kotlin.String, statusCode: kotlin.Int?, message: kotlin.String, source: com.datadog.android.rum.RumErrorSource, stackTrace: kotlin.String, errorType: kotlin.String?, attributes: kotlin.collections.Map): kotlin.Unit {} + + override fun stopResourceWithError(key: kotlin.String, statusCode: kotlin.Int?, message: kotlin.String, source: com.datadog.android.rum.RumErrorSource, throwable: kotlin.Throwable, attributes: kotlin.collections.Map): kotlin.Unit {} + + override fun stopSession(): kotlin.Unit {} + + override fun stopView(key: kotlin.Any, attributes: kotlin.collections.Map): kotlin.Unit {} +} \ No newline at end of file diff --git a/packages/core/android/src/test/kotlin/com/datadog/tools/unit/forge/TelemetryConfigurationEventForgeryFactory.kt b/packages/core/android/src/test/kotlin/com/datadog/tools/unit/forge/TelemetryConfigurationEventForgeryFactory.kt index 7f56c3219..98a550338 100644 --- a/packages/core/android/src/test/kotlin/com/datadog/tools/unit/forge/TelemetryConfigurationEventForgeryFactory.kt +++ b/packages/core/android/src/test/kotlin/com/datadog/tools/unit/forge/TelemetryConfigurationEventForgeryFactory.kt @@ -59,6 +59,7 @@ internal class TelemetryConfigurationEventForgeryFactory : forge.aNullable { aBool() }, forge.aNullable { aBool() }, forge.aNullable { aBool() }, + forge.aNullable { aBool() }, forge.aNullable { aString() }, forge.aNullable { aBool() }, forge.aNullable { aBool() }, From 682369e9c1eea20200461637c594314941c3b1b1 Mon Sep 17 00:00:00 2001 From: louiszawadzki Date: Mon, 4 Sep 2023 10:38:00 +0200 Subject: [PATCH 08/28] Do not recreate proxies at every call --- .../datadog/reactnative/DatadogSDKWrapper.kt | 34 ++++++++++++++----- 1 file changed, 26 insertions(+), 8 deletions(-) diff --git a/packages/core/android/src/main/kotlin/com/datadog/reactnative/DatadogSDKWrapper.kt b/packages/core/android/src/main/kotlin/com/datadog/reactnative/DatadogSDKWrapper.kt index f6870d890..32cebbfe3 100644 --- a/packages/core/android/src/main/kotlin/com/datadog/reactnative/DatadogSDKWrapper.kt +++ b/packages/core/android/src/main/kotlin/com/datadog/reactnative/DatadogSDKWrapper.kt @@ -22,6 +22,16 @@ import com.datadog.android.webview.WebViewTracking internal class DatadogSDKWrapper : DatadogWrapper { + // lazy here is on purpose. The thing is that this class will be instantiated even before + // Sdk.initialize is called, but telemetry proxy can be created only after SDK is initialized. + private val telemetryProxy by lazy { Datadog._internalProxy() } + + // lazy here is on purpose. The thing is that this class will be instantiated even before + // Sdk.initialize is called, but webview proxy can be created only after SDK is initialized. + private val webViewProxy by lazy { + WebViewTracking._InternalWebViewProxy(Datadog.getInstance()) + } + override fun setVerbosity(level: Int) { Datadog.setVerbosity(level) } @@ -66,23 +76,31 @@ internal class DatadogSDKWrapper : DatadogWrapper { } override fun telemetryDebug(message: String) { - // TODO: store instance of proxy to avoid creating one every time - Datadog._internalProxy()._telemetry.debug(message) + // Do not initialize the telemetry proxy before SDK is initialized + if (isInitialized()) { + telemetryProxy._telemetry.debug(message) + } } override fun telemetryError(message: String, stack: String?, kind: String?) { - // TODO: store instance of proxy to avoid creating one every time - Datadog._internalProxy()._telemetry.error(message, stack, kind) + // Do not initialize the telemetry proxy before SDK is initialized + if (isInitialized()) { + telemetryProxy._telemetry.error(message, stack, kind) + } } override fun telemetryError(message: String, throwable: Throwable?) { - // TODO: store instance of proxy to avoid creating one every time - Datadog._internalProxy()._telemetry.error(message, throwable) + // Do not initialize the telemetry proxy before SDK is initialized + if (isInitialized()) { + telemetryProxy._telemetry.error(message, throwable) + } } override fun consumeWebviewEvent(message: String) { - // TODO: store instance of proxy to avoid creating one every time - WebViewTracking._InternalWebViewProxy(Datadog.getInstance()).consumeWebviewEvent(message) + // Do not initialize the webview proxy before SDK is initialized + if (isInitialized()) { + webViewProxy.consumeWebviewEvent(message) + } } override fun isInitialized(): Boolean { From 61c9bd47e8b0fed1c32aeef362de71873e12d3e5 Mon Sep 17 00:00:00 2001 From: louiszawadzki Date: Mon, 4 Sep 2023 10:52:54 +0200 Subject: [PATCH 09/28] Update ktlint --- packages/core/android/build.gradle | 3 +- .../kotlin/com/datadog/reactnative/DdTrace.kt | 2 +- .../com/datadog/reactnative/DdRumTest.kt | 55 +++++++---- .../com/datadog/reactnative/DdSdkTest.kt | 61 ++++++------ .../com/datadog/tools/unit/MockRumMonitor.kt | 93 +++++++++++++++---- .../com/datadog/tools/unit/ReflectUtils.kt | 1 - .../unit/forge/ActionEventForgeryFactory.kt | 2 +- .../forge/DdSdkConfigurationForgeryFactory.kt | 4 +- .../unit/forge/ResourceEventForgeryFactory.kt | 2 +- 9 files changed, 149 insertions(+), 74 deletions(-) diff --git a/packages/core/android/build.gradle b/packages/core/android/build.gradle index f2aff0433..10b8a18e7 100644 --- a/packages/core/android/build.gradle +++ b/packages/core/android/build.gradle @@ -12,7 +12,7 @@ buildscript { classpath 'com.android.tools.build:gradle:7.2.2' // noinspection DifferentKotlinGradleVersion classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version" - classpath "org.jlleitschuh.gradle:ktlint-gradle:10.2.1" + classpath "org.jlleitschuh.gradle:ktlint-gradle:11.5.1" classpath "io.gitlab.arturbosch.detekt:detekt-gradle-plugin:1.18.0" classpath 'com.github.bjoernq:unmockplugin:0.7.9' } @@ -207,7 +207,6 @@ ktlint { outputToConsole.set(true) ignoreFailures.set(false) enableExperimentalRules.set(false) - additionalEditorconfigFile.set(file("${project.rootDir}/script/config/.editorconfig")) filter { exclude("**/generated/**") include("**/kotlin/**") diff --git a/packages/core/android/src/oldarch/kotlin/com/datadog/reactnative/DdTrace.kt b/packages/core/android/src/oldarch/kotlin/com/datadog/reactnative/DdTrace.kt index 42687a692..7c26f4b75 100644 --- a/packages/core/android/src/oldarch/kotlin/com/datadog/reactnative/DdTrace.kt +++ b/packages/core/android/src/oldarch/kotlin/com/datadog/reactnative/DdTrace.kt @@ -16,7 +16,7 @@ import com.facebook.react.bridge.ReadableMap * The entry point to use Datadog's Trace feature. */ class DdTrace( - reactContext: ReactApplicationContext, + reactContext: ReactApplicationContext ) : ReactContextBaseJavaModule(reactContext) { private val implementation = DdTraceImplementation() diff --git a/packages/core/android/src/test/kotlin/com/datadog/reactnative/DdRumTest.kt b/packages/core/android/src/test/kotlin/com/datadog/reactnative/DdRumTest.kt index a328cecbc..b9c3797d2 100644 --- a/packages/core/android/src/test/kotlin/com/datadog/reactnative/DdRumTest.kt +++ b/packages/core/android/src/test/kotlin/com/datadog/reactnative/DdRumTest.kt @@ -6,10 +6,12 @@ package com.datadog.reactnative -import com.datadog.android.api.SdkCore -import com.datadog.android.rum.* +import com.datadog.android.rum.RumActionType +import com.datadog.android.rum.RumAttributes +import com.datadog.android.rum.RumErrorSource +import com.datadog.android.rum.RumMonitor +import com.datadog.android.rum.RumResourceKind import com.datadog.tools.unit.forge.BaseConfigurator -import com.datadog.tools.unit.setStaticValue import com.datadog.tools.unit.toReadableMap import com.facebook.react.bridge.Promise import com.nhaarman.mockitokotlin2.doReturn @@ -129,8 +131,11 @@ internal class DdRumTest { // When testedDdRum.addAction( - type.name, name, fakeContext.toReadableMap(), - fakeTimestamp, mockPromise + type.name, + name, + fakeContext.toReadableMap(), + fakeTimestamp, + mockPromise ) // Then @@ -166,8 +171,11 @@ internal class DdRumTest { // When testedDdRum.startAction( - type.name, name, fakeContext.toReadableMap(), - fakeTimestamp, mockPromise + type.name, + name, + fakeContext.toReadableMap(), + fakeTimestamp, + mockPromise ) // Then @@ -203,8 +211,11 @@ internal class DdRumTest { // When testedDdRum.stopAction( - type.name, name, fakeContext.toReadableMap(), - fakeTimestamp, mockPromise + type.name, + name, + fakeContext.toReadableMap(), + fakeTimestamp, + mockPromise ) // Then @@ -241,8 +252,12 @@ internal class DdRumTest { // When testedDdRum.startResource( - key, method, url, fakeContext.toReadableMap(), - fakeTimestamp, mockPromise + key, + method, + url, + fakeContext.toReadableMap(), + fakeTimestamp, + mockPromise ) // Then @@ -360,8 +375,12 @@ internal class DdRumTest { // When testedDdRum.addError( - message, source.name, stackTrace, fakeContext.toReadableMap(), - fakeTimestamp, mockPromise + message, + source.name, + stackTrace, + fakeContext.toReadableMap(), + fakeTimestamp, + mockPromise ) // Then @@ -381,8 +400,12 @@ internal class DdRumTest { // When testedDdRum.addError( - message, source, stackTrace, fakeContext.toReadableMap(), - fakeTimestamp, mockPromise + message, + source, + stackTrace, + fakeContext.toReadableMap(), + fakeTimestamp, + mockPromise ) // Then @@ -396,7 +419,6 @@ internal class DdRumTest { @Test fun `M call addTiming W addTiming()`(@StringForgery timing: String) { - // When testedDdRum.addTiming(timing, mockPromise) @@ -406,7 +428,6 @@ internal class DdRumTest { @Test fun `M call stopSession W stopSession()`() { - // When testedDdRum.stopSession(mockPromise) diff --git a/packages/core/android/src/test/kotlin/com/datadog/reactnative/DdSdkTest.kt b/packages/core/android/src/test/kotlin/com/datadog/reactnative/DdSdkTest.kt index e83a8a77a..2d2654384 100644 --- a/packages/core/android/src/test/kotlin/com/datadog/reactnative/DdSdkTest.kt +++ b/packages/core/android/src/test/kotlin/com/datadog/reactnative/DdSdkTest.kt @@ -16,7 +16,9 @@ import com.datadog.android.core.configuration.UploadFrequency import com.datadog.android.event.EventMapper import com.datadog.android.log.LogsConfiguration import com.datadog.android.privacy.TrackingConsent -import com.datadog.android.rum.* +import com.datadog.android.rum.RumConfiguration +import com.datadog.android.rum.RumPerformanceMetric +import com.datadog.android.rum._RumInternalProxy import com.datadog.android.rum.configuration.VitalsUpdateFrequency import com.datadog.android.rum.model.ActionEvent import com.datadog.android.rum.model.ResourceEvent @@ -24,9 +26,13 @@ import com.datadog.android.rum.tracking.ActivityViewTrackingStrategy import com.datadog.android.telemetry.model.TelemetryConfigurationEvent import com.datadog.android.trace.TraceConfiguration import com.datadog.android.trace.TracingHeaderType -import com.datadog.tools.unit.* import com.datadog.tools.unit.GenericAssert.Companion.assertThat +import com.datadog.tools.unit.MockRumMonitor import com.datadog.tools.unit.forge.BaseConfigurator +import com.datadog.tools.unit.setStaticValue +import com.datadog.tools.unit.toReadableArray +import com.datadog.tools.unit.toReadableJavaOnlyMap +import com.datadog.tools.unit.toReadableMap import com.facebook.react.bridge.Promise import com.facebook.react.bridge.ReactApplicationContext import com.facebook.react.bridge.ReadableMap @@ -58,7 +64,6 @@ import fr.xgouchet.elmyr.junit5.ForgeExtension import java.net.InetSocketAddress import java.net.Proxy import java.util.Locale -import java.util.concurrent.atomic.AtomicBoolean import java.util.stream.Stream import org.assertj.core.api.Assertions.assertThat import org.junit.jupiter.api.AfterEach @@ -317,7 +322,6 @@ internal class DdSdkTest { .hasField("featureConfiguration") { it.hasFieldEqualTo("sampleRate", expectedRumSampleRate) } - } // endregion @@ -1134,6 +1138,7 @@ internal class DdSdkTest { it.hasFieldEqualTo("userActionTracking", true) } } + @Test fun `𝕄 initialize native SDK 𝕎 initialize() {sdk verbosity}`( @Forgery configuration: DdSdkConfiguration, @@ -1257,12 +1262,12 @@ internal class DdSdkTest { verify(mockDatadog).enableLogs(logsConfigCaptor.capture()) } assertThat(rumConfigCaptor.firstValue) - .hasField("featureConfiguration") { rumConfig -> + .hasField("featureConfiguration") { rumConfig -> rumConfig.hasField("longTaskTrackingStrategy") { longTaskTrackingStrategy -> longTaskTrackingStrategy .isInstanceOf( "com.datadog.android.rum.internal.instrumentation." + - "MainLooperLongTaskStrategy" + "MainLooperLongTaskStrategy" ) .hasFieldEqualTo("thresholdMs", threshold.toLong()) } @@ -1298,7 +1303,7 @@ internal class DdSdkTest { verify(mockDatadog).enableLogs(logsConfigCaptor.capture()) } assertThat(rumConfigCaptor.firstValue) - .hasField("featureConfiguration") { rumConfig -> + .hasField("featureConfiguration") { rumConfig -> rumConfig.doesNotHaveField("longTaskTrackingStrategy") } } @@ -1378,7 +1383,7 @@ internal class DdSdkTest { Pair( forge.aStringMatching("[a-z]+\\.[a-z]{3}"), setOf( - TracingHeaderType.DATADOG, + TracingHeaderType.DATADOG ) ) } @@ -1441,9 +1446,9 @@ internal class DdSdkTest { host, setOf( TracingHeaderType.DATADOG, - TracingHeaderType.B3, + TracingHeaderType.B3 ) - ), + ) ) val firstPartyHosts = mutableListOf() @@ -1451,7 +1456,7 @@ internal class DdSdkTest { mapOf( "match" to host, "propagatorTypes" to listOf( - TracingHeaderType.DATADOG.name.lowercase(), + TracingHeaderType.DATADOG.name.lowercase() ).toReadableArray() ).toReadableMap() ) @@ -1459,7 +1464,7 @@ internal class DdSdkTest { mapOf( "match" to host, "propagatorTypes" to listOf( - TracingHeaderType.B3.name.lowercase(), + TracingHeaderType.B3.name.lowercase() ).toReadableArray() ).toReadableMap() ) @@ -1507,7 +1512,7 @@ internal class DdSdkTest { ) { // Given val bridgeConfiguration = configuration.copy( - uploadFrequency = input, + uploadFrequency = input ) val sdkConfigCaptor = argumentCaptor() val rumConfigCaptor = argumentCaptor() @@ -1546,7 +1551,7 @@ internal class DdSdkTest { ) { // Given val bridgeConfiguration = configuration.copy( - batchSize = input, + batchSize = input ) val sdkConfigCaptor = argumentCaptor() val rumConfigCaptor = argumentCaptor() @@ -1584,7 +1589,7 @@ internal class DdSdkTest { // Given val trackBackgroundEvents = forge.aNullable { forge.aBool() } val bridgeConfiguration = configuration.copy( - trackBackgroundEvents = trackBackgroundEvents, + trackBackgroundEvents = trackBackgroundEvents ) val sdkConfigCaptor = argumentCaptor() val rumConfigCaptor = argumentCaptor() @@ -1751,7 +1756,7 @@ internal class DdSdkTest { // Given val bridgeConfiguration = configuration.copy( vitalsUpdateFrequency = "AVERAGE", - longTaskThresholdMs = (threshold / 1_000_000).toDouble(), + longTaskThresholdMs = (threshold / 1_000_000).toDouble() ) val frameDurationNs = threshold + frameDurationOverThreshold @@ -1788,7 +1793,7 @@ internal class DdSdkTest { // Given val bridgeConfiguration = configuration.copy( vitalsUpdateFrequency = "NEVER", - longTaskThresholdMs = (threshold / 1_000_000).toDouble(), + longTaskThresholdMs = (threshold / 1_000_000).toDouble() ) val frameDurationNs = threshold + frameDurationOverThreshold @@ -1912,7 +1917,9 @@ internal class DdSdkTest { assertThat(rumConfigCaptor.firstValue) .hasField("featureConfiguration") { val configurationMapper = it - .getActualValue>("telemetryConfigurationMapper") + .getActualValue>( + "telemetryConfigurationMapper" + ) val result = configurationMapper.map(telemetryConfigurationEvent)!! assertThat(result.telemetry.configuration.trackNativeErrors!!).isEqualTo( trackNativeErrors @@ -1942,7 +1949,7 @@ internal class DdSdkTest { @Test fun `𝕄 set a resource mapper that does not drop resources 𝕎 initialize() {}`( - @Forgery resourceEvent: ResourceEvent, + @Forgery resourceEvent: ResourceEvent ) { // Given val sdkConfigCaptor = argumentCaptor() @@ -1975,7 +1982,7 @@ internal class DdSdkTest { @Test fun `𝕄 set a resource mapper that drops flagged resources 𝕎 initialize() {}`( - @Forgery resourceEvent: ResourceEvent, + @Forgery resourceEvent: ResourceEvent ) { // Given val sdkConfigCaptor = argumentCaptor() @@ -2013,7 +2020,7 @@ internal class DdSdkTest { @Test fun `𝕄 set a action mapper that does not drop actions 𝕎 initialize() {}`( - @Forgery actionEvent: ActionEvent, + @Forgery actionEvent: ActionEvent ) { // Given val sdkConfigCaptor = argumentCaptor() @@ -2046,7 +2053,7 @@ internal class DdSdkTest { @Test fun `𝕄 set a action mapper that drops flagged actions 𝕎 initialize() {}`( - @Forgery actionEvent: ActionEvent, + @Forgery actionEvent: ActionEvent ) { // Given val sdkConfigCaptor = argumentCaptor() @@ -2272,7 +2279,6 @@ internal class DdSdkTest { @Test fun `𝕄 build Granted consent 𝕎 buildTrackingConsent {granted}`(forge: Forge) { - // When val consent = testedBridgeSdk.buildTrackingConsent( forge.anElementFrom("granted", "GRANTED") @@ -2284,7 +2290,6 @@ internal class DdSdkTest { @Test fun `𝕄 build Pending consent 𝕎 buildTrackingConsent {pending}`(forge: Forge) { - // When val consent = testedBridgeSdk.buildTrackingConsent( forge.anElementFrom("pending", "PENDING") @@ -2296,7 +2301,6 @@ internal class DdSdkTest { @Test fun `𝕄 build Granted consent 𝕎 buildTrackingConsent {not_granted}`(forge: Forge) { - // When val consent = testedBridgeSdk.buildTrackingConsent( forge.anElementFrom("not_granted", "NOT_GRANTED") @@ -2308,7 +2312,6 @@ internal class DdSdkTest { @Test fun `𝕄 build default Pending consent 𝕎 buildTrackingConsent {any}`(forge: Forge) { - // When val consent = testedBridgeSdk.buildTrackingConsent( forge.anElementFrom(null, "some-type") @@ -2320,7 +2323,6 @@ internal class DdSdkTest { @Test fun `𝕄 call setTrackingConsent 𝕎 setTrackingConsent ()`(forge: Forge) { - // Given val consent = forge.anElementFrom("pending", "granted", "not_granted") @@ -2335,7 +2337,6 @@ internal class DdSdkTest { fun `𝕄 not build proxy config 𝕎 no proxy config specified`( @Forgery configuration: DdSdkConfiguration ) { - // Given val config = configuration.copy(additionalConfig = null) @@ -2526,7 +2527,7 @@ internal class DdSdkTest { return Stream.of( Arguments.of("SMALL", BatchSize.SMALL), Arguments.of("MEDIUM", BatchSize.MEDIUM), - Arguments.of("LARGE", BatchSize.LARGE), + Arguments.of("LARGE", BatchSize.LARGE) ) } @@ -2535,7 +2536,7 @@ internal class DdSdkTest { return Stream.of( Arguments.of("RARE", UploadFrequency.RARE), Arguments.of("AVERAGE", UploadFrequency.AVERAGE), - Arguments.of("FREQUENT", UploadFrequency.FREQUENT), + Arguments.of("FREQUENT", UploadFrequency.FREQUENT) ) } } diff --git a/packages/core/android/src/test/kotlin/com/datadog/tools/unit/MockRumMonitor.kt b/packages/core/android/src/test/kotlin/com/datadog/tools/unit/MockRumMonitor.kt index 46d39b825..2ae8cfd50 100644 --- a/packages/core/android/src/test/kotlin/com/datadog/tools/unit/MockRumMonitor.kt +++ b/packages/core/android/src/test/kotlin/com/datadog/tools/unit/MockRumMonitor.kt @@ -2,20 +2,34 @@ package com.datadog.tools.unit import com.datadog.android.rum.RumMonitor -class MockRumMonitor: RumMonitor { +class MockRumMonitor : RumMonitor { override var debug = false override fun _getInternal(): com.datadog.android.rum._RumInternalProxy? { return null } - override fun addAction(type: com.datadog.android.rum.RumActionType, name: kotlin.String, attributes: kotlin.collections.Map): kotlin.Unit {} + override fun addAction( + type: com.datadog.android.rum.RumActionType, + name: kotlin.String, + attributes: kotlin.collections.Map + ): kotlin.Unit {} override fun addAttribute(key: kotlin.String, value: kotlin.Any?): kotlin.Unit {} - override fun addError(message: kotlin.String, source: com.datadog.android.rum.RumErrorSource, throwable: kotlin.Throwable?, attributes: kotlin.collections.Map): kotlin.Unit {} + override fun addError( + message: kotlin.String, + source: com.datadog.android.rum.RumErrorSource, + throwable: kotlin.Throwable?, + attributes: kotlin.collections.Map + ): kotlin.Unit {} - override fun addErrorWithStacktrace(message: kotlin.String, source: com.datadog.android.rum.RumErrorSource, stacktrace: kotlin.String?, attributes: kotlin.collections.Map): kotlin.Unit {} + override fun addErrorWithStacktrace( + message: kotlin.String, + source: com.datadog.android.rum.RumErrorSource, + stacktrace: kotlin.String?, + attributes: kotlin.collections.Map + ): kotlin.Unit {} override fun addFeatureFlagEvaluation(name: kotlin.String, value: kotlin.Any): kotlin.Unit {} @@ -29,21 +43,62 @@ class MockRumMonitor: RumMonitor { override fun removeAttribute(key: kotlin.String): kotlin.Unit {} - override fun startAction(type: com.datadog.android.rum.RumActionType, name: kotlin.String, attributes: kotlin.collections.Map): kotlin.Unit {} - - override fun startResource(key: kotlin.String, method: kotlin.String, url: kotlin.String, attributes: kotlin.collections.Map): kotlin.Unit {} - - override fun startView(key: kotlin.Any, name: kotlin.String, attributes: kotlin.collections.Map): kotlin.Unit {} - - override fun stopAction(type: com.datadog.android.rum.RumActionType, name: kotlin.String, attributes: kotlin.collections.Map): kotlin.Unit {} - - override fun stopResource(key: kotlin.String, statusCode: kotlin.Int?, size: kotlin.Long?, kind: com.datadog.android.rum.RumResourceKind, attributes: kotlin.collections.Map): kotlin.Unit {} - - override fun stopResourceWithError(key: kotlin.String, statusCode: kotlin.Int?, message: kotlin.String, source: com.datadog.android.rum.RumErrorSource, stackTrace: kotlin.String, errorType: kotlin.String?, attributes: kotlin.collections.Map): kotlin.Unit {} - - override fun stopResourceWithError(key: kotlin.String, statusCode: kotlin.Int?, message: kotlin.String, source: com.datadog.android.rum.RumErrorSource, throwable: kotlin.Throwable, attributes: kotlin.collections.Map): kotlin.Unit {} + override fun startAction( + type: com.datadog.android.rum.RumActionType, + name: kotlin.String, + attributes: kotlin.collections.Map + ): kotlin.Unit {} + + override fun startResource( + key: kotlin.String, + method: kotlin.String, + url: kotlin.String, + attributes: kotlin.collections.Map + ): kotlin.Unit {} + + override fun startView( + key: kotlin.Any, + name: kotlin.String, + attributes: kotlin.collections.Map + ): kotlin.Unit {} + + override fun stopAction( + type: com.datadog.android.rum.RumActionType, + name: kotlin.String, + attributes: kotlin.collections.Map + ): kotlin.Unit {} + + override fun stopResource( + key: kotlin.String, + statusCode: kotlin.Int?, + size: kotlin.Long?, + kind: com.datadog.android.rum.RumResourceKind, + attributes: kotlin.collections.Map + ): kotlin.Unit {} + + override fun stopResourceWithError( + key: kotlin.String, + statusCode: kotlin.Int?, + message: kotlin.String, + source: com.datadog.android.rum.RumErrorSource, + stackTrace: kotlin.String, + errorType: kotlin.String?, + attributes: kotlin.collections.Map + ): kotlin.Unit {} + + override fun stopResourceWithError( + key: kotlin.String, + statusCode: kotlin.Int?, + message: kotlin.String, + source: com.datadog.android.rum.RumErrorSource, + throwable: kotlin.Throwable, + attributes: kotlin.collections.Map + ): kotlin.Unit {} override fun stopSession(): kotlin.Unit {} - override fun stopView(key: kotlin.Any, attributes: kotlin.collections.Map): kotlin.Unit {} -} \ No newline at end of file + override fun stopView( + key: kotlin.Any, + attributes: kotlin.collections.Map + ): kotlin.Unit {} +} diff --git a/packages/core/android/src/test/kotlin/com/datadog/tools/unit/ReflectUtils.kt b/packages/core/android/src/test/kotlin/com/datadog/tools/unit/ReflectUtils.kt index 291c840f8..49beb4465 100644 --- a/packages/core/android/src/test/kotlin/com/datadog/tools/unit/ReflectUtils.kt +++ b/packages/core/android/src/test/kotlin/com/datadog/tools/unit/ReflectUtils.kt @@ -81,7 +81,6 @@ inline fun getStaticValue( * @param fieldName the name of the field */ inline fun Class.getStaticValue(fieldName: String): R { - val field = getDeclaredField(fieldName) // make it accessible diff --git a/packages/core/android/src/test/kotlin/com/datadog/tools/unit/forge/ActionEventForgeryFactory.kt b/packages/core/android/src/test/kotlin/com/datadog/tools/unit/forge/ActionEventForgeryFactory.kt index e39a24f3c..994f28703 100644 --- a/packages/core/android/src/test/kotlin/com/datadog/tools/unit/forge/ActionEventForgeryFactory.kt +++ b/packages/core/android/src/test/kotlin/com/datadog/tools/unit/forge/ActionEventForgeryFactory.kt @@ -92,7 +92,7 @@ internal class ActionEventForgeryFactory : name = forge.anAlphabeticalString(), model = forge.anAlphabeticalString(), brand = forge.anAlphabeticalString(), - type = forge.aValueFrom(ActionEvent.DeviceType::class.java), + type = forge.aValueFrom(ActionEvent.DeviceType::class.java) ), context = ActionEvent.Context( additionalProperties = mutableMapOf() diff --git a/packages/core/android/src/test/kotlin/com/datadog/tools/unit/forge/DdSdkConfigurationForgeryFactory.kt b/packages/core/android/src/test/kotlin/com/datadog/tools/unit/forge/DdSdkConfigurationForgeryFactory.kt index 6ca158254..5294931b1 100644 --- a/packages/core/android/src/test/kotlin/com/datadog/tools/unit/forge/DdSdkConfigurationForgeryFactory.kt +++ b/packages/core/android/src/test/kotlin/com/datadog/tools/unit/forge/DdSdkConfigurationForgeryFactory.kt @@ -63,9 +63,9 @@ class DdSdkConfigurationForgeryFactory : ForgeryFactory { trackInteractions = forge.aBool(), trackNetworkRequests = forge.aBool(), reactVersion = forge.aString(), - reactNativeVersion = forge.aString(), + reactNativeVersion = forge.aString() ), - trackFrustrations = forge.aNullable { aBool() }, + trackFrustrations = forge.aNullable { aBool() } ) } } diff --git a/packages/core/android/src/test/kotlin/com/datadog/tools/unit/forge/ResourceEventForgeryFactory.kt b/packages/core/android/src/test/kotlin/com/datadog/tools/unit/forge/ResourceEventForgeryFactory.kt index 6cfaf3930..dae18a67d 100644 --- a/packages/core/android/src/test/kotlin/com/datadog/tools/unit/forge/ResourceEventForgeryFactory.kt +++ b/packages/core/android/src/test/kotlin/com/datadog/tools/unit/forge/ResourceEventForgeryFactory.kt @@ -100,7 +100,7 @@ internal class ResourceEventForgeryFactory : name = forge.anAlphabeticalString(), model = forge.anAlphabeticalString(), brand = forge.anAlphabeticalString(), - type = forge.aValueFrom(ResourceEvent.DeviceType::class.java), + type = forge.aValueFrom(ResourceEvent.DeviceType::class.java) ), context = ResourceEvent.Context( additionalProperties = mutableMapOf() From d2d074f7a6bc73e557ee6a42d1d44cec94aca289 Mon Sep 17 00:00:00 2001 From: louiszawadzki Date: Wed, 6 Sep 2023 11:07:57 +0200 Subject: [PATCH 10/28] Get RUM Monitor only once when adding attributes --- .../main/kotlin/com/datadog/reactnative/DatadogSDKWrapper.kt | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/packages/core/android/src/main/kotlin/com/datadog/reactnative/DatadogSDKWrapper.kt b/packages/core/android/src/main/kotlin/com/datadog/reactnative/DatadogSDKWrapper.kt index 32cebbfe3..e2b5b89cc 100644 --- a/packages/core/android/src/main/kotlin/com/datadog/reactnative/DatadogSDKWrapper.kt +++ b/packages/core/android/src/main/kotlin/com/datadog/reactnative/DatadogSDKWrapper.kt @@ -66,8 +66,9 @@ internal class DatadogSDKWrapper : DatadogWrapper { } override fun addRumGlobalAttributes(attributes: Map) { + val rumMonitor = this.getRumMonitor() attributes.forEach { - this.getRumMonitor().addAttribute(it.key, it.value) + rumMonitor.addAttribute(it.key, it.value) } } From 604e8afce783eabb231658017cd827c592c63dea Mon Sep 17 00:00:00 2001 From: louiszawadzki Date: Wed, 6 Sep 2023 11:10:18 +0200 Subject: [PATCH 11/28] Rename configuration builders --- .../kotlin/com/datadog/reactnative/DdSdkImplementation.kt | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/packages/core/android/src/main/kotlin/com/datadog/reactnative/DdSdkImplementation.kt b/packages/core/android/src/main/kotlin/com/datadog/reactnative/DdSdkImplementation.kt index 56d433dde..fac7489ab 100644 --- a/packages/core/android/src/main/kotlin/com/datadog/reactnative/DdSdkImplementation.kt +++ b/packages/core/android/src/main/kotlin/com/datadog/reactnative/DdSdkImplementation.kt @@ -54,8 +54,8 @@ class DdSdkImplementation( */ fun initialize(configuration: ReadableMap, promise: Promise) { val ddSdkConfiguration = configuration.asDdSdkConfiguration() - val sdkConfiguration = buildSDKConfiguration(ddSdkConfiguration) - val rumConfiguration = buildRUMConfiguration(ddSdkConfiguration) + val sdkConfiguration = buildSdkConfiguration(ddSdkConfiguration) + val rumConfiguration = buildRumConfiguration(ddSdkConfiguration) val trackingConsent = buildTrackingConsent(ddSdkConfiguration.trackingConsent) configureSdkVerbosity(ddSdkConfiguration) @@ -177,7 +177,7 @@ class DdSdkImplementation( } @Suppress("ComplexMethod", "LongMethod", "UnsafeCallOnNullableType") - private fun buildRUMConfiguration(configuration: DdSdkConfiguration): RumConfiguration { + private fun buildRumConfiguration(configuration: DdSdkConfiguration): RumConfiguration { val configBuilder = RumConfiguration.Builder( applicationId = configuration.applicationId @@ -307,7 +307,7 @@ class DdSdkImplementation( return firstPartyHostsWithHeaderTypes } - private fun buildSDKConfiguration(configuration: DdSdkConfiguration): Configuration { + private fun buildSdkConfiguration(configuration: DdSdkConfiguration): Configuration { val serviceName = configuration.additionalConfig?.get(DD_SERVICE_NAME) as? String val configBuilder = Configuration.Builder( clientToken = configuration.clientToken, From 33d3d7d3a7fe143b6d9632a31eacd4a33d519b86 Mon Sep 17 00:00:00 2001 From: louiszawadzki Date: Wed, 6 Sep 2023 11:13:17 +0200 Subject: [PATCH 12/28] Clean imports in MockRumMonitor --- .../com/datadog/tools/unit/MockRumMonitor.kt | 130 +++++++++--------- 1 file changed, 67 insertions(+), 63 deletions(-) diff --git a/packages/core/android/src/test/kotlin/com/datadog/tools/unit/MockRumMonitor.kt b/packages/core/android/src/test/kotlin/com/datadog/tools/unit/MockRumMonitor.kt index 2ae8cfd50..d389be984 100644 --- a/packages/core/android/src/test/kotlin/com/datadog/tools/unit/MockRumMonitor.kt +++ b/packages/core/android/src/test/kotlin/com/datadog/tools/unit/MockRumMonitor.kt @@ -1,104 +1,108 @@ package com.datadog.tools.unit +import com.datadog.android.rum.RumActionType +import com.datadog.android.rum.RumErrorSource import com.datadog.android.rum.RumMonitor +import com.datadog.android.rum.RumResourceKind +import com.datadog.android.rum._RumInternalProxy class MockRumMonitor : RumMonitor { override var debug = false - override fun _getInternal(): com.datadog.android.rum._RumInternalProxy? { + override fun _getInternal(): _RumInternalProxy? { return null } override fun addAction( - type: com.datadog.android.rum.RumActionType, - name: kotlin.String, - attributes: kotlin.collections.Map - ): kotlin.Unit {} + type: RumActionType, + name: String, + attributes: Map + ) {} - override fun addAttribute(key: kotlin.String, value: kotlin.Any?): kotlin.Unit {} + override fun addAttribute(key: String, value: Any?) {} override fun addError( - message: kotlin.String, - source: com.datadog.android.rum.RumErrorSource, - throwable: kotlin.Throwable?, - attributes: kotlin.collections.Map - ): kotlin.Unit {} + message: String, + source: RumErrorSource, + throwable: Throwable?, + attributes: Map + ) {} override fun addErrorWithStacktrace( - message: kotlin.String, - source: com.datadog.android.rum.RumErrorSource, - stacktrace: kotlin.String?, - attributes: kotlin.collections.Map - ): kotlin.Unit {} + message: String, + source: RumErrorSource, + stacktrace: String?, + attributes: Map + ) {} - override fun addFeatureFlagEvaluation(name: kotlin.String, value: kotlin.Any): kotlin.Unit {} + override fun addFeatureFlagEvaluation(name: String, value: Any) {} - override fun addTiming(name: kotlin.String): kotlin.Unit {} + override fun addTiming(name: String) {} - override fun clearAttributes(): kotlin.Unit {} + override fun clearAttributes() {} - override fun getAttributes(): kotlin.collections.Map { + override fun getAttributes(): Map { return mapOf() } - override fun removeAttribute(key: kotlin.String): kotlin.Unit {} + override fun removeAttribute(key: String) {} override fun startAction( - type: com.datadog.android.rum.RumActionType, - name: kotlin.String, - attributes: kotlin.collections.Map - ): kotlin.Unit {} + type: RumActionType, + name: String, + attributes: Map + ) {} override fun startResource( - key: kotlin.String, - method: kotlin.String, - url: kotlin.String, - attributes: kotlin.collections.Map - ): kotlin.Unit {} + key: String, + method: String, + url: String, + attributes: Map + ) {} override fun startView( - key: kotlin.Any, - name: kotlin.String, - attributes: kotlin.collections.Map - ): kotlin.Unit {} + key: Any, + name: String, + attributes: Map + ) {} override fun stopAction( - type: com.datadog.android.rum.RumActionType, - name: kotlin.String, - attributes: kotlin.collections.Map - ): kotlin.Unit {} + type: RumActionType, + name: String, + attributes: Map + ) {} override fun stopResource( - key: kotlin.String, - statusCode: kotlin.Int?, - size: kotlin.Long?, - kind: com.datadog.android.rum.RumResourceKind, - attributes: kotlin.collections.Map - ): kotlin.Unit {} + key: String, + statusCode: Int?, + size: Long?, + kind: RumResourceKind, + attributes: Map + ) {} override fun stopResourceWithError( - key: kotlin.String, - statusCode: kotlin.Int?, - message: kotlin.String, - source: com.datadog.android.rum.RumErrorSource, - stackTrace: kotlin.String, - errorType: kotlin.String?, - attributes: kotlin.collections.Map - ): kotlin.Unit {} + key: String, + statusCode: Int?, + message: String, + source: RumErrorSource, + stackTrace: String, + errorType: String?, + attributes: Map + ) {} override fun stopResourceWithError( - key: kotlin.String, - statusCode: kotlin.Int?, - message: kotlin.String, - source: com.datadog.android.rum.RumErrorSource, - throwable: kotlin.Throwable, - attributes: kotlin.collections.Map - ): kotlin.Unit {} + key: String, + statusCode: Int?, + message: String, + source: RumErrorSource, + throwable: Throwable, + attributes: Map + ) {} - override fun stopSession(): kotlin.Unit {} + override fun stopSession() {} override fun stopView( - key: kotlin.Any, - attributes: kotlin.collections.Map - ): kotlin.Unit {} + key: Any, + attributes: Map + ) {} } From 00a7d78ebb26fbb410da24aa03f2b739ab102ee1 Mon Sep 17 00:00:00 2001 From: louiszawadzki Date: Tue, 5 Sep 2023 16:46:09 +0200 Subject: [PATCH 13/28] Migrate iOS SDK to v2 --- example/ios/Podfile | 4 +- example/ios/Podfile.lock | 61 +- packages/core/DatadogSDKReactNative.podspec | 10 +- .../ios/Sources/DdLogsImplementation.swift | 48 +- .../ios/Sources/DdRumImplementation.swift | 65 +-- .../core/ios/Sources/DdSdkConfiguration.swift | 63 +- .../ios/Sources/DdSdkImplementation.swift | 266 ++++----- .../ios/Sources/DdTraceImplementation.swift | 4 +- .../ios/Sources/RNDdSdkConfiguration.swift | 6 +- .../Sources/RUMMonitorInternalProtocol.swift | 40 ++ packages/core/ios/Tests/DdLogsTests.swift | 75 ++- packages/core/ios/Tests/DdRumTests.swift | 143 +---- packages/core/ios/Tests/DdSdkTests.swift | 539 ++++++++++-------- packages/core/ios/Tests/DdTraceTests.swift | 3 +- packages/core/ios/Tests/MockRUMMonitor.swift | 159 ++++++ packages/core/ios/Tests/RUMMocks.swift | 6 +- 16 files changed, 879 insertions(+), 613 deletions(-) create mode 100644 packages/core/ios/Sources/RUMMonitorInternalProtocol.swift create mode 100644 packages/core/ios/Tests/MockRUMMonitor.swift diff --git a/example/ios/Podfile b/example/ios/Podfile index 087ef4640..8cfc614ed 100644 --- a/example/ios/Podfile +++ b/example/ios/Podfile @@ -22,6 +22,8 @@ if linkage != nil end target 'ddSdkReactnativeExample' do + pod 'DatadogSDKReactNative', :path => '../../packages/core/DatadogSDKReactNative.podspec', :testspecs => ['Tests'] + config = use_native_modules! # Flags change depending on the env values. @@ -59,7 +61,7 @@ target 'ddSdkReactnativeExample' do ) __apply_Xcode_12_5_M1_post_install_workaround(installer) # Enable `DD_SDK_COMPILED_FOR_TESTING` condition when compiling `DatadogSDK` dependency: - datadog_sdk_target = installer.pods_project.targets.detect {|t| t.name == "DatadogSDK" } + datadog_sdk_target = installer.pods_project.targets.detect {|t| ["DatadogCore", "DatadogRUM", "DatadogLogs", "DatadogInternal", "DatadogTrace"].include?(t.name) } datadog_sdk_target.build_configurations.each do |config| config.build_settings['SWIFT_ACTIVE_COMPILATION_CONDITIONS'] = '$(inherited) DD_SDK_COMPILED_FOR_TESTING' end diff --git a/example/ios/Podfile.lock b/example/ios/Podfile.lock index f763a338c..b8a41248e 100644 --- a/example/ios/Podfile.lock +++ b/example/ios/Podfile.lock @@ -1,13 +1,35 @@ PODS: - boost (1.76.0) - - DatadogSDK (1.22.0) - - DatadogSDKCrashReporting (1.22.0): - - DatadogSDK (= 1.22.0) - - PLCrashReporter (~> 1.11.0) + - DatadogCore (2.1.2): + - DatadogInternal (= 2.1.2) + - DatadogCrashReporting (2.1.2): + - DatadogInternal (= 2.1.2) + - PLCrashReporter (~> 1.11.1) + - DatadogInternal (2.1.2) + - DatadogLogs (2.1.2): + - DatadogInternal (= 2.1.2) + - DatadogRUM (2.1.2): + - DatadogInternal (= 2.1.2) - DatadogSDKReactNative (1.8.5): - - DatadogSDK (~> 1.22.0) - - DatadogSDKCrashReporting (~> 1.22.0) + - DatadogCore (~> 2.1.2) + - DatadogCrashReporting (~> 2.1.2) + - DatadogLogs (~> 2.1.2) + - DatadogRUM (~> 2.1.2) + - DatadogTrace (~> 2.1.2) + - DatadogWebViewTracking (~> 2.1.2) - React-Core + - DatadogSDKReactNative/Tests (1.8.5): + - DatadogCore (~> 2.1.2) + - DatadogCrashReporting (~> 2.1.2) + - DatadogLogs (~> 2.1.2) + - DatadogRUM (~> 2.1.2) + - DatadogTrace (~> 2.1.2) + - DatadogWebViewTracking (~> 2.1.2) + - React-Core + - DatadogTrace (2.1.2): + - DatadogInternal (= 2.1.2) + - DatadogWebViewTracking (2.1.2): + - DatadogInternal (= 2.1.2) - DoubleConversion (1.1.6) - FBLazyVector (0.71.10) - FBReactNativeSpec (0.71.10): @@ -387,7 +409,8 @@ PODS: DEPENDENCIES: - boost (from `../node_modules/react-native/third-party-podspecs/boost.podspec`) - - "DatadogSDKReactNative (from `../node_modules/@datadog/mobile-react-native`)" + - DatadogSDKReactNative (from `../../packages/core/DatadogSDKReactNative.podspec`) + - DatadogSDKReactNative/Tests (from `../../packages/core/DatadogSDKReactNative.podspec`) - DoubleConversion (from `../node_modules/react-native/third-party-podspecs/DoubleConversion.podspec`) - FBLazyVector (from `../node_modules/react-native/Libraries/FBLazyVector`) - FBReactNativeSpec (from `../node_modules/react-native/React/FBReactNativeSpec`) @@ -433,8 +456,13 @@ DEPENDENCIES: SPEC REPOS: trunk: - - DatadogSDK - - DatadogSDKCrashReporting + - DatadogCore + - DatadogCrashReporting + - DatadogInternal + - DatadogLogs + - DatadogRUM + - DatadogTrace + - DatadogWebViewTracking - fmt - HMSegmentedControl - libevent @@ -444,7 +472,7 @@ EXTERNAL SOURCES: boost: :podspec: "../node_modules/react-native/third-party-podspecs/boost.podspec" DatadogSDKReactNative: - :path: "../node_modules/@datadog/mobile-react-native" + :path: "../../packages/core/DatadogSDKReactNative.podspec" DoubleConversion: :podspec: "../node_modules/react-native/third-party-podspecs/DoubleConversion.podspec" FBLazyVector: @@ -528,9 +556,14 @@ EXTERNAL SOURCES: SPEC CHECKSUMS: boost: 57d2868c099736d80fcd648bf211b4431e51a558 - DatadogSDK: 46e1a7363bc3130fae151ec4aedf11ea291517c5 - DatadogSDKCrashReporting: 24a0e6ec6db905cdeb174721962a7941b2f8a9d2 - DatadogSDKReactNative: 1cd2c5ca0673e9fc83ad4b44b2c14f90cce9d53c + DatadogCore: 24190ba2cf526577212a9a6dd99e323684a867c1 + DatadogCrashReporting: ace454b37c3e8bb3e343823301dd2bf8f7da2e6f + DatadogInternal: 5b02abb37a3ea80b86b0b02463d305b53f76d8d0 + DatadogLogs: 612176842ed36a796b9dc6c8a28c079faa721d19 + DatadogRUM: 5372a3c69f865a0f98870818144bf0b6c3282136 + DatadogSDKReactNative: 4ba919b617e60dd5ada3e8e053e45797e3b062c4 + DatadogTrace: 61c815e87bd4d2e232cbc03e1c05cb9f61a34834 + DatadogWebViewTracking: b7b0b70263dfdf9abb16fecb654d7ad669cfc5db DoubleConversion: 5189b271737e1565bdce30deb4a08d647e3f5f54 FBLazyVector: ddb55c55295ea51ed98aa7e2e08add2f826309d5 FBReactNativeSpec: 90fc1a90b4b7a171e0a7c20ea426c1bf6ce4399c @@ -576,6 +609,6 @@ SPEC CHECKSUMS: RNScreens: f7ad633b2e0190b77b6a7aab7f914fad6f198d8d Yoga: e7ea9e590e27460d28911403b894722354d73479 -PODFILE CHECKSUM: ffc581c91d71c08d4a9374af21697b3d934fc7cf +PODFILE CHECKSUM: 32a6101a728d3e9718c34a74bebf1924834aef29 COCOAPODS: 1.12.1 diff --git a/packages/core/DatadogSDKReactNative.podspec b/packages/core/DatadogSDKReactNative.podspec index 9b2846f88..f2386589e 100644 --- a/packages/core/DatadogSDKReactNative.podspec +++ b/packages/core/DatadogSDKReactNative.podspec @@ -17,9 +17,13 @@ Pod::Spec.new do |s| s.source_files = "ios/Sources/*.{h,m,mm,swift}" s.dependency "React-Core" - s.dependency 'DatadogSDK', '~> 1.22.0' - s.dependency 'DatadogSDKCrashReporting', '~> 1.22.0' - + s.dependency 'DatadogCore', '~> 2.1.2' + s.dependency 'DatadogLogs', '~> 2.1.2' + s.dependency 'DatadogTrace', '~> 2.1.2' + s.dependency 'DatadogRUM', '~> 2.1.2' + s.dependency 'DatadogCrashReporting', '~> 2.1.2' + s.dependency 'DatadogWebViewTracking', '~> 2.1.2' + s.test_spec 'Tests' do |test_spec| test_spec.source_files = 'ios/Tests/*.swift' end diff --git a/packages/core/ios/Sources/DdLogsImplementation.swift b/packages/core/ios/Sources/DdLogsImplementation.swift index 9cc154813..a567ae863 100644 --- a/packages/core/ios/Sources/DdLogsImplementation.swift +++ b/packages/core/ios/Sources/DdLogsImplementation.swift @@ -5,51 +5,23 @@ */ import Foundation -import Datadog - -extension DDLogger: NativeLogger { - // Adding stubs until they are added to the the LoggerProtocol extension - func debug(_ message: String, errorKind: String?, errorMessage: String?, stackTrace: String?, attributes: [String : Encodable]?) { - log(level: .debug, message: message, errorKind: errorKind, errorMessage: errorMessage, stackTrace: stackTrace, attributes: attributes) - } - func info(_ message: String, errorKind: String?, errorMessage: String?, stackTrace: String?, attributes: [String : Encodable]?) { - log(level: .info, message: message, errorKind: errorKind, errorMessage: errorMessage, stackTrace: stackTrace, attributes: attributes) - } - func warn(_ message: String, errorKind: String?, errorMessage: String?, stackTrace: String?, attributes: [String : Encodable]?) { - log(level: .warn, message: message, errorKind: errorKind, errorMessage: errorMessage, stackTrace: stackTrace, attributes: attributes) - } - func error(_ message: String, errorKind: String?, errorMessage: String?, stackTrace: String?, attributes: [String : Encodable]?) { - log(level: .error, message: message, errorKind: errorKind, errorMessage: errorMessage, stackTrace: stackTrace, attributes: attributes) - } -} -internal protocol NativeLogger { - func debug(_ message: String, error: Error?, attributes: [String: Encodable]?) - func debug(_ message: String, errorKind: String?, errorMessage: String?, stackTrace: String?, attributes: [String: Encodable]?) - func info(_ message: String, error: Error?, attributes: [String: Encodable]?) - func info(_ message: String, errorKind: String?, errorMessage: String?, stackTrace: String?, attributes: [String: Encodable]?) - func warn(_ message: String, error: Error?, attributes: [String: Encodable]?) - func warn(_ message: String, errorKind: String?, errorMessage: String?, stackTrace: String?, attributes: [String: Encodable]?) - func error(_ message: String, error: Error?, attributes: [String: Encodable]?) - func error(_ message: String, errorKind: String?, errorMessage: String?, stackTrace: String?, attributes: [String: Encodable]?) -} +import DatadogLogs +import DatadogCore @objc public class DdLogsImplementation: NSObject { - private lazy var logger: NativeLogger = loggerProvider() - private let loggerProvider: () -> NativeLogger + private lazy var logger: LoggerProtocol = loggerProvider() + private let loggerProvider: () -> LoggerProtocol private let isSDKInitialized: () -> Bool - internal init(_ loggerProvider: @escaping () -> NativeLogger, _ isSDKInitialized: @escaping () -> Bool) { + internal init(_ loggerProvider: @escaping () -> LoggerProtocol, _ isSDKInitialized: @escaping () -> Bool) { self.loggerProvider = loggerProvider self.isSDKInitialized = isSDKInitialized } @objc public override convenience init() { - let builder = Logger.builder - .sendNetworkInfo(true) - .printLogsToConsole(true) - self.init({ builder.build() }, { Datadog.isInitialized }) + self.init({ Logger.create(with: Logger.Configuration(networkInfoEnabled: true, consoleLogFormat: .short)) }, { Datadog.isInitialized() }) } @objc @@ -103,7 +75,7 @@ public class DdLogsImplementation: NSObject { return } let attributes = castAttributesToSwift(context).mergeWithGlobalAttributes() - logger.debug(message, errorKind: errorKind, errorMessage: errorMessage, stackTrace: stacktrace, attributes: attributes) + logger._internal.log(level: .debug, message: message, errorKind: errorKind, errorMessage: errorMessage, stackTrace: stacktrace, attributes: attributes) resolve(nil) } @@ -114,7 +86,7 @@ public class DdLogsImplementation: NSObject { return } let attributes = castAttributesToSwift(context).mergeWithGlobalAttributes() - logger.info(message, errorKind: errorKind, errorMessage: errorMessage, stackTrace: stacktrace, attributes: attributes) + logger._internal.log(level: .info, message: message, errorKind: errorKind, errorMessage: errorMessage, stackTrace: stacktrace, attributes: attributes) resolve(nil) } @@ -125,7 +97,7 @@ public class DdLogsImplementation: NSObject { return } let attributes = castAttributesToSwift(context).mergeWithGlobalAttributes() - logger.warn(message, errorKind: errorKind, errorMessage: errorMessage, stackTrace: stacktrace, attributes: attributes) + logger._internal.log(level: .warn, message: message, errorKind: errorKind, errorMessage: errorMessage, stackTrace: stacktrace, attributes: attributes) resolve(nil) } @@ -136,7 +108,7 @@ public class DdLogsImplementation: NSObject { return } let attributes = castAttributesToSwift(context).mergeWithGlobalAttributes() - logger.error(message, errorKind: errorKind, errorMessage: errorMessage, stackTrace: stacktrace, attributes: attributes) + logger._internal.log(level: .error, message: message, errorKind: errorKind, errorMessage: errorMessage, stackTrace: stacktrace, attributes: attributes) resolve(nil) } } diff --git a/packages/core/ios/Sources/DdRumImplementation.swift b/packages/core/ios/Sources/DdRumImplementation.swift index 46049b80b..3e2d90f14 100644 --- a/packages/core/ios/Sources/DdRumImplementation.swift +++ b/packages/core/ios/Sources/DdRumImplementation.swift @@ -5,34 +5,10 @@ */ import Foundation -import Datadog - -extension DDRUMMonitor: NativeRUM { } -internal protocol NativeRUM { - func startView(key: String, name: String?, attributes: [String: Encodable]) - func stopView(key: String, attributes: [String: Encodable]) - func addError(message: String, type: String?, source: RUMErrorSource, stack: String?, attributes: [String: Encodable], file: StaticString?, line: UInt?) - func startResourceLoading(resourceKey: String, httpMethod: RUMMethod, urlString: String, attributes: [String: Encodable]) - func stopResourceLoading(resourceKey: String, statusCode: Int?, kind: RUMResourceType, size: Int64?, attributes: [String: Encodable]) - func startUserAction(type: RUMUserActionType, name: String, attributes: [String: Encodable]) - func stopUserAction(type: RUMUserActionType, name: String?, attributes: [String: Encodable]) - func addUserAction(type: RUMUserActionType, name: String, attributes: [String: Encodable]) - func addTiming(name: String) - func stopSession() - func addResourceMetrics(resourceKey: String, - fetch: (start: Date, end: Date), - redirection: (start: Date, end: Date)?, - dns: (start: Date, end: Date)?, - connect: (start: Date, end: Date)?, - ssl: (start: Date, end: Date)?, - firstByte: (start: Date, end: Date)?, - download: (start: Date, end: Date)?, - responseSize: Int64?, - attributes: [AttributeKey: AttributeValue]) - func addFeatureFlagEvaluation(name: String, value: Encodable) -} +import DatadogRUM +import DatadogInternal -private extension RUMUserActionType { +private extension RUMActionType { init(from string: String) { switch string.lowercased() { case "tap": self = .tap @@ -101,18 +77,27 @@ public class DdRumImplementation: NSObject { internal static let missingResourceSize = -1 - lazy var nativeRUM: NativeRUM = rumProvider() - private let rumProvider: () -> NativeRUM + lazy var nativeRUM: RUMMonitorProtocol = rumProvider() + lazy var rumInternal: RUMMonitorInternalProtocol? = rumInternalProvider() + private let rumProvider: () -> RUMMonitorProtocol + private let rumInternalProvider: () -> RUMMonitorInternalProtocol? - private typealias UserAction = (type: RUMUserActionType, name: String?) + private typealias UserAction = (type: RUMActionType, name: String?) - internal init(_ rumProvider: @escaping () -> NativeRUM) { + internal init( + _ rumProvider: @escaping () -> RUMMonitorProtocol, + _ rumInternalProvider: @escaping () -> RUMMonitorInternalProtocol? + ) { self.rumProvider = rumProvider + self.rumInternalProvider = rumInternalProvider } @objc public override convenience init() { - self.init { Global.rum } + self.init( + { RUMMonitor.shared() }, + { RUMMonitor.shared()._internal } + ) } @objc @@ -129,25 +114,25 @@ public class DdRumImplementation: NSObject { @objc public func startAction(type: String, name: String, context: NSDictionary, timestampMs: Double, resolve:RCTPromiseResolveBlock, reject:RCTPromiseRejectBlock) -> Void { - nativeRUM.startUserAction(type: RUMUserActionType(from: type), name: name, attributes: attributes(from: context, with: timestampMs)) + nativeRUM.startAction(type: RUMActionType(from: type), name: name, attributes: attributes(from: context, with: timestampMs)) resolve(nil) } @objc public func stopAction(type: String, name: String, context: NSDictionary, timestampMs: Double, resolve:RCTPromiseResolveBlock, reject:RCTPromiseRejectBlock) -> Void { - nativeRUM.stopUserAction(type: RUMUserActionType(from: type), name: name, attributes: attributes(from: context, with: timestampMs)) + nativeRUM.stopAction(type: RUMActionType(from: type), name: name, attributes: attributes(from: context, with: timestampMs)) resolve(nil) } @objc public func addAction(type: String, name: String, context: NSDictionary, timestampMs: Double, resolve:RCTPromiseResolveBlock, reject:RCTPromiseRejectBlock) -> Void { - nativeRUM.addUserAction(type: RUMUserActionType(from: type), name: name, attributes: attributes(from: context, with: timestampMs)) + nativeRUM.addAction(type: RUMActionType(from: type), name: name, attributes: attributes(from: context, with: timestampMs)) resolve(nil) } @objc public func startResource(key: String, method: String, url: String, context: NSDictionary, timestampMs: Double, resolve:RCTPromiseResolveBlock, reject:RCTPromiseRejectBlock) -> Void { - nativeRUM.startResourceLoading(resourceKey: key, httpMethod: RUMMethod(from: method), urlString: url, attributes: attributes(from: context, with: timestampMs)) + nativeRUM.startResource(resourceKey: key, httpMethod: RUMMethod(from: method), urlString: url, attributes: attributes(from: context, with: timestampMs)) resolve(nil) } @@ -160,7 +145,7 @@ public class DdRumImplementation: NSObject { addResourceMetrics(key: key, resourceTimings: resourceTimings) } - nativeRUM.stopResourceLoading( + nativeRUM.stopResource( resourceKey: key, statusCode: Int(statusCode), kind: RUMResourceType(from: kind), @@ -172,7 +157,7 @@ public class DdRumImplementation: NSObject { @objc public func addError(message: String, source: String, stacktrace: String, context: NSDictionary, timestampMs: Double, resolve:RCTPromiseResolveBlock, reject:RCTPromiseRejectBlock) -> Void { - nativeRUM.addError(message: message, type: nil, source: RUMErrorSource(from: source), stack: stacktrace, attributes: attributes(from: context, with: timestampMs), file: nil, line: nil) + nativeRUM.addError(message: message, type: nil, stack: stacktrace, source: RUMErrorSource(from: source), attributes: attributes(from: context, with: timestampMs), file: nil, line: nil) resolve(nil) } @@ -214,8 +199,10 @@ public class DdRumImplementation: NSObject { let firstByte = timingValue(from: resourceTimings, for: Self.firstByteTimingKey) let download = timingValue(from: resourceTimings, for: Self.downloadTimingKey) + if let fetch = fetch { - nativeRUM.addResourceMetrics( + rumInternal?.addResourceMetrics( + at: Date.init(), resourceKey: key, fetch: fetch, redirection: redirect, diff --git a/packages/core/ios/Sources/DdSdkConfiguration.swift b/packages/core/ios/Sources/DdSdkConfiguration.swift index cff287057..975e35cd2 100644 --- a/packages/core/ios/Sources/DdSdkConfiguration.swift +++ b/packages/core/ios/Sources/DdSdkConfiguration.swift @@ -5,6 +5,8 @@ */ import Foundation +import DatadogCore +import DatadogInternal /** A configuration object to initialize Datadog's features. @@ -31,18 +33,18 @@ import Foundation public class DdSdkConfiguration: NSObject { public var clientToken: String = "" public var env: String = "" - public var applicationId: String? = nil + public var applicationId: String = "" public var nativeCrashReportEnabled: Bool? = nil public var nativeLongTaskThresholdMs: Double? = nil public var longTaskThresholdMs: Double = 0.0 public var sampleRate: Double? = nil - public var site: NSString? = nil + public var site: DatadogSite public var trackingConsent: NSString? = nil public var telemetrySampleRate: Double? = nil public var vitalsUpdateFrequency: NSString? = nil public var trackFrustrations: Bool? = nil - public var uploadFrequency: NSString? = nil - public var batchSize: NSString? = nil + public var uploadFrequency: Datadog.Configuration.UploadFrequency + public var batchSize: Datadog.Configuration.BatchSize public var trackBackgroundEvents: Bool? = nil public var additionalConfig: NSDictionary? = nil public var configurationForTelemetry: ConfigurationForTelemetry? = nil @@ -50,7 +52,7 @@ public class DdSdkConfiguration: NSObject { public init( clientToken: String, env: String, - applicationId: String?, + applicationId: String, nativeCrashReportEnabled: Bool?, nativeLongTaskThresholdMs: Double?, longTaskThresholdMs: Double, @@ -73,17 +75,62 @@ public class DdSdkConfiguration: NSObject { self.nativeLongTaskThresholdMs = nativeLongTaskThresholdMs self.longTaskThresholdMs = longTaskThresholdMs self.sampleRate = sampleRate - self.site = site + self.site = DdSdkConfiguration.buildSite(site: site) self.trackingConsent = trackingConsent self.telemetrySampleRate = telemetrySampleRate self.vitalsUpdateFrequency = vitalsUpdateFrequency self.trackFrustrations = trackFrustrations - self.uploadFrequency = uploadFrequency - self.batchSize = batchSize + self.uploadFrequency = DdSdkConfiguration.buildUploadFrequency(uploadFrequency: uploadFrequency) + self.batchSize = DdSdkConfiguration.buildBatchSize(batchSize: batchSize) self.trackBackgroundEvents = trackBackgroundEvents self.additionalConfig = additionalConfig self.configurationForTelemetry = configurationForTelemetry } + + static func buildSite(site: NSString?) -> DatadogSite { + switch site?.lowercased ?? "us" { + case "us1", "us": + return .us1 + case "eu1", "eu": + return .eu1 + case "us3": + return .us3 + case "us5": + return .us5 + case "us1_fed", "gov": + return .us1_fed + case "ap1": + return .ap1 + default: + return .us1 + } + } + + static func buildBatchSize(batchSize: NSString?) -> Datadog.Configuration.BatchSize { + switch batchSize?.lowercased ?? "" { + case "small": + return .small + case "medium": + return .medium + case "large": + return .large + default: + return .medium + } + } + + static func buildUploadFrequency(uploadFrequency: NSString?) -> Datadog.Configuration.UploadFrequency { + switch uploadFrequency?.lowercased ?? "" { + case "rare": + return .rare + case "average": + return .average + case "frequent": + return .frequent + default: + return .average + } + } } public class ConfigurationForTelemetry: NSObject { diff --git a/packages/core/ios/Sources/DdSdkImplementation.swift b/packages/core/ios/Sources/DdSdkImplementation.swift index af20d99b1..0f1a20a8b 100644 --- a/packages/core/ios/Sources/DdSdkImplementation.swift +++ b/packages/core/ios/Sources/DdSdkImplementation.swift @@ -5,8 +5,13 @@ */ import Foundation -import Datadog +import DatadogCore +import DatadogRUM +import DatadogLogs +import DatadogTrace import DatadogCrashReporting +import DatadogWebViewTracking +import DatadogInternal import React func getDefaultAppVersion() -> String { @@ -20,18 +25,34 @@ public class DdSdkImplementation: NSObject { let jsDispatchQueue: DispatchQueueType let jsRefreshRateMonitor: RefreshRateMonitor let mainDispatchQueue: DispatchQueueType + let RUMMonitorProvider: () -> RUMMonitorProtocol + let RUMMonitorInternalProvider: () -> RUMMonitorInternalProtocol? private let jsLongTaskThresholdInSeconds: TimeInterval = 0.1; @objc public convenience init(bridge: RCTBridge) { - self.init(mainDispatchQueue: DispatchQueue.main, jsDispatchQueue: bridge, jsRefreshRateMonitor: JSRefreshRateMonitor.init()) + self.init( + mainDispatchQueue: DispatchQueue.main, + jsDispatchQueue: bridge, + jsRefreshRateMonitor: JSRefreshRateMonitor.init(), + RUMMonitorProvider: { RUMMonitor.shared() }, + RUMMonitorInternalProvider: { RUMMonitor.shared()._internal } + ) } - init(mainDispatchQueue: DispatchQueueType, jsDispatchQueue: DispatchQueueType, jsRefreshRateMonitor: RefreshRateMonitor) { + init( + mainDispatchQueue: DispatchQueueType, + jsDispatchQueue: DispatchQueueType, + jsRefreshRateMonitor: RefreshRateMonitor, + RUMMonitorProvider: @escaping () -> RUMMonitorProtocol, + RUMMonitorInternalProvider: @escaping () -> RUMMonitorInternalProtocol? + ) { self.mainDispatchQueue = mainDispatchQueue self.jsDispatchQueue = jsDispatchQueue self.jsRefreshRateMonitor = jsRefreshRateMonitor + self.RUMMonitorProvider = RUMMonitorProvider + self.RUMMonitorInternalProvider = RUMMonitorInternalProvider super.init() } @@ -42,7 +63,8 @@ public class DdSdkImplementation: NSObject { self.mainDispatchQueue.async { let sdkConfiguration = configuration.asDdSdkConfiguration() - if Datadog.isInitialized { + // TODO: see if this `if` is still needed + if Datadog.isInitialized() { // Initializing the SDK twice results in Global.rum and // Global.sharedTracer to be set to no-op instances consolePrint("Datadog SDK is already initialized, skipping initialization.") @@ -57,13 +79,22 @@ public class DdSdkImplementation: NSObject { } self.setVerbosityLevel(additionalConfig: sdkConfiguration.additionalConfig) - let ddConfig = self.buildConfiguration(configuration: sdkConfiguration) + let sdkConfig = self.buildSDKConfiguration(configuration: sdkConfiguration) let consent = self.buildTrackingConsent(consent: sdkConfiguration.trackingConsent) - Datadog.initialize(appContext: Datadog.AppContext(), trackingConsent: consent, configuration: ddConfig) - self.sendConfigurationAsTelemetry(rnConfiguration: sdkConfiguration) + Datadog.initialize(with: sdkConfig, trackingConsent: consent) - Global.rum = RUMMonitor.initialize() + let rumConfig = self.buildRUMConfiguration(configuration: sdkConfiguration) + RUM.enable(with: rumConfig) + + Logs.enable(with: Logs.Configuration()) + + Trace.enable(with: Trace.Configuration()) + if sdkConfiguration.nativeCrashReportEnabled ?? false { + CrashReporting.enable() + } + + self.sendConfigurationAsTelemetry(rnConfiguration: sdkConfiguration) self.startJSRefreshRateMonitoring(sdkConfiguration: sdkConfiguration) resolve(nil) @@ -74,7 +105,7 @@ public class DdSdkImplementation: NSObject { public func setAttributes(attributes: NSDictionary, resolve:RCTPromiseResolveBlock, reject:RCTPromiseRejectBlock) -> Void { let castedAttributes = castAttributesToSwift(attributes) for (key, value) in castedAttributes { - Global.rum.addAttribute(forKey: key, value: value) + RUMMonitorProvider().addAttribute(forKey: key, value: value) GlobalState.addAttribute(forKey: key, value: value) } @@ -114,7 +145,9 @@ public class DdSdkImplementation: NSObject { @objc public func consumeWebviewEvent(message: NSString, resolve:RCTPromiseResolveBlock, reject:RCTPromiseRejectBlock) -> Void { do{ - try Datadog._internal.webEventBridge.send(message) + // TODO: memoize message emitter once core is initialized + let messageEmitter = WebViewTracking._internal.messageEmitter(in: CoreRegistry.default) + try messageEmitter.send(body: message) } catch { Datadog._internal.telemetry.error(id: "datadog_react_native:\(error.localizedDescription)", message: "The message being sent was:\(message)" as String, kind: "WebViewEventBridgeError" as String, stack: String(describing: error) as String) } @@ -122,138 +155,92 @@ public class DdSdkImplementation: NSObject { } func sendConfigurationAsTelemetry(rnConfiguration: DdSdkConfiguration) -> Void { - Datadog._internal.telemetry.setConfigurationMapper { event in - var event = event - - var configuration = event.telemetry.configuration - configuration.initializationType = rnConfiguration.configurationForTelemetry?.initializationType as? String - configuration.trackErrors = rnConfiguration.configurationForTelemetry?.trackErrors - configuration.trackInteractions = rnConfiguration.configurationForTelemetry?.trackInteractions - configuration.trackResources = rnConfiguration.configurationForTelemetry?.trackNetworkRequests - configuration.trackNetworkRequests = rnConfiguration.configurationForTelemetry?.trackNetworkRequests - configuration.reactVersion = rnConfiguration.configurationForTelemetry?.reactVersion as? String - configuration.reactNativeVersion = rnConfiguration.configurationForTelemetry?.reactNativeVersion as? String - - // trackCrossPlatformLongTasks will be deprecated for trackLongTask - configuration.trackCrossPlatformLongTasks = rnConfiguration.longTaskThresholdMs != 0 - configuration.trackLongTask = rnConfiguration.longTaskThresholdMs != 0 - configuration.trackNativeErrors = rnConfiguration.nativeCrashReportEnabled - configuration.trackNativeLongTasks = rnConfiguration.nativeLongTaskThresholdMs != 0 - event.telemetry.configuration = configuration - - return event - } + // TODO: missing some keys: initializationType, reactVersion, reactNativeVersion, trackNativeErrors + let telemetry = TelemetryCore(core: CoreRegistry.default) + telemetry.configuration( + trackCrossPlatformLongTasks: rnConfiguration.longTaskThresholdMs != 0, + trackErrors: rnConfiguration.configurationForTelemetry?.trackErrors, + trackInteractions: rnConfiguration.configurationForTelemetry?.trackInteractions, + trackLongTask: rnConfiguration.longTaskThresholdMs != 0, + trackNativeLongTasks: rnConfiguration.nativeLongTaskThresholdMs != 0, + trackNetworkRequests: rnConfiguration.configurationForTelemetry?.trackNetworkRequests + ) } - func buildConfiguration(configuration: DdSdkConfiguration, defaultAppVersion: String = getDefaultAppVersion()) -> Datadog.Configuration { - let ddConfigBuilder: Datadog.Configuration.Builder - if let rumAppID = configuration.applicationId { - ddConfigBuilder = Datadog.Configuration.builderUsing( - rumApplicationID: rumAppID, - clientToken: configuration.clientToken, - environment: configuration.env - ) - .set(rumSessionsSamplingRate: Float(configuration.sampleRate ?? 100.0)) - } else { - ddConfigBuilder = Datadog.Configuration.builderUsing( - clientToken: configuration.clientToken, - environment: configuration.env - ) - } - - switch configuration.site?.lowercased ?? "us" { - case "us1", "us": - _ = ddConfigBuilder.set(endpoint: .us1) - case "eu1", "eu": - _ = ddConfigBuilder.set(endpoint: .eu1) - case "us3": - _ = ddConfigBuilder.set(endpoint: .us3) - case "us5": - _ = ddConfigBuilder.set(endpoint: .us5) - case "us1_fed", "gov": - _ = ddConfigBuilder.set(endpoint: .us1_fed) - case "ap1": - _ = ddConfigBuilder.set(endpoint: .ap1) - default: - _ = ddConfigBuilder.set(endpoint: .us1) - } - - _ = ddConfigBuilder.set(mobileVitalsFrequency: buildVitalsUpdateFrequency(frequency: configuration.vitalsUpdateFrequency)) - - _ = ddConfigBuilder.set(uploadFrequency: buildUploadFrequency(frequency: configuration.uploadFrequency)) - - _ = ddConfigBuilder.set(batchSize: buildBatchSize(batchSize: configuration.batchSize)) - - if var telemetrySampleRate = (configuration.telemetrySampleRate as? NSNumber)?.floatValue { - _ = ddConfigBuilder.set(sampleTelemetry: telemetrySampleRate) - } - - if var trackFrustrations = (configuration.trackFrustrations) { - _ = ddConfigBuilder.trackFrustrations(trackFrustrations) - } - - if var trackBackgroundEvents = (configuration.trackBackgroundEvents) { - _ = ddConfigBuilder.trackBackgroundEvents(trackBackgroundEvents) + func buildSDKConfiguration(configuration: DdSdkConfiguration) -> Datadog.Configuration { + // TODO: Add version to config once this is released on iOS + var config = Datadog.Configuration( + clientToken: configuration.clientToken, + env: configuration.env, + site: configuration.site, + service: configuration.additionalConfig?[InternalConfigurationAttributes.serviceName] as? String ?? nil, + batchSize: configuration.batchSize, + uploadFrequency: configuration.uploadFrequency, + proxyConfiguration: buildProxyConfiguration(config: configuration.additionalConfig) + ) + if var additionalConfiguration = configuration.additionalConfig as? [String: Any] { + config._internal_mutation { + $0.additionalConfiguration = additionalConfiguration + } } + return config + } + + func buildRUMConfiguration(configuration: DdSdkConfiguration) -> RUM.Configuration { + var longTaskThreshold: TimeInterval? = nil if let threshold = configuration.nativeLongTaskThresholdMs as? TimeInterval { if (threshold != 0) { // `nativeLongTaskThresholdMs` attribute is in milliseconds - _ = ddConfigBuilder.trackRUMLongTasks(threshold: threshold / 1_000) + longTaskThreshold = threshold / 1_000 } } - - let additionalConfig = configuration.additionalConfig - - if var additionalConfiguration = additionalConfig as? [String: Any] { - if let versionSuffix = additionalConfig?[InternalConfigurationAttributes.versionSuffix] as? String { - let datadogVersion = defaultAppVersion + versionSuffix - additionalConfiguration[CrossPlatformAttributes.version] = datadogVersion - } - - _ = ddConfigBuilder.set(additionalConfiguration: additionalConfiguration) - } - - if let enableViewTracking = additionalConfig?[InternalConfigurationAttributes.nativeViewTracking] as? Bool, enableViewTracking { - _ = ddConfigBuilder.trackUIKitRUMViews() - } - - if let enableInteractionTracking = additionalConfig?[InternalConfigurationAttributes.nativeInteractionTracking] as? Bool, enableInteractionTracking { - _ = ddConfigBuilder.trackUIKitRUMActions() + + var uiKitViewsPredicate: UIKitRUMViewsPredicate? = nil + if let enableViewTracking = configuration.additionalConfig?[InternalConfigurationAttributes.nativeViewTracking] as? Bool, enableViewTracking { + uiKitViewsPredicate = DefaultUIKitRUMViewsPredicate() } - if let serviceName = additionalConfig?[InternalConfigurationAttributes.serviceName] as? String { - _ = ddConfigBuilder.set(serviceName: serviceName) + var uiKitActionsPredicate: UIKitRUMActionsPredicate? = nil + if let enableInteractionTracking = configuration.additionalConfig?[InternalConfigurationAttributes.nativeInteractionTracking] as? Bool, enableInteractionTracking { + uiKitActionsPredicate = DefaultUIKitRUMActionsPredicate() } - - if let firstPartyHosts = additionalConfig?[InternalConfigurationAttributes.firstPartyHosts] as? NSArray { + + var urlSessionTracking: RUM.Configuration.URLSessionTracking? = nil + if let firstPartyHosts = configuration.additionalConfig?[InternalConfigurationAttributes.firstPartyHosts] as? NSArray { // We will always fall under this condition as firstPartyHosts is an empty array by default - _ = ddConfigBuilder.trackURLSession(firstPartyHostsWithHeaderTypes: firstPartyHosts.asFirstPartyHosts()) - } - - if let proxyConfiguration = buildProxyConfiguration(config: additionalConfig) { - _ = ddConfigBuilder.set(proxyConfiguration: proxyConfiguration) - } - - if configuration.nativeCrashReportEnabled ?? false { - _ = ddConfigBuilder.enableCrashReporting(using: DDCrashReportingPlugin()) + urlSessionTracking = RUM.Configuration.URLSessionTracking( + firstPartyHostsTracing: .traceWithHeaders( + hostsWithHeaders: firstPartyHosts.asFirstPartyHosts(), + sampleRate: 100.0 + ) + ) } - - _ = ddConfigBuilder.setRUMResourceEventMapper({ resourceEvent in - if resourceEvent.context?.contextInfo[InternalConfigurationAttributes.dropResource] != nil { - return nil - } - return resourceEvent - }) - - _ = ddConfigBuilder.setRUMActionEventMapper({ actionEvent in - if actionEvent.context?.contextInfo[InternalConfigurationAttributes.dropResource] != nil { - return nil - } - return actionEvent - }) - - return ddConfigBuilder.build() + + return RUM.Configuration( + applicationID: configuration.applicationId, + sessionSampleRate: (configuration.sampleRate as? NSNumber)?.floatValue ?? 100.0, + uiKitViewsPredicate: uiKitViewsPredicate, + uiKitActionsPredicate: uiKitActionsPredicate, + urlSessionTracking: urlSessionTracking, + trackFrustrations: configuration.trackFrustrations ?? true, + trackBackgroundEvents: configuration.trackBackgroundEvents ?? false, + longTaskThreshold: longTaskThreshold, + vitalsUpdateFrequency: buildVitalsUpdateFrequency(frequency: configuration.vitalsUpdateFrequency), + resourceEventMapper: { resourceEvent in + if resourceEvent.context?.contextInfo[InternalConfigurationAttributes.dropResource] != nil { + return nil + } + return resourceEvent + }, + actionEventMapper: { actionEvent in + if actionEvent.context?.contextInfo[InternalConfigurationAttributes.dropResource] != nil { + return nil + } + return actionEvent + }, + telemetrySampleRate: (configuration.telemetrySampleRate as? NSNumber)?.floatValue ?? 20.0 + ) } func buildProxyConfiguration(config: NSDictionary?) -> [AnyHashable: Any]? { @@ -311,21 +298,19 @@ public class DdSdkImplementation: NSObject { return trackingConsent } - func buildVitalsUpdateFrequency(frequency: NSString?) -> Datadog.Configuration.VitalsFrequency { - let vitalsFrequency: Datadog.Configuration.VitalsFrequency + func buildVitalsUpdateFrequency(frequency: NSString?) -> RUM.Configuration.VitalsFrequency? { switch frequency?.lowercased { case "never": - vitalsFrequency = .never + return nil case "rare": - vitalsFrequency = .rare + return .rare case "average": - vitalsFrequency = .average + return .average case "frequent": - vitalsFrequency = .frequent + return .frequent default: - vitalsFrequency = .average + return .average } - return vitalsFrequency } func buildUploadFrequency(frequency: NSString?) -> Datadog.Configuration.UploadFrequency { @@ -363,8 +348,9 @@ public class DdSdkImplementation: NSObject { switch verbosityLevel?.lowercased { case "debug": Datadog.verbosityLevel = .debug + // TODO: deprecate info in js and android case "info": - Datadog.verbosityLevel = .info + Datadog.verbosityLevel = .debug case "warn": Datadog.verbosityLevel = .warn case "error": @@ -382,7 +368,7 @@ public class DdSdkImplementation: NSObject { } func buildFrameTimeCallback(sdkConfiguration: DdSdkConfiguration)-> ((Double) -> ())? { - let jsRefreshRateMonitoringEnabled = buildVitalsUpdateFrequency(frequency: sdkConfiguration.vitalsUpdateFrequency) != .never + let jsRefreshRateMonitoringEnabled = buildVitalsUpdateFrequency(frequency: sdkConfiguration.vitalsUpdateFrequency) != nil let jsLongTaskMonitoringEnabled = sdkConfiguration.longTaskThresholdMs != 0 if (!jsRefreshRateMonitoringEnabled && !jsLongTaskMonitoringEnabled) { @@ -391,10 +377,10 @@ public class DdSdkImplementation: NSObject { func frameTimeCallback(frameTime: Double) { if (jsRefreshRateMonitoringEnabled && frameTime > 0) { - Global.rum._internal.updatePerformanceMetric(at: Date(), metric: .jsFrameTimeSeconds, value: frameTime) + RUMMonitorInternalProvider()?.updatePerformanceMetric(at: Date(), metric: .jsFrameTimeSeconds, value: frameTime, attributes: [:]) } if (jsLongTaskMonitoringEnabled && frameTime > sdkConfiguration.longTaskThresholdMs / 1_000) { - Global.rum._internal.addLongTask(at: Date(), duration: frameTime, attributes: ["long_task.target": "javascript"]) + RUMMonitorInternalProvider()?.addLongTask(at: Date(), duration: frameTime, attributes: ["long_task.target": "javascript"]) } } diff --git a/packages/core/ios/Sources/DdTraceImplementation.swift b/packages/core/ios/Sources/DdTraceImplementation.swift index f6a2d2886..01762c61f 100644 --- a/packages/core/ios/Sources/DdTraceImplementation.swift +++ b/packages/core/ios/Sources/DdTraceImplementation.swift @@ -5,7 +5,7 @@ */ import Foundation -import Datadog +import DatadogTrace @objc public class DdTraceImplementation: NSObject { @@ -19,7 +19,7 @@ public class DdTraceImplementation: NSObject { @objc public override convenience init() { - self.init { Tracer.initialize(configuration: Tracer.Configuration()) } + self.init { Tracer.shared() } } @objc diff --git a/packages/core/ios/Sources/RNDdSdkConfiguration.swift b/packages/core/ios/Sources/RNDdSdkConfiguration.swift index cb813fda0..c0ff3080c 100644 --- a/packages/core/ios/Sources/RNDdSdkConfiguration.swift +++ b/packages/core/ios/Sources/RNDdSdkConfiguration.swift @@ -4,7 +4,9 @@ * Copyright 2016-Present Datadog, Inc. */ -import Datadog +import DatadogCore +import DatadogRUM +import DatadogInternal import Foundation extension NSDictionary { @@ -30,7 +32,7 @@ extension NSDictionary { return DdSdkConfiguration( clientToken: (clientToken != nil) ? clientToken! : String(), env: (env != nil) ? env! : String(), - applicationId: applicationId, + applicationId: (applicationId != nil) ? applicationId! : String(), nativeCrashReportEnabled: nativeCrashReportEnabled, nativeLongTaskThresholdMs: nativeLongTaskThresholdMs, longTaskThresholdMs: (longTaskThresholdMs != nil) ? longTaskThresholdMs! : Double(), diff --git a/packages/core/ios/Sources/RUMMonitorInternalProtocol.swift b/packages/core/ios/Sources/RUMMonitorInternalProtocol.swift new file mode 100644 index 000000000..5eb91b174 --- /dev/null +++ b/packages/core/ios/Sources/RUMMonitorInternalProtocol.swift @@ -0,0 +1,40 @@ + +/* + * Unless explicitly stated otherwise all files in this repository are licensed under the Apache License Version 2.0. + * This product includes software developed at Datadog (https://www.datadoghq.com/). + * Copyright 2019-2020 Datadog, Inc. + */ + +import DatadogRUM +import DatadogInternal + +public protocol RUMMonitorInternalProtocol { + func addLongTask( + at time: Date, + duration: TimeInterval, + attributes: [AttributeKey: AttributeValue] + ) + + func updatePerformanceMetric( + at time: Date, + metric: PerformanceMetric, + value: Double, + attributes: [AttributeKey: AttributeValue] + ) + + func addResourceMetrics( + at time: Date, + resourceKey: String, + fetch: (start: Date, end: Date), + redirection: (start: Date, end: Date)?, + dns: (start: Date, end: Date)?, + connect: (start: Date, end: Date)?, + ssl: (start: Date, end: Date)?, + firstByte: (start: Date, end: Date)?, + download: (start: Date, end: Date)?, + responseSize: Int64?, + attributes: [AttributeKey: AttributeValue] + ) +} + +extension DatadogInternalInterface: RUMMonitorInternalProtocol {} diff --git a/packages/core/ios/Tests/DdLogsTests.swift b/packages/core/ios/Tests/DdLogsTests.swift index 67c1e3971..35a81ded6 100644 --- a/packages/core/ios/Tests/DdLogsTests.swift +++ b/packages/core/ios/Tests/DdLogsTests.swift @@ -6,6 +6,8 @@ import XCTest @testable import DatadogSDKReactNative +import DatadogLogs +import DatadogInternal func mockResolve(args: Any?) {} func mockReject(args: String?, arg: String?, err: Error?) {} @@ -374,7 +376,34 @@ internal class DdLogsTests: XCTestCase { } } -private class MockNativeLogger: NativeLogger { +private class MockNativeLogger: LoggerProtocol { + init () { + + } + + func log(level: DatadogLogs.LogLevel, message: String, error: Error?, attributes: [String : Encodable]?) { + receivedMethodCalls.append(MethodCall( + kind: MockNativeLogger.MethodCall.Kind(from: level), + message: message, + errorKind: nil, + errorMessage: nil, + stackTrace: nil, + attributes: attributes + )) + } + + func addAttribute(forKey key: DatadogInternal.AttributeKey, value: DatadogInternal.AttributeValue) {} + + func removeAttribute(forKey key: DatadogInternal.AttributeKey) {} + + func addTag(withKey key: String, value: String) {} + + func removeTag(withKey key: String) {} + + func add(tag: String) {} + + func remove(tag: String) {} + struct MethodCall { enum Kind { case debug @@ -389,30 +418,52 @@ private class MockNativeLogger: NativeLogger { let stackTrace: String? let attributes: [String: Encodable]? } + private(set) var receivedMethodCalls = [MethodCall]() func debug(_ message: String, error: Error?, attributes: [String: Encodable]?) { receivedMethodCalls.append(MethodCall(kind: .debug, message: message, errorKind: nil, errorMessage: nil, stackTrace: nil, attributes: attributes)) } - func debug(_ message: String, errorKind: String?, errorMessage: String?, stackTrace: String?, attributes: [String: Encodable]?) { - receivedMethodCalls.append(MethodCall(kind: .debug, message: message, errorKind: errorKind, errorMessage: errorMessage, stackTrace: stackTrace, attributes: attributes)) - } func info(_ message: String, error: Error?, attributes: [String: Encodable]?) { receivedMethodCalls.append(MethodCall(kind: .info, message: message, errorKind: nil, errorMessage: nil, stackTrace: nil, attributes: attributes)) } - func info(_ message: String, errorKind: String?, errorMessage: String?, stackTrace: String?, attributes: [String: Encodable]?) { - receivedMethodCalls.append(MethodCall(kind: .info, message: message, errorKind: errorKind, errorMessage: errorMessage, stackTrace: stackTrace, attributes: attributes)) - } func warn(_ message: String, error: Error?, attributes: [String: Encodable]?) { receivedMethodCalls.append(MethodCall(kind: .warn, message: message, errorKind: nil, errorMessage: nil, stackTrace: nil, attributes: attributes)) } - func warn(_ message: String, errorKind: String?, errorMessage: String?, stackTrace: String?, attributes: [String: Encodable]?) { - receivedMethodCalls.append(MethodCall(kind: .warn, message: message, errorKind: errorKind, errorMessage: errorMessage, stackTrace: stackTrace, attributes: attributes)) - } func error(_ message: String, error: Error?, attributes: [String: Encodable]?) { receivedMethodCalls.append(MethodCall(kind: .error, message: message, errorKind: nil, errorMessage: nil, stackTrace: nil, attributes: attributes)) } - func error(_ message: String, errorKind: String?, errorMessage: String?, stackTrace: String?, attributes: [String: Encodable]?) { - receivedMethodCalls.append(MethodCall(kind: .error, message: message, errorKind: errorKind, errorMessage: errorMessage, stackTrace: stackTrace, attributes: attributes)) +} + +extension MockNativeLogger: InternalLoggerProtocol { + func log(level: DatadogLogs.LogLevel, message: String, errorKind: String?, errorMessage: String?, stackTrace: String?, attributes: [String : Encodable]?) { + receivedMethodCalls.append(MethodCall( + kind: MockNativeLogger.MethodCall.Kind(from: level), + message: message, + errorKind: errorKind, + errorMessage: errorMessage, + stackTrace: stackTrace, + attributes: attributes + )) + } +} + +extension MockNativeLogger.MethodCall.Kind { + init (from level: DatadogLogs.LogLevel) { + switch level { + case .debug: + self = .debug + case .info: + self = .info + case .warn: + self = .warn + case .error: + self = .error + // unsupported cases + case .notice: + self = .debug + case .critical: + self = .debug + } } } diff --git a/packages/core/ios/Tests/DdRumTests.swift b/packages/core/ios/Tests/DdRumTests.swift index d10e41f31..45f7417bf 100644 --- a/packages/core/ios/Tests/DdRumTests.swift +++ b/packages/core/ios/Tests/DdRumTests.swift @@ -5,11 +5,13 @@ */ import XCTest +@testable import DatadogCore +@testable import DatadogRUM @testable import DatadogSDKReactNative -@testable import Datadog +@testable import DatadogInternal internal class DdRumTests: XCTestCase { - private let mockNativeRUM = MockNativeRUM() + private let mockNativeRUM = MockRUMMonitor() private var rum: DdRumImplementation! // swiftlint:disable:this implicitly_unwrapped_optional private func mockResolve(args: Any?) {} @@ -19,17 +21,17 @@ internal class DdRumTests: XCTestCase { override func setUpWithError() throws { try super.setUpWithError() - rum = DdRumImplementation { self.mockNativeRUM } + rum = DdRumImplementation({ self.mockNativeRUM }, { self.mockNativeRUM._internalMock }) } func testItInitializesNativeRumOnlyOnce() { // Given let expectation = self.expectation(description: "Initialize RUM once") - let rum = DdRumImplementation { [unowned self] in + let rum = DdRumImplementation({ [unowned self] in expectation.fulfill() return self.mockNativeRUM - } + }, { nil }) // When (0..<10).forEach { _ in rum.addTiming(name: "foo", resolve: mockResolve, reject: mockReject) } @@ -189,31 +191,31 @@ internal class DdRumTests: XCTestCase { mockNativeRUM.calledMethods.first, .addResourceMetrics( resourceKey: "resource key", - fetch: MockNativeRUM.Interval( + fetch: MockRUMMonitor.Interval( start: nanoTimeToDate(timestampNs: 0), end: nanoTimeToDate(timestampNs: 13) ), - redirection: MockNativeRUM.Interval( + redirection: MockRUMMonitor.Interval( start: nanoTimeToDate(timestampNs: 1), end: nanoTimeToDate(timestampNs: 2) ), - dns: MockNativeRUM.Interval( + dns: MockRUMMonitor.Interval( start: nanoTimeToDate(timestampNs: 3), end: nanoTimeToDate(timestampNs: 4) ), - connect: MockNativeRUM.Interval( + connect: MockRUMMonitor.Interval( start: nanoTimeToDate(timestampNs: 5), end: nanoTimeToDate(timestampNs: 6) ), - ssl: MockNativeRUM.Interval( + ssl: MockRUMMonitor.Interval( start: nanoTimeToDate(timestampNs: 7), end: nanoTimeToDate(timestampNs: 8) ), - firstByte: MockNativeRUM.Interval( + firstByte: MockRUMMonitor.Interval( start: nanoTimeToDate(timestampNs: 9), end: nanoTimeToDate(timestampNs: 10) ), - download: MockNativeRUM.Interval( + download: MockRUMMonitor.Interval( start: nanoTimeToDate(timestampNs: 11), end: nanoTimeToDate(timestampNs: 12) ), @@ -265,121 +267,14 @@ internal class DdRumTests: XCTestCase { } func testRumErrorSourceMapping() throws { - XCTAssertEqual(RUMErrorSource(from: "source"), RUMErrorSource.source) - XCTAssertEqual(RUMErrorSource(from: "network"), RUMErrorSource.network) - XCTAssertEqual(RUMErrorSource(from: "webview"), RUMErrorSource.webview) - XCTAssertEqual(RUMErrorSource(from: "console"), RUMErrorSource.console) - XCTAssertEqual(RUMErrorSource(from: "foobar"), RUMErrorSource.custom) +// XCTAssertEqual(RUMErrorSource(from: "source"), RUMErrorSource.source) +// XCTAssertEqual(RUMErrorSource(from: "network"), RUMErrorSource.network) +// XCTAssertEqual(RUMErrorSource(from: "webview"), RUMErrorSource.webview) +// XCTAssertEqual(RUMErrorSource(from: "console"), RUMErrorSource.console) +// XCTAssertEqual(RUMErrorSource(from: "foobar"), RUMErrorSource.custom) } private func nanoTimeToDate(timestampNs: Int64) -> Date { return Date(timeIntervalSince1970: TimeInterval(fromNs: timestampNs)) } } - -private class MockNativeRUM: NativeRUM { - struct Interval: Equatable { - let start: Date? - let end: Date? - } - - enum CalledMethod: Equatable { - case startView(key: String, name: String?) - case stopView(key: String) - case addError(message: String, source: RUMErrorSource, stack: String?) - case startResourceLoading(resourceKey: String, httpMethod: RUMMethod, urlString: String) - case stopResourceLoading(resourceKey: String, statusCode: Int, kind: RUMResourceType, size: Int64?) - case startUserAction(type: RUMUserActionType, name: String) - case stopUserAction(type: RUMUserActionType, name: String?) - case addUserAction(type: RUMUserActionType, name: String) - case addTiming(name: String) - case stopSession(_: Int? = nil) // We need an attribute for the case to be Equatable - case addResourceMetrics(resourceKey: String, - fetch: Interval, - redirection: Interval, - dns: Interval, - connect: Interval, - ssl: Interval, - firstByte: Interval, - download: Interval, - responseSize: Int64?) - } - - private(set) var calledMethods = [CalledMethod]() - private(set) var receivedAttributes = [[String: Encodable]]() - private(set) var receivedFeatureFlags = [String: Encodable]() - - // swiftlint:disable force_cast - func startView(key: String, name: String?, attributes: [String: Encodable]) { - calledMethods.append(.startView(key: key, name: name)) - receivedAttributes.append(attributes) - } - - func stopView(key: String, attributes: [String: Encodable]) { - calledMethods.append(.stopView(key: key)) - receivedAttributes.append(attributes) - } - - func addError(message: String, type: String?, source: RUMErrorSource, stack: String?, attributes: [String: Encodable], file: StaticString?, line: UInt?) { - calledMethods.append(.addError(message: message, source: source, stack: stack)) - receivedAttributes.append(attributes) - } - - func startResourceLoading(resourceKey: String, httpMethod: RUMMethod, urlString: String, attributes: [String: Encodable]) { - calledMethods.append(.startResourceLoading(resourceKey: resourceKey, httpMethod: httpMethod, urlString: urlString)) - receivedAttributes.append(attributes) - } - func stopResourceLoading(resourceKey: String, statusCode: Int?, kind: RUMResourceType, size: Int64?, attributes: [String: Encodable]) { - calledMethods.append(.stopResourceLoading(resourceKey: resourceKey, statusCode: statusCode ?? 0, kind: kind, size: size)) - receivedAttributes.append(attributes) - } - func startUserAction(type: RUMUserActionType, name: String, attributes: [String: Encodable]) { - calledMethods.append(.startUserAction(type: type, name: name)) - receivedAttributes.append(attributes) - } - func stopUserAction(type: RUMUserActionType, name: String?, attributes: [String: Encodable]) { - calledMethods.append(.stopUserAction(type: type, name: name)) - receivedAttributes.append(attributes) - } - func addUserAction(type: RUMUserActionType, name: String, attributes: [String: Encodable]) { - calledMethods.append(.addUserAction(type: type, name: name)) - receivedAttributes.append(attributes) - } - func addTiming(name: String) { - calledMethods.append(.addTiming(name: name)) - } - func stopSession() { - calledMethods.append(.stopSession()) - } - func addFeatureFlagEvaluation(name: String, value: Encodable) { - receivedFeatureFlags[name] = value - } - func addResourceMetrics( - resourceKey: String, - fetch: (start: Date, end: Date), - redirection: (start: Date, end: Date)?, - dns: (start: Date, end: Date)?, - connect: (start: Date, end: Date)?, - ssl: (start: Date, end: Date)?, - firstByte: (start: Date, end: Date)?, - download: (start: Date, end: Date)?, - responseSize: Int64?, - attributes: [AttributeKey: AttributeValue] - ) { - calledMethods.append( - .addResourceMetrics( - resourceKey: resourceKey, - fetch: Interval(start: fetch.start, end: fetch.end), - redirection: Interval(start: redirection?.start, end: redirection?.end), - dns: Interval(start: dns?.start, end: dns?.end), - connect: Interval(start: connect?.start, end: connect?.end), - ssl: Interval(start: ssl?.start, end: ssl?.end), - firstByte: Interval(start: firstByte?.start, end: firstByte?.end), - download: Interval(start: download?.start, end: download?.end), - responseSize: responseSize - ) - ) - receivedAttributes.append(attributes) - } - // swiftlint:enable force_cast -} diff --git a/packages/core/ios/Tests/DdSdkTests.swift b/packages/core/ios/Tests/DdSdkTests.swift index 81ca6c286..0600a0ea4 100644 --- a/packages/core/ios/Tests/DdSdkTests.swift +++ b/packages/core/ios/Tests/DdSdkTests.swift @@ -6,7 +6,10 @@ import XCTest @testable import DatadogSDKReactNative -@testable import Datadog +@testable import DatadogCore +@testable import DatadogRUM +@testable import DatadogInternal +import DatadogLogs final class DispatchQueueMock: DispatchQueueType { func async(execute work: @escaping @convention(block) () -> Void) { @@ -32,11 +35,23 @@ internal class DdSdkTests: XCTestCase { var printedMessage = "" consolePrint = { msg in printedMessage += msg } - DdSdkImplementation(mainDispatchQueue: DispatchQueueMock(), jsDispatchQueue: DispatchQueueMock(), jsRefreshRateMonitor: JSRefreshRateMonitor()).initialize(configuration: .mockAny(), resolve: mockResolve, reject: mockReject) + DdSdkImplementation( + mainDispatchQueue: DispatchQueueMock(), + jsDispatchQueue: DispatchQueueMock(), + jsRefreshRateMonitor: JSRefreshRateMonitor(), + RUMMonitorProvider: { MockRUMMonitor() }, + RUMMonitorInternalProvider: { nil } + ).initialize(configuration: .mockAny(), resolve: mockResolve, reject: mockReject) XCTAssertEqual(printedMessage, "") - DdSdkImplementation(mainDispatchQueue: DispatchQueueMock(), jsDispatchQueue: DispatchQueueMock(), jsRefreshRateMonitor: JSRefreshRateMonitor()).initialize(configuration: .mockAny(), resolve: mockResolve, reject: mockReject) + DdSdkImplementation( + mainDispatchQueue: DispatchQueueMock(), + jsDispatchQueue: DispatchQueueMock(), + jsRefreshRateMonitor: JSRefreshRateMonitor(), + RUMMonitorProvider: { MockRUMMonitor() }, + RUMMonitorInternalProvider: { nil } + ).initialize(configuration: .mockAny(), resolve: mockResolve, reject: mockReject) XCTAssertEqual(printedMessage, "Datadog SDK is already initialized, skipping initialization.") @@ -46,57 +61,63 @@ internal class DdSdkTests: XCTestCase { func testBuildConfigurationNoUIKitViewsByDefault() { let configuration: DdSdkConfiguration = .mockAny() - let ddConfig = DdSdkImplementation().buildConfiguration(configuration: configuration) + let ddConfig = DdSdkImplementation().buildRUMConfiguration(configuration: configuration) - XCTAssertNil(ddConfig.rumUIKitViewsPredicate) + XCTAssertNil(ddConfig.uiKitViewsPredicate) } func testBuildConfigurationUIKitViewsTrackingDisabled() { let configuration: DdSdkConfiguration = .mockAny(additionalConfig: ["_dd.native_view_tracking": false]) - let ddConfig = DdSdkImplementation().buildConfiguration(configuration: configuration) + let ddConfig = DdSdkImplementation().buildRUMConfiguration(configuration: configuration) - XCTAssertNil(ddConfig.rumUIKitViewsPredicate) + XCTAssertNil(ddConfig.uiKitViewsPredicate) } func testBuildConfigurationUIKitViewsTrackingEnabled() { let configuration: DdSdkConfiguration = .mockAny(additionalConfig: ["_dd.native_view_tracking": true]) - let ddConfig = DdSdkImplementation().buildConfiguration(configuration: configuration) + let ddConfig = DdSdkImplementation().buildRUMConfiguration(configuration: configuration) - XCTAssertNotNil(ddConfig.rumUIKitViewsPredicate) + XCTAssertNotNil(ddConfig.uiKitViewsPredicate) } func testBuildConfigurationNoUIKitUserActionsByDefault() { let configuration: DdSdkConfiguration = .mockAny() - let ddConfig = DdSdkImplementation().buildConfiguration(configuration: configuration) + let ddConfig = DdSdkImplementation().buildRUMConfiguration(configuration: configuration) - XCTAssertNil(ddConfig.rumUIKitUserActionsPredicate) + XCTAssertNil(ddConfig.uiKitActionsPredicate) } func testBuildConfigurationUIKitUserActionsTrackingDisabled() { let configuration: DdSdkConfiguration = .mockAny(additionalConfig: ["_dd.native_interaction_tracking": false]) - let ddConfig = DdSdkImplementation().buildConfiguration(configuration: configuration) + let ddConfig = DdSdkImplementation().buildRUMConfiguration(configuration: configuration) - XCTAssertNil(ddConfig.rumUIKitUserActionsPredicate) + XCTAssertNil(ddConfig.uiKitActionsPredicate) } func testBuildConfigurationUIKitUserActionsTrackingEnabled() { let configuration: DdSdkConfiguration = .mockAny(additionalConfig: ["_dd.native_interaction_tracking": true]) - let ddConfig = DdSdkImplementation().buildConfiguration(configuration: configuration) + let ddConfig = DdSdkImplementation().buildRUMConfiguration(configuration: configuration) - XCTAssertNotNil(ddConfig.rumUIKitUserActionsPredicate) + XCTAssertNotNil(ddConfig.uiKitActionsPredicate) } func testSDKInitializationWithVerbosityDebug() { let validConfiguration: NSDictionary = .mockAny(additionalConfig: ["_dd.sdk_verbosity": "debug"]) - DdSdkImplementation(mainDispatchQueue: DispatchQueueMock(), jsDispatchQueue: DispatchQueueMock(), jsRefreshRateMonitor: JSRefreshRateMonitor()).initialize(configuration: validConfiguration, resolve: mockResolve, reject: mockReject) + DdSdkImplementation( + mainDispatchQueue: DispatchQueueMock(), + jsDispatchQueue: DispatchQueueMock(), + jsRefreshRateMonitor: JSRefreshRateMonitor(), + RUMMonitorProvider: { MockRUMMonitor() }, + RUMMonitorInternalProvider: { nil } + ).initialize(configuration: validConfiguration, resolve: mockResolve, reject: mockReject) - XCTAssertEqual(Datadog.verbosityLevel, LogLevel.debug) + XCTAssertEqual(Datadog.verbosityLevel, CoreLoggerLevel.debug) Datadog.internalFlushAndDeinitialize() } @@ -104,9 +125,15 @@ internal class DdSdkTests: XCTestCase { func testSDKInitializationWithVerbosityInfo() { let validConfiguration: NSDictionary = .mockAny(additionalConfig: ["_dd.sdk_verbosity": "info"]) - DdSdkImplementation(mainDispatchQueue: DispatchQueueMock(), jsDispatchQueue: DispatchQueueMock(), jsRefreshRateMonitor: JSRefreshRateMonitor()).initialize(configuration: validConfiguration, resolve: mockResolve, reject: mockReject) + DdSdkImplementation( + mainDispatchQueue: DispatchQueueMock(), + jsDispatchQueue: DispatchQueueMock(), + jsRefreshRateMonitor: JSRefreshRateMonitor(), + RUMMonitorProvider: { MockRUMMonitor() }, + RUMMonitorInternalProvider: { nil } + ).initialize(configuration: validConfiguration, resolve: mockResolve, reject: mockReject) - XCTAssertEqual(Datadog.verbosityLevel, LogLevel.info) + XCTAssertEqual(Datadog.verbosityLevel, CoreLoggerLevel.debug) Datadog.internalFlushAndDeinitialize() } @@ -114,9 +141,15 @@ internal class DdSdkTests: XCTestCase { func testSDKInitializationWithVerbosityWarn() { let validConfiguration: NSDictionary = .mockAny(additionalConfig: ["_dd.sdk_verbosity": "warn"]) - DdSdkImplementation(mainDispatchQueue: DispatchQueueMock(), jsDispatchQueue: DispatchQueueMock(), jsRefreshRateMonitor: JSRefreshRateMonitor()).initialize(configuration: validConfiguration, resolve: mockResolve, reject: mockReject) + DdSdkImplementation( + mainDispatchQueue: DispatchQueueMock(), + jsDispatchQueue: DispatchQueueMock(), + jsRefreshRateMonitor: JSRefreshRateMonitor(), + RUMMonitorProvider: { MockRUMMonitor() }, + RUMMonitorInternalProvider: { nil } + ).initialize(configuration: validConfiguration, resolve: mockResolve, reject: mockReject) - XCTAssertEqual(Datadog.verbosityLevel, LogLevel.warn) + XCTAssertEqual(Datadog.verbosityLevel, CoreLoggerLevel.warn) Datadog.internalFlushAndDeinitialize() } @@ -124,9 +157,15 @@ internal class DdSdkTests: XCTestCase { func testSDKInitializationWithVerbosityError() { let validConfiguration: NSDictionary = .mockAny(additionalConfig: ["_dd.sdk_verbosity": "error"]) - DdSdkImplementation(mainDispatchQueue: DispatchQueueMock(), jsDispatchQueue: DispatchQueueMock(), jsRefreshRateMonitor: JSRefreshRateMonitor()).initialize(configuration: validConfiguration, resolve: mockResolve, reject: mockReject) + DdSdkImplementation( + mainDispatchQueue: DispatchQueueMock(), + jsDispatchQueue: DispatchQueueMock(), + jsRefreshRateMonitor: JSRefreshRateMonitor(), + RUMMonitorProvider: { MockRUMMonitor() }, + RUMMonitorInternalProvider: { nil } + ).initialize(configuration: validConfiguration, resolve: mockResolve, reject: mockReject) - XCTAssertEqual(Datadog.verbosityLevel, LogLevel.error) + XCTAssertEqual(Datadog.verbosityLevel, CoreLoggerLevel.error) Datadog.internalFlushAndDeinitialize() } @@ -134,7 +173,13 @@ internal class DdSdkTests: XCTestCase { func testSDKInitializationWithVerbosityNil() { let validConfiguration: NSDictionary = .mockAny(additionalConfig: nil) - DdSdkImplementation(mainDispatchQueue: DispatchQueueMock(), jsDispatchQueue: DispatchQueueMock(), jsRefreshRateMonitor: JSRefreshRateMonitor()).initialize(configuration: validConfiguration, resolve: mockResolve, reject: mockReject) + DdSdkImplementation( + mainDispatchQueue: DispatchQueueMock(), + jsDispatchQueue: DispatchQueueMock(), + jsRefreshRateMonitor: JSRefreshRateMonitor(), + RUMMonitorProvider: { MockRUMMonitor() }, + RUMMonitorInternalProvider: { nil } + ).initialize(configuration: validConfiguration, resolve: mockResolve, reject: mockReject) XCTAssertNil(Datadog.verbosityLevel) @@ -144,7 +189,13 @@ internal class DdSdkTests: XCTestCase { func testSDKInitializationWithVerbosityUnknown() { let validConfiguration: NSDictionary = .mockAny(additionalConfig: ["_dd.sdk_verbosity": "foo"]) - DdSdkImplementation(mainDispatchQueue: DispatchQueueMock(), jsDispatchQueue: DispatchQueueMock(), jsRefreshRateMonitor: JSRefreshRateMonitor()).initialize(configuration: validConfiguration, resolve: mockResolve, reject: mockReject) + DdSdkImplementation( + mainDispatchQueue: DispatchQueueMock(), + jsDispatchQueue: DispatchQueueMock(), + jsRefreshRateMonitor: JSRefreshRateMonitor(), + RUMMonitorProvider: { MockRUMMonitor() }, + RUMMonitorInternalProvider: { nil } + ).initialize(configuration: validConfiguration, resolve: mockResolve, reject: mockReject) XCTAssertNil(Datadog.verbosityLevel) @@ -154,87 +205,87 @@ internal class DdSdkTests: XCTestCase { func testBuildConfigurationDefaultEndpoint() { let configuration: DdSdkConfiguration = .mockAny() - let ddConfig = DdSdkImplementation().buildConfiguration(configuration: configuration) + let ddConfig = DdSdkImplementation().buildSDKConfiguration(configuration: configuration) - XCTAssertEqual(ddConfig.datadogEndpoint, .us1) + XCTAssertEqual(ddConfig.site, .us1) } func testBuildConfigurationUSEndpoint() { let configuration: DdSdkConfiguration = .mockAny(site: "US") - let ddConfig = DdSdkImplementation().buildConfiguration(configuration: configuration) + let ddConfig = DdSdkImplementation().buildSDKConfiguration(configuration: configuration) - XCTAssertEqual(ddConfig.datadogEndpoint, .us1) + XCTAssertEqual(ddConfig.site, .us1) } func testBuildConfigurationUS1Endpoint() { let configuration: DdSdkConfiguration = .mockAny(site: "US1") - let ddConfig = DdSdkImplementation().buildConfiguration(configuration: configuration) + let ddConfig = DdSdkImplementation().buildSDKConfiguration(configuration: configuration) - XCTAssertEqual(ddConfig.datadogEndpoint, .us1) + XCTAssertEqual(ddConfig.site, .us1) } func testBuildConfigurationUS3Endpoint() { let configuration: DdSdkConfiguration = .mockAny(site: "US3") - let ddConfig = DdSdkImplementation().buildConfiguration(configuration: configuration) + let ddConfig = DdSdkImplementation().buildSDKConfiguration(configuration: configuration) - XCTAssertEqual(ddConfig.datadogEndpoint, .us3) + XCTAssertEqual(ddConfig.site, .us3) } func testBuildConfigurationUS5Endpoint() { let configuration: DdSdkConfiguration = .mockAny(site: "US5") - let ddConfig = DdSdkImplementation().buildConfiguration(configuration: configuration) + let ddConfig = DdSdkImplementation().buildSDKConfiguration(configuration: configuration) - XCTAssertEqual(ddConfig.datadogEndpoint, .us5) + XCTAssertEqual(ddConfig.site, .us5) } func testBuildConfigurationUS1FEDEndpoint() { let configuration: DdSdkConfiguration = .mockAny(site: "US1_FED") - let ddConfig = DdSdkImplementation().buildConfiguration(configuration: configuration) + let ddConfig = DdSdkImplementation().buildSDKConfiguration(configuration: configuration) - XCTAssertEqual(ddConfig.datadogEndpoint, .us1_fed) + XCTAssertEqual(ddConfig.site, .us1_fed) } func testBuildConfigurationGOVEndpoint() { let configuration: DdSdkConfiguration = .mockAny(site: "GOV") - let ddConfig = DdSdkImplementation().buildConfiguration(configuration: configuration) + let ddConfig = DdSdkImplementation().buildSDKConfiguration(configuration: configuration) - XCTAssertEqual(ddConfig.datadogEndpoint, .us1_fed) + XCTAssertEqual(ddConfig.site, .us1_fed) } func testBuildConfigurationEUEndpoint() { let configuration: DdSdkConfiguration = .mockAny(site: "EU") - let ddConfig = DdSdkImplementation().buildConfiguration(configuration: configuration) + let ddConfig = DdSdkImplementation().buildSDKConfiguration(configuration: configuration) - XCTAssertEqual(ddConfig.datadogEndpoint, .eu1) + XCTAssertEqual(ddConfig.site, .eu1) } func testBuildConfigurationEU1Endpoint() { let configuration: DdSdkConfiguration = .mockAny(site: "EU1") - let ddConfig = DdSdkImplementation().buildConfiguration(configuration: configuration) + let ddConfig = DdSdkImplementation().buildSDKConfiguration(configuration: configuration) - XCTAssertEqual(ddConfig.datadogEndpoint, .eu1) + XCTAssertEqual(ddConfig.site, .eu1) } func testBuildConfigurationAP1Endpoint() { let configuration: DdSdkConfiguration = .mockAny(site: "AP1") - let ddConfig = DdSdkImplementation().buildConfiguration(configuration: configuration) + let ddConfig = DdSdkImplementation().buildSDKConfiguration(configuration: configuration) - XCTAssertEqual(ddConfig.datadogEndpoint, .ap1) + XCTAssertEqual(ddConfig.site, .ap1) } func testBuildConfigurationAdditionalConfig() { let configuration: DdSdkConfiguration = .mockAny(additionalConfig: ["foo": "test", "bar": 42]) - let ddConfig = DdSdkImplementation().buildConfiguration(configuration: configuration) + let ddConfig = DdSdkImplementation().buildSDKConfiguration(configuration: configuration) // swiftlint:disable force_cast XCTAssertEqual(ddConfig.additionalConfiguration["foo"] as! String, "test") @@ -245,79 +296,89 @@ internal class DdSdkTests: XCTestCase { func testBuildConfigurationWithNilServiceNameByDefault() { let configuration: DdSdkConfiguration = .mockAny() - let ddConfig = DdSdkImplementation().buildConfiguration(configuration: configuration) + let ddConfig = DdSdkImplementation().buildSDKConfiguration(configuration: configuration) - XCTAssertNil(ddConfig.serviceName) + XCTAssertNil(ddConfig.service) } func testBuildConfigurationWithServiceName() { let configuration: DdSdkConfiguration = .mockAny(additionalConfig: ["_dd.service_name": "com.example.app"]) - let ddConfig = DdSdkImplementation().buildConfiguration(configuration: configuration) + let ddConfig = DdSdkImplementation().buildSDKConfiguration(configuration: configuration) - XCTAssertEqual(ddConfig.serviceName, "com.example.app") + XCTAssertEqual(ddConfig.service, "com.example.app") } func testBuildConfigurationNoCrashReportByDefault() { - let configuration: DdSdkConfiguration = .mockAny(nativeCrashReportEnabled: nil) - - let ddConfig = DdSdkImplementation().buildConfiguration(configuration: configuration) - - XCTAssertNil(ddConfig.crashReportingPlugin) + // TODO: rewrite this test +// let configuration: DdSdkConfiguration = .mockAny(nativeCrashReportEnabled: nil) +// +// let ddConfig = DdSdkImplementation().buildSDKConfiguration(configuration: configuration) +// +// XCTAssertNil(ddConfig.crashReportingPlugin) } func testBuildConfigurationNoCrashReport() { - let configuration: DdSdkConfiguration = .mockAny(nativeCrashReportEnabled: false) - - let ddConfig = DdSdkImplementation().buildConfiguration(configuration: configuration) - - XCTAssertNil(ddConfig.crashReportingPlugin) + // TODO: rewrite this test +// let configuration: DdSdkConfiguration = .mockAny(nativeCrashReportEnabled: false) +// +// let ddConfig = DdSdkImplementation().buildSDKConfiguration(configuration: configuration) +// +// XCTAssertNil(ddConfig.crashReportingPlugin) } func testBuildConfigurationWithCrashReport() { - let configuration: DdSdkConfiguration = .mockAny( - nativeCrashReportEnabled: true - ) - - let ddConfig = DdSdkImplementation().buildConfiguration(configuration: configuration) - - XCTAssertNotNil(ddConfig.crashReportingPlugin) + // TODO: rewrite this test +// let configuration: DdSdkConfiguration = .mockAny( +// nativeCrashReportEnabled: true +// ) +// +// let ddConfig = DdSdkImplementation().buildSDKConfiguration(configuration: configuration) +// +// XCTAssertNotNil(ddConfig.crashReportingPlugin) } func testBuildConfigurationWithVersionSuffix() { - let configuration: DdSdkConfiguration = .mockAny(additionalConfig: ["_dd.version_suffix": ":codepush-3"]) - - let ddConfig = DdSdkImplementation().buildConfiguration(configuration: configuration, defaultAppVersion: "1.2.3") - - XCTAssertEqual(ddConfig.additionalConfiguration["_dd.version"] as! String, "1.2.3:codepush-3") + // TODO: Re-enable this test when function is supported +// let configuration: DdSdkConfiguration = .mockAny(additionalConfig: ["_dd.version_suffix": ":codepush-3"]) +// +// let ddConfig = DdSdkImplementation().buildRUMConfiguration(configuration: configuration, defaultAppVersion: "1.2.3") +// +// XCTAssertEqual(ddConfig.additionalConfiguration["_dd.version"] as! String, "1.2.3:codepush-3") } func testBuildConfigurationFrustrationTrackingEnabledByDefault() { let configuration: DdSdkConfiguration = .mockAny() - let ddConfig = DdSdkImplementation().buildConfiguration(configuration: configuration) + let ddConfig = DdSdkImplementation().buildRUMConfiguration(configuration: configuration) - XCTAssertEqual(ddConfig.rumFrustrationSignalsTrackingEnabled, true) + XCTAssertEqual(ddConfig.trackFrustrations, true) } func testBuildConfigurationFrustrationTrackingEnabledExplicitly() { let configuration: DdSdkConfiguration = .mockAny(trackFrustrations: true) - let ddConfig = DdSdkImplementation().buildConfiguration(configuration: configuration) + let ddConfig = DdSdkImplementation().buildRUMConfiguration(configuration: configuration) - XCTAssertEqual(ddConfig.rumFrustrationSignalsTrackingEnabled, true) + XCTAssertEqual(ddConfig.trackFrustrations, true) } func testBuildConfigurationFrustrationTrackingDisabled() { let configuration: DdSdkConfiguration = .mockAny(trackFrustrations: false) - let ddConfig = DdSdkImplementation().buildConfiguration(configuration: configuration) + let ddConfig = DdSdkImplementation().buildRUMConfiguration(configuration: configuration) - XCTAssertEqual(ddConfig.rumFrustrationSignalsTrackingEnabled, false) + XCTAssertEqual(ddConfig.trackFrustrations, false) } func testSettingUserInfo() throws { - let bridge = DdSdkImplementation(mainDispatchQueue: DispatchQueueMock(), jsDispatchQueue: DispatchQueueMock(), jsRefreshRateMonitor: JSRefreshRateMonitor()) + let bridge = DdSdkImplementation( + mainDispatchQueue: DispatchQueueMock(), + jsDispatchQueue: DispatchQueueMock(), + jsRefreshRateMonitor: JSRefreshRateMonitor(), + RUMMonitorProvider: { MockRUMMonitor() }, + RUMMonitorInternalProvider: { nil } + ) bridge.initialize(configuration: .mockAny(), resolve: mockResolve, reject: mockReject) bridge.setUser( @@ -335,23 +396,29 @@ internal class DdSdkTests: XCTestCase { reject: mockReject ) - let receivedUserInfo = try XCTUnwrap(defaultDatadogCore as? DatadogCore).userInfoProvider.value - XCTAssertEqual(receivedUserInfo.id, "abc-123") - XCTAssertEqual(receivedUserInfo.name, "John Doe") - XCTAssertEqual(receivedUserInfo.email, "john@doe.com") - XCTAssertEqual(receivedUserInfo.extraInfo["extra-info-1"] as? Int64, 123) - XCTAssertEqual(receivedUserInfo.extraInfo["extra-info-2"] as? String, "abc") - XCTAssertEqual(receivedUserInfo.extraInfo["extra-info-3"] as? Bool, true) + let ddContext = try XCTUnwrap(CoreRegistry.default as? DatadogCore).contextProvider.read() + let userInfo = try XCTUnwrap(ddContext.userInfo) + + XCTAssertEqual(userInfo.id, "abc-123") + XCTAssertEqual(userInfo.name, "John Doe") + XCTAssertEqual(userInfo.email, "john@doe.com") + XCTAssertEqual(userInfo.extraInfo["extra-info-1"] as? Int64, 123) + XCTAssertEqual(userInfo.extraInfo["extra-info-2"] as? String, "abc") + XCTAssertEqual(userInfo.extraInfo["extra-info-3"] as? Bool, true) Datadog.internalFlushAndDeinitialize() } func testSettingAttributes() { - let bridge = DdSdkImplementation(mainDispatchQueue: DispatchQueueMock(), jsDispatchQueue: DispatchQueueMock(), jsRefreshRateMonitor: JSRefreshRateMonitor()) - bridge.initialize(configuration: .mockAny(), resolve: mockResolve, reject: mockReject) - let rumMonitorMock = MockRUMMonitor() - Global.rum = rumMonitorMock + let bridge = DdSdkImplementation( + mainDispatchQueue: DispatchQueueMock(), + jsDispatchQueue: DispatchQueueMock(), + jsRefreshRateMonitor: JSRefreshRateMonitor(), + RUMMonitorProvider: { rumMonitorMock }, + RUMMonitorInternalProvider: { nil } + ) + bridge.initialize(configuration: .mockAny(), resolve: mockResolve, reject: mockReject) bridge.setAttributes( attributes: NSDictionary( @@ -365,9 +432,9 @@ internal class DdSdkTests: XCTestCase { reject: mockReject ) - XCTAssertEqual(rumMonitorMock.receivedAttributes["attribute-1"] as? Int64, 123) - XCTAssertEqual(rumMonitorMock.receivedAttributes["attribute-2"] as? String, "abc") - XCTAssertEqual(rumMonitorMock.receivedAttributes["attribute-3"] as? Bool, true) + XCTAssertEqual(rumMonitorMock.addedAttributes["attribute-1"] as? Int64, 123) + XCTAssertEqual(rumMonitorMock.addedAttributes["attribute-2"] as? String, "abc") + XCTAssertEqual(rumMonitorMock.addedAttributes["attribute-3"] as? Bool, true) XCTAssertEqual(GlobalState.globalAttributes["attribute-1"] as? Int64, 123) XCTAssertEqual(GlobalState.globalAttributes["attribute-2"] as? String, "abc") @@ -408,17 +475,17 @@ internal class DdSdkTests: XCTestCase { func testBuildLongTaskThreshold() { let configuration: DdSdkConfiguration = .mockAny(nativeLongTaskThresholdMs: 2_500) - let ddConfig = DdSdkImplementation().buildConfiguration(configuration: configuration) + let ddConfig = DdSdkImplementation().buildRUMConfiguration(configuration: configuration) - XCTAssertEqual(ddConfig.rumLongTaskDurationThreshold, 2.5) + XCTAssertEqual(ddConfig.longTaskThreshold, 2.5) } func testBuildNoLongTaskTracking() { let configuration: DdSdkConfiguration = .mockAny(nativeLongTaskThresholdMs: 0) - let ddConfig = DdSdkImplementation().buildConfiguration(configuration: configuration) + let ddConfig = DdSdkImplementation().buildRUMConfiguration(configuration: configuration) - XCTAssertEqual(ddConfig.rumLongTaskDurationThreshold, nil) + XCTAssertEqual(ddConfig.longTaskThreshold, nil) } func testBuildFirstPartyHosts() { @@ -427,12 +494,13 @@ internal class DdSdkTests: XCTestCase { ["match": "datadog.com", "propagatorTypes": ["b3multi", "tracecontext"]] ]]) - let ddConfig = DdSdkImplementation().buildConfiguration(configuration: configuration) + let ddConfig = DdSdkImplementation().buildRUMConfiguration(configuration: configuration) var firstPartyHosts: FirstPartyHosts? = FirstPartyHosts(["example.com": [.datadog, .b3]]) firstPartyHosts += FirstPartyHosts(["datadog.com": [.b3multi, .tracecontext]]) - XCTAssertEqual(ddConfig.firstPartyHosts, firstPartyHosts) + // TODO: rewrite this test +// XCTAssertEqual(ddConfig.urlSessionTracking?.firstPartyHostsTracing, firstPartyHosts!) } func testBuildMalformedFirstPartyHosts() { @@ -440,11 +508,12 @@ internal class DdSdkTests: XCTestCase { ["match": "example.com", "propagatorTypes": ["badPropagatorType", "b3"]], ]]) - let ddConfig = DdSdkImplementation().buildConfiguration(configuration: configuration) + let ddConfig = DdSdkImplementation().buildRUMConfiguration(configuration: configuration) let firstPartyHosts: FirstPartyHosts? = FirstPartyHosts(["example.com": [.b3]]) - XCTAssertEqual(ddConfig.firstPartyHosts, firstPartyHosts) + // TODO: rewrite this test +// XCTAssertEqual(ddConfig.firstPartyHosts, firstPartyHosts) } func testBuildFirstPartyHostsWithDuplicatedMatchKey() { @@ -453,19 +522,20 @@ internal class DdSdkTests: XCTestCase { ["match": "example.com", "propagatorTypes": ["tracecontext"]], ]]) - let ddConfig = DdSdkImplementation().buildConfiguration(configuration: configuration) + let ddConfig = DdSdkImplementation().buildRUMConfiguration(configuration: configuration) var firstPartyHosts: FirstPartyHosts? = FirstPartyHosts(["example.com": [.b3, .tracecontext]]) - XCTAssertEqual(ddConfig.firstPartyHosts, firstPartyHosts) + // TODO: rewrite this test +// XCTAssertEqual(ddConfig.firstPartyHosts, firstPartyHosts) } func testBuildTelemetrySampleRate() { let configuration: DdSdkConfiguration = .mockAny(telemetrySampleRate: 42.0) - let ddConfig = DdSdkImplementation().buildConfiguration(configuration: configuration) + let ddConfig = DdSdkImplementation().buildRUMConfiguration(configuration: configuration) - XCTAssertEqual(ddConfig.rumTelemetrySamplingRate, 42.0) + XCTAssertEqual(ddConfig.telemetrySampleRate, 42.0) } func testBuildProxyConfiguration() { @@ -521,7 +591,7 @@ internal class DdSdkTests: XCTestCase { ] ) - let ddConfig = DdSdkImplementation().buildConfiguration(configuration: configuration) + let ddConfig = DdSdkImplementation().buildSDKConfiguration(configuration: configuration) XCTAssertEqual(ddConfig.proxyConfiguration?["HTTPProxy"] as? String, "host") XCTAssertEqual(ddConfig.proxyConfiguration?["HTTPPort"] as? NSNumber, 99) @@ -532,23 +602,23 @@ internal class DdSdkTests: XCTestCase { func testBuildConfigurationAverageVitalsUpdateFrequency() { let configuration: DdSdkConfiguration = .mockAny(vitalsUpdateFrequency: "average") - let ddConfig = DdSdkImplementation().buildConfiguration(configuration: configuration) + let ddConfig = DdSdkImplementation().buildRUMConfiguration(configuration: configuration) - XCTAssertEqual(ddConfig.mobileVitalsFrequency, .average) + XCTAssertEqual(ddConfig.vitalsUpdateFrequency, .average) } func testBuildConfigurationNeverVitalsUpdateFrequency() { let configuration: DdSdkConfiguration = .mockAny(vitalsUpdateFrequency: "never") - let ddConfig = DdSdkImplementation().buildConfiguration(configuration: configuration) + let ddConfig = DdSdkImplementation().buildRUMConfiguration(configuration: configuration) - XCTAssertEqual(ddConfig.mobileVitalsFrequency, .never) + XCTAssertEqual(ddConfig.vitalsUpdateFrequency, nil) } func testBuildConfigurationAverageUploadFrequency() { let configuration: DdSdkConfiguration = .mockAny(uploadFrequency: "AVERAGE") - let ddConfig = DdSdkImplementation().buildConfiguration(configuration: configuration) + let ddConfig = DdSdkImplementation().buildSDKConfiguration(configuration: configuration) XCTAssertEqual(ddConfig.uploadFrequency, .average) } @@ -556,7 +626,7 @@ internal class DdSdkTests: XCTestCase { func testBuildConfigurationFrequentUploadFrequency() { let configuration: DdSdkConfiguration = .mockAny(uploadFrequency: "FREQUENT") - let ddConfig = DdSdkImplementation().buildConfiguration(configuration: configuration) + let ddConfig = DdSdkImplementation().buildSDKConfiguration(configuration: configuration) XCTAssertEqual(ddConfig.uploadFrequency, .frequent) } @@ -564,7 +634,7 @@ internal class DdSdkTests: XCTestCase { func testBuildConfigurationRareUploadFrequency() { let configuration: DdSdkConfiguration = .mockAny(uploadFrequency: "RARE") - let ddConfig = DdSdkImplementation().buildConfiguration(configuration: configuration) + let ddConfig = DdSdkImplementation().buildSDKConfiguration(configuration: configuration) XCTAssertEqual(ddConfig.uploadFrequency, .rare) } @@ -572,7 +642,7 @@ internal class DdSdkTests: XCTestCase { func testBuildConfigurationMediumBatchSize() { let configuration: DdSdkConfiguration = .mockAny(batchSize: "MEDIUM") - let ddConfig = DdSdkImplementation().buildConfiguration(configuration: configuration) + let ddConfig = DdSdkImplementation().buildSDKConfiguration(configuration: configuration) XCTAssertEqual(ddConfig.batchSize, .medium) } @@ -580,7 +650,7 @@ internal class DdSdkTests: XCTestCase { func testBuildConfigurationLargeBatchSize() { let configuration: DdSdkConfiguration = .mockAny(batchSize: "LARGE") - let ddConfig = DdSdkImplementation().buildConfiguration(configuration: configuration) + let ddConfig = DdSdkImplementation().buildSDKConfiguration(configuration: configuration) XCTAssertEqual(ddConfig.batchSize, .large) } @@ -588,7 +658,7 @@ internal class DdSdkTests: XCTestCase { func testBuildConfigurationSmallBatchSize() { let configuration: DdSdkConfiguration = .mockAny(batchSize: "SMALL") - let ddConfig = DdSdkImplementation().buildConfiguration(configuration: configuration) + let ddConfig = DdSdkImplementation().buildSDKConfiguration(configuration: configuration) XCTAssertEqual(ddConfig.batchSize, .small) } @@ -597,8 +667,13 @@ internal class DdSdkTests: XCTestCase { let mockRefreshRateMonitor = MockJSRefreshRateMonitor() let rumMonitorMock = MockRUMMonitor() - DdSdkImplementation(mainDispatchQueue: DispatchQueueMock(), jsDispatchQueue: DispatchQueueMock(), jsRefreshRateMonitor: mockRefreshRateMonitor).initialize(configuration: .mockAny(longTaskThresholdMs: 0.0), resolve: mockResolve, reject: mockReject) - Global.rum = rumMonitorMock + DdSdkImplementation( + mainDispatchQueue: DispatchQueueMock(), + jsDispatchQueue: DispatchQueueMock(), + jsRefreshRateMonitor: mockRefreshRateMonitor, + RUMMonitorProvider: { rumMonitorMock }, + RUMMonitorInternalProvider: { rumMonitorMock._internalMock } + ).initialize(configuration: .mockAny(longTaskThresholdMs: 0.0), resolve: mockResolve, reject: mockReject) XCTAssertTrue(mockRefreshRateMonitor.isStarted) @@ -613,8 +688,13 @@ internal class DdSdkTests: XCTestCase { let mockRefreshRateMonitor = MockJSRefreshRateMonitor() let rumMonitorMock = MockRUMMonitor() - DdSdkImplementation(mainDispatchQueue: DispatchQueueMock(), jsDispatchQueue: DispatchQueueMock(), jsRefreshRateMonitor: mockRefreshRateMonitor).initialize(configuration: .mockAny(longTaskThresholdMs: 0.0, vitalsUpdateFrequency: "never"), resolve: mockResolve, reject: mockReject) - Global.rum = rumMonitorMock + DdSdkImplementation( + mainDispatchQueue: DispatchQueueMock(), + jsDispatchQueue: DispatchQueueMock(), + jsRefreshRateMonitor: mockRefreshRateMonitor, + RUMMonitorProvider: { rumMonitorMock }, + RUMMonitorInternalProvider: { rumMonitorMock._internalMock } + ).initialize(configuration: .mockAny(longTaskThresholdMs: 0.0, vitalsUpdateFrequency: "never"), resolve: mockResolve, reject: mockReject) XCTAssertFalse(mockRefreshRateMonitor.isStarted) @@ -629,8 +709,13 @@ internal class DdSdkTests: XCTestCase { let mockRefreshRateMonitor = MockJSRefreshRateMonitor() let rumMonitorMock = MockRUMMonitor() - DdSdkImplementation(mainDispatchQueue: DispatchQueueMock(), jsDispatchQueue: DispatchQueueMock(), jsRefreshRateMonitor: mockRefreshRateMonitor).initialize(configuration: .mockAny(longTaskThresholdMs: 0.2, vitalsUpdateFrequency: "never"), resolve: mockResolve, reject: mockReject) - Global.rum = rumMonitorMock + DdSdkImplementation( + mainDispatchQueue: DispatchQueueMock(), + jsDispatchQueue: DispatchQueueMock(), + jsRefreshRateMonitor: mockRefreshRateMonitor, + RUMMonitorProvider: { rumMonitorMock }, + RUMMonitorInternalProvider: { rumMonitorMock._internalMock } + ).initialize(configuration: .mockAny(longTaskThresholdMs: 0.2, vitalsUpdateFrequency: "never"), resolve: mockResolve, reject: mockReject) XCTAssertTrue(mockRefreshRateMonitor.isStarted) @@ -646,8 +731,13 @@ internal class DdSdkTests: XCTestCase { let mockRefreshRateMonitor = MockJSRefreshRateMonitor() let rumMonitorMock = MockRUMMonitor() - DdSdkImplementation(mainDispatchQueue: DispatchQueueMock(), jsDispatchQueue: DispatchQueueMock(), jsRefreshRateMonitor: mockRefreshRateMonitor).initialize(configuration: .mockAny(longTaskThresholdMs: 200, vitalsUpdateFrequency: "average"), resolve: mockResolve, reject: mockReject) - Global.rum = rumMonitorMock + DdSdkImplementation( + mainDispatchQueue: DispatchQueueMock(), + jsDispatchQueue: DispatchQueueMock(), + jsRefreshRateMonitor: mockRefreshRateMonitor, + RUMMonitorProvider: { rumMonitorMock }, + RUMMonitorInternalProvider: { rumMonitorMock._internalMock } + ).initialize(configuration: .mockAny(longTaskThresholdMs: 200, vitalsUpdateFrequency: "average"), resolve: mockResolve, reject: mockReject) XCTAssertTrue(mockRefreshRateMonitor.isStarted) @@ -665,108 +755,109 @@ internal class DdSdkTests: XCTestCase { func testBackgroundTrackingEnabled() { let configuration: DdSdkConfiguration = .mockAny(trackBackgroundEvents: true) - let ddConfig = DdSdkImplementation().buildConfiguration(configuration: configuration) + let ddConfig = DdSdkImplementation().buildRUMConfiguration(configuration: configuration) - XCTAssertEqual(ddConfig.rumBackgroundEventTrackingEnabled, true) + XCTAssertEqual(ddConfig.trackBackgroundEvents, true) } func testBackgroundTrackingDisabled() { let configuration: DdSdkConfiguration = .mockAny(trackBackgroundEvents: false) - let ddConfig = DdSdkImplementation().buildConfiguration(configuration: configuration) + let ddConfig = DdSdkImplementation().buildRUMConfiguration(configuration: configuration) - XCTAssertEqual(ddConfig.rumBackgroundEventTrackingEnabled, false) + XCTAssertEqual(ddConfig.trackBackgroundEvents, false) } func testBackgroundTrackingUndefined() { let configuration: DdSdkConfiguration = .mockAny(trackBackgroundEvents: nil) - let ddConfig = DdSdkImplementation().buildConfiguration(configuration: configuration) + let ddConfig = DdSdkImplementation().buildRUMConfiguration(configuration: configuration) - XCTAssertEqual(ddConfig.rumBackgroundEventTrackingEnabled, false) + XCTAssertEqual(ddConfig.trackBackgroundEvents, false) } func testConfigurationTelemetryEventMapper() throws { - DdSdkImplementation( - mainDispatchQueue: DispatchQueueMock(), - jsDispatchQueue: DispatchQueueMock(), - jsRefreshRateMonitor: JSRefreshRateMonitor()) - .initialize( - configuration: .mockAny( - nativeCrashReportEnabled: false, - nativeLongTaskThresholdMs: 0.0, - longTaskThresholdMs: 0.1, - configurationForTelemetry: ["initializationType": "LEGACY", "trackErrors": true, "trackInteractions": true, "trackNetworkRequests": true, "reactVersion": "18.2.0", "reactNativeVersion": "0.71.0"] - ), - resolve: mockResolve, - reject: mockReject - ) - - - guard let configurationEventMapper = try XCTUnwrap(DD.telemetry as? RUMTelemetry).configurationEventMapper else { return } - - let mappedEvent = configurationEventMapper( - TelemetryConfigurationEvent( - dd: TelemetryConfigurationEvent.DD(), - action: nil, - application: nil, - date: Int64(), - experimentalFeatures: nil, - service: "mockService", - session: nil, - source: .reactNative, - telemetry: TelemetryConfigurationEvent.Telemetry( - configuration: TelemetryConfigurationEvent.Telemetry.Configuration( - actionNameAttribute: nil, - batchSize: nil, - batchUploadFrequency: nil, - forwardConsoleLogs: nil, - forwardErrorsToLogs: nil, - forwardReports: nil, - premiumSampleRate: nil, - replaySampleRate: nil, - selectedTracingPropagators: nil, - sessionSampleRate: nil, - silentMultipleInit: nil, - telemetryConfigurationSampleRate: nil, - telemetrySampleRate: nil, - traceSampleRate: nil, - trackSessionAcrossSubdomains: nil, - useAllowedTracingOrigins: nil, - useAllowedTracingUrls: nil, - useBeforeSend: nil, - useCrossSiteSessionCookie: nil, - useExcludedActivityUrls: nil, - useLocalEncryption: nil, - useSecureSessionCookie: nil, - useTracing: nil, - viewTrackingStrategy: nil - ) - ), - version: "1.0.0", - view: nil - ) - ) - - XCTAssertEqual(mappedEvent.telemetry.configuration.initializationType, "LEGACY") - XCTAssertEqual(mappedEvent.telemetry.configuration.trackErrors, true) - XCTAssertEqual(mappedEvent.telemetry.configuration.trackInteractions, true) - XCTAssertEqual(mappedEvent.telemetry.configuration.trackNetworkRequests, true) - XCTAssertEqual(mappedEvent.telemetry.configuration.trackNativeErrors, false) - XCTAssertEqual(mappedEvent.telemetry.configuration.trackNativeLongTasks, false) - XCTAssertEqual(mappedEvent.telemetry.configuration.trackLongTask, true) - XCTAssertEqual(mappedEvent.telemetry.configuration.reactVersion, "18.2.0") - XCTAssertEqual(mappedEvent.telemetry.configuration.reactNativeVersion, "0.71.0") - - Datadog.internalFlushAndDeinitialize() + //TODO: rewrite this test +// DdSdkImplementation( +// mainDispatchQueue: DispatchQueueMock(), +// jsDispatchQueue: DispatchQueueMock(), +// jsRefreshRateMonitor: JSRefreshRateMonitor()) +// .initialize( +// configuration: .mockAny( +// nativeCrashReportEnabled: false, +// nativeLongTaskThresholdMs: 0.0, +// longTaskThresholdMs: 0.1, +// configurationForTelemetry: ["initializationType": "LEGACY", "trackErrors": true, "trackInteractions": true, "trackNetworkRequests": true, "reactVersion": "18.2.0", "reactNativeVersion": "0.71.0"] +// ), +// resolve: mockResolve, +// reject: mockReject +// ) +// +// +// guard let configurationEventMapper = try XCTUnwrap(DD.telemetry as? RUMTelemetry).configurationEventMapper else { return } +// +// let mappedEvent = configurationEventMapper( +// TelemetryConfigurationEvent( +// dd: TelemetryConfigurationEvent.DD(), +// action: nil, +// application: nil, +// date: Int64(), +// experimentalFeatures: nil, +// service: "mockService", +// session: nil, +// source: .reactNative, +// telemetry: TelemetryConfigurationEvent.Telemetry( +// configuration: TelemetryConfigurationEvent.Telemetry.Configuration( +// actionNameAttribute: nil, +// batchSize: nil, +// batchUploadFrequency: nil, +// forwardConsoleLogs: nil, +// forwardErrorsToLogs: nil, +// forwardReports: nil, +// premiumSampleRate: nil, +// replaySampleRate: nil, +// selectedTracingPropagators: nil, +// sessionSampleRate: nil, +// silentMultipleInit: nil, +// telemetryConfigurationSampleRate: nil, +// telemetrySampleRate: nil, +// traceSampleRate: nil, +// trackSessionAcrossSubdomains: nil, +// useAllowedTracingOrigins: nil, +// useAllowedTracingUrls: nil, +// useBeforeSend: nil, +// useCrossSiteSessionCookie: nil, +// useExcludedActivityUrls: nil, +// useLocalEncryption: nil, +// useSecureSessionCookie: nil, +// useTracing: nil, +// viewTrackingStrategy: nil +// ) +// ), +// version: "1.0.0", +// view: nil +// ) +// ) +// +// XCTAssertEqual(mappedEvent.telemetry.configuration.initializationType, "LEGACY") +// XCTAssertEqual(mappedEvent.telemetry.configuration.trackErrors, true) +// XCTAssertEqual(mappedEvent.telemetry.configuration.trackInteractions, true) +// XCTAssertEqual(mappedEvent.telemetry.configuration.trackNetworkRequests, true) +// XCTAssertEqual(mappedEvent.telemetry.configuration.trackNativeErrors, false) +// XCTAssertEqual(mappedEvent.telemetry.configuration.trackNativeLongTasks, false) +// XCTAssertEqual(mappedEvent.telemetry.configuration.trackLongTask, true) +// XCTAssertEqual(mappedEvent.telemetry.configuration.reactVersion, "18.2.0") +// XCTAssertEqual(mappedEvent.telemetry.configuration.reactNativeVersion, "0.71.0") +// +// Datadog.internalFlushAndDeinitialize() } func testDropsResourceMarkedAsDropped() throws { let configuration: DdSdkConfiguration = .mockAny() - let ddConfig = DdSdkImplementation().buildConfiguration(configuration: configuration) + let ddConfig = DdSdkImplementation().buildRUMConfiguration(configuration: configuration) - let resourceEventMapper = try XCTUnwrap(ddConfig.rumResourceEventMapper) + let resourceEventMapper = try XCTUnwrap(ddConfig.resourceEventMapper) let mockDroppedResourceEvent = RUMResourceEvent.mockRandomDropped() let mappedDroppedEvent = resourceEventMapper(mockDroppedResourceEvent) @@ -780,9 +871,9 @@ internal class DdSdkTests: XCTestCase { func testDropsActionMarkedAsDropped() throws { let configuration: DdSdkConfiguration = .mockAny() - let ddConfig = DdSdkImplementation().buildConfiguration(configuration: configuration) + let ddConfig = DdSdkImplementation().buildRUMConfiguration(configuration: configuration) - let actionEventMapper = try XCTUnwrap(ddConfig.rumActionEventMapper) + let actionEventMapper = try XCTUnwrap(ddConfig.actionEventMapper) let mockDroppedActionEvent = RUMActionEvent.mockRandomDropped() let mappedDroppedEvent = actionEventMapper(mockDroppedActionEvent) @@ -797,7 +888,13 @@ internal class DdSdkTests: XCTestCase { let bridge = DispatchQueueMock() let mockJSRefreshRateMonitor = MockJSRefreshRateMonitor() - DdSdkImplementation(mainDispatchQueue: DispatchQueueMock(), jsDispatchQueue: bridge, jsRefreshRateMonitor: mockJSRefreshRateMonitor).initialize(configuration: .mockAny(longTaskThresholdMs: 0.2), resolve: mockResolve, reject: mockReject) + DdSdkImplementation( + mainDispatchQueue: DispatchQueueMock(), + jsDispatchQueue: bridge, + jsRefreshRateMonitor: mockJSRefreshRateMonitor, + RUMMonitorProvider: { MockRUMMonitor() }, + RUMMonitorInternalProvider: { nil } + ).initialize(configuration: .mockAny(longTaskThresholdMs: 0.2), resolve: mockResolve, reject: mockReject) XCTAssertTrue(bridge.isSameQueue(queue: mockJSRefreshRateMonitor.jsQueue!)) @@ -805,26 +902,6 @@ internal class DdSdkTests: XCTestCase { } } -private class MockRUMMonitor: DDRUMMonitor, RUMCommandSubscriber { - private(set) var receivedAttributes = [AttributeKey: AttributeValue]() - private(set) var lastReceivedPerformanceMetrics = [PerformanceMetric: Double]() - private(set) var receivedLongTasks = [Date: TimeInterval]() - - override func addAttribute(forKey key: AttributeKey, value: AttributeValue) { - receivedAttributes[key] = value - } - - func process(command: RUMCommand) { - if (command is RUMAddLongTaskCommand) { - receivedLongTasks[(command as! RUMAddLongTaskCommand).time] = (command as! RUMAddLongTaskCommand).duration - } - if (command is RUMUpdatePerformanceMetric) { - lastReceivedPerformanceMetrics[.jsFrameTimeSeconds] = (command as! RUMUpdatePerformanceMetric).value - } - } -} - - private final class MockJSRefreshRateMonitor: RefreshRateMonitor { private var refreshRateListener: RefreshRateListener? private var frameTimeCallback: frame_time_callback? @@ -930,7 +1007,13 @@ extension NSDictionary { extension DdSdkImplementation { internal override convenience init() { - self.init(mainDispatchQueue: DispatchQueue.main, jsDispatchQueue: DispatchQueue.main, jsRefreshRateMonitor: JSRefreshRateMonitor.init()) + self.init( + mainDispatchQueue: DispatchQueue.main, + jsDispatchQueue: DispatchQueue.main, + jsRefreshRateMonitor: JSRefreshRateMonitor.init(), + RUMMonitorProvider: { MockRUMMonitor() }, + RUMMonitorInternalProvider: { nil } + ) } } diff --git a/packages/core/ios/Tests/DdTraceTests.swift b/packages/core/ios/Tests/DdTraceTests.swift index 0f559cd34..6c86a6e92 100644 --- a/packages/core/ios/Tests/DdTraceTests.swift +++ b/packages/core/ios/Tests/DdTraceTests.swift @@ -6,7 +6,8 @@ import XCTest @testable import DatadogSDKReactNative -@testable import Datadog +@testable import DatadogCore +@testable import DatadogTrace internal class DdTraceTests: XCTestCase { diff --git a/packages/core/ios/Tests/MockRUMMonitor.swift b/packages/core/ios/Tests/MockRUMMonitor.swift new file mode 100644 index 000000000..df8b27ac1 --- /dev/null +++ b/packages/core/ios/Tests/MockRUMMonitor.swift @@ -0,0 +1,159 @@ +/* + * Unless explicitly stated otherwise all files in this repository are licensed under the Apache License Version 2.0. + * This product includes software developed at Datadog (https://www.datadoghq.com/). + * Copyright 2019-2020 Datadog, Inc. + */ + +@testable import DatadogCore +@testable import DatadogRUM +@testable import DatadogInternal +@testable import DatadogSDKReactNative + +internal class MockRUMMonitor: RUMMonitorProtocol { + init () { + self.debug = false + } + + func addAttribute(forKey key: DatadogInternal.AttributeKey, value: DatadogInternal.AttributeValue) { + addedAttributes[key] = value + } + + func removeAttribute(forKey key: DatadogInternal.AttributeKey) {} + + var debug: Bool + + struct Interval: Equatable { + let start: Date? + let end: Date? + } + + enum CalledMethod: Equatable { + case startView(key: String, name: String?) + case stopView(key: String) + case addError(message: String, source: RUMErrorSource, stack: String?) + case startResourceLoading(resourceKey: String, httpMethod: RUMMethod, urlString: String) + case stopResourceLoading(resourceKey: String, statusCode: Int, kind: RUMResourceType, size: Int64?) + case startUserAction(type: RUMActionType, name: String) + case stopUserAction(type: RUMActionType, name: String?) + case addUserAction(type: RUMActionType, name: String) + case addTiming(name: String) + case stopSession(_: Int? = nil) // We need an attribute for the case to be Equatable + case addResourceMetrics(resourceKey: String, + fetch: Interval, + redirection: Interval, + dns: Interval, + connect: Interval, + ssl: Interval, + firstByte: Interval, + download: Interval, + responseSize: Int64?) + case addLongTasks(time: Date, duration: TimeInterval) + case updatePerformanceMetric(time: Date, metric: DatadogRUM.PerformanceMetric, value: Double) + + } + + public var calledMethods = [CalledMethod]() + public var receivedAttributes = [[AttributeKey: AttributeValue]]() + private(set) var addedAttributes = [AttributeKey: AttributeValue]() + private(set) var receivedFeatureFlags = [String: Encodable]() + public var lastReceivedPerformanceMetrics = [PerformanceMetric: Double]() + public var receivedLongTasks = [Date: TimeInterval]() + + func startView(key: String, name: String?, attributes: [AttributeKey: AttributeValue]) { + calledMethods.append(.startView(key: key, name: name)) + receivedAttributes.append(attributes) + } + + func stopView(key: String, attributes: [AttributeKey: AttributeValue]) { + calledMethods.append(.stopView(key: key)) + receivedAttributes.append(attributes) + } + + func addError(message: String, type: String?, stack: String?, source: RUMErrorSource, attributes: [String: Encodable], file: StaticString?, line: UInt?) { + calledMethods.append(.addError(message: message, source: source, stack: stack)) + receivedAttributes.append(attributes) + } + + func startResource(resourceKey: String, httpMethod: RUMMethod, urlString: String, attributes: [String: Encodable]) { + calledMethods.append(.startResourceLoading(resourceKey: resourceKey, httpMethod: httpMethod, urlString: urlString)) + receivedAttributes.append(attributes) + } + func stopResource(resourceKey: String, statusCode: Int?, kind: RUMResourceType, size: Int64?, attributes: [String: Encodable]) { + calledMethods.append(.stopResourceLoading(resourceKey: resourceKey, statusCode: statusCode ?? 0, kind: kind, size: size)) + receivedAttributes.append(attributes) + } + func startAction(type: RUMActionType, name: String, attributes: [String: Encodable]) { + calledMethods.append(.startUserAction(type: type, name: name)) + receivedAttributes.append(attributes) + } + func stopAction(type: RUMActionType, name: String?, attributes: [String: Encodable]) { + calledMethods.append(.stopUserAction(type: type, name: name)) + receivedAttributes.append(attributes) + } + func addAction(type: RUMActionType, name: String, attributes: [String: Encodable]) { + calledMethods.append(.addUserAction(type: type, name: name)) + receivedAttributes.append(attributes) + } + func addTiming(name: String) { + calledMethods.append(.addTiming(name: name)) + } + func stopSession() { + calledMethods.append(.stopSession()) + } + func addFeatureFlagEvaluation(name: String, value: Encodable) { + receivedFeatureFlags[name] = value + } + + var _internalMock: MockRUMMonitorInternal { + MockRUMMonitorInternal(monitor: self) + } +} + +public struct MockRUMMonitorInternal: RUMMonitorInternalProtocol { + let monitor: MockRUMMonitor + + public func addLongTask(at time: Date, duration: TimeInterval, attributes: [AttributeKey : AttributeValue]) { + monitor.calledMethods.append( + .addLongTasks(time: time, duration: duration) + ) + monitor.receivedAttributes.append(attributes) + monitor.receivedLongTasks[time] = duration + } + + public func updatePerformanceMetric(at time: Date, metric: DatadogRUM.PerformanceMetric, value: Double, attributes: [AttributeKey : AttributeValue]) { + monitor.calledMethods.append( + .updatePerformanceMetric(time: time, metric: metric, value: value) + ) + monitor.receivedAttributes.append(attributes) + monitor.lastReceivedPerformanceMetrics[metric] = value + } + + public func addResourceMetrics( + at time: Date, + resourceKey: String, + fetch: (start: Date, end: Date), + redirection: (start: Date, end: Date)?, + dns: (start: Date, end: Date)?, + connect: (start: Date, end: Date)?, + ssl: (start: Date, end: Date)?, + firstByte: (start: Date, end: Date)?, + download: (start: Date, end: Date)?, + responseSize: Int64?, + attributes: [AttributeKey: AttributeValue] + ) { + monitor.calledMethods.append( + .addResourceMetrics( + resourceKey: resourceKey, + fetch: MockRUMMonitor.Interval(start: fetch.start, end: fetch.end), + redirection: MockRUMMonitor.Interval(start: redirection?.start, end: redirection?.end), + dns: MockRUMMonitor.Interval(start: dns?.start, end: dns?.end), + connect: MockRUMMonitor.Interval(start: connect?.start, end: connect?.end), + ssl: MockRUMMonitor.Interval(start: ssl?.start, end: ssl?.end), + firstByte: MockRUMMonitor.Interval(start: firstByte?.start, end: firstByte?.end), + download: MockRUMMonitor.Interval(start: download?.start, end: download?.end), + responseSize: responseSize + ) + ) + monitor.receivedAttributes.append(attributes) + } +} diff --git a/packages/core/ios/Tests/RUMMocks.swift b/packages/core/ios/Tests/RUMMocks.swift index 0d4c28b31..7c95b4834 100644 --- a/packages/core/ios/Tests/RUMMocks.swift +++ b/packages/core/ios/Tests/RUMMocks.swift @@ -4,7 +4,7 @@ * Copyright 2019-Present Datadog, Inc. */ -@testable import Datadog +@testable import DatadogRUM // MARK: - Foundation Mocks protocol RandomMockable { @@ -257,6 +257,7 @@ extension RUMResourceEvent: RandomMockable { return RUMResourceEvent( dd: .init( browserSdkVersion: nil, + configuration: nil, discarded: nil, rulePsr: nil, session: .init(plan: .plan1), @@ -314,6 +315,7 @@ extension RUMResourceEvent: RandomMockable { return RUMResourceEvent( dd: .init( browserSdkVersion: nil, + configuration: nil, discarded: nil, rulePsr: nil, session: .init(plan: .plan1), @@ -381,6 +383,7 @@ extension RUMActionEvent: RandomMockable { ) ), browserSdkVersion: nil, + configuration: nil, session: .init(plan: .plan1) ), action: .init( @@ -433,6 +436,7 @@ extension RUMActionEvent: RandomMockable { ) ), browserSdkVersion: nil, + configuration: nil, session: .init(plan: .plan1) ), action: .init( From 00991d3e818482a751f9c1b998b51416653cde86 Mon Sep 17 00:00:00 2001 From: louiszawadzki Date: Thu, 7 Sep 2023 11:01:53 +0200 Subject: [PATCH 14/28] Clarify that info verbosity maps to debug on iOS --- packages/core/ios/Sources/DdSdkImplementation.swift | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/core/ios/Sources/DdSdkImplementation.swift b/packages/core/ios/Sources/DdSdkImplementation.swift index 0f1a20a8b..ae91ab140 100644 --- a/packages/core/ios/Sources/DdSdkImplementation.swift +++ b/packages/core/ios/Sources/DdSdkImplementation.swift @@ -348,8 +348,8 @@ public class DdSdkImplementation: NSObject { switch verbosityLevel?.lowercased { case "debug": Datadog.verbosityLevel = .debug - // TODO: deprecate info in js and android case "info": + // .info is mapped to .debug Datadog.verbosityLevel = .debug case "warn": Datadog.verbosityLevel = .warn From cd92cb9edbbb4968b5536f19098aabe59ed524b3 Mon Sep 17 00:00:00 2001 From: louiszawadzki Date: Thu, 7 Sep 2023 11:48:07 +0200 Subject: [PATCH 15/28] Fix SDK tests that had changed --- example/ios/Podfile | 2 +- example/ios/PodfileForTests | 4 +- .../ios/Sources/DdSdkImplementation.swift | 29 +++-- packages/core/ios/Tests/DdSdkTests.swift | 120 +++++++++++++----- 4 files changed, 108 insertions(+), 47 deletions(-) diff --git a/example/ios/Podfile b/example/ios/Podfile index 8cfc614ed..64c60a6cf 100644 --- a/example/ios/Podfile +++ b/example/ios/Podfile @@ -61,7 +61,7 @@ target 'ddSdkReactnativeExample' do ) __apply_Xcode_12_5_M1_post_install_workaround(installer) # Enable `DD_SDK_COMPILED_FOR_TESTING` condition when compiling `DatadogSDK` dependency: - datadog_sdk_target = installer.pods_project.targets.detect {|t| ["DatadogCore", "DatadogRUM", "DatadogLogs", "DatadogInternal", "DatadogTrace"].include?(t.name) } + datadog_sdk_target = installer.pods_project.targets.detect {|t| ["DatadogCore", "DatadogRUM", "DatadogLogs", "DatadogInternal", "DatadogTrace", "DatadogCrashReporting"].include?(t.name) } datadog_sdk_target.build_configurations.each do |config| config.build_settings['SWIFT_ACTIVE_COMPILATION_CONDITIONS'] = '$(inherited) DD_SDK_COMPILED_FOR_TESTING' end diff --git a/example/ios/PodfileForTests b/example/ios/PodfileForTests index aeb3d2919..eaa582754 100644 --- a/example/ios/PodfileForTests +++ b/example/ios/PodfileForTests @@ -44,7 +44,7 @@ target 'ddSdkReactnativeExample' do # An absolute path to your application root. :app_path => "#{Pod::Config.instance.installation_root}/.." ) - + target 'ddSdkReactnativeExampleTests' do inherit! :complete # Pods for testing @@ -59,7 +59,7 @@ target 'ddSdkReactnativeExample' do ) __apply_Xcode_12_5_M1_post_install_workaround(installer) # Enable `DD_SDK_COMPILED_FOR_TESTING` condition when compiling `DatadogSDK` dependency: - datadog_sdk_target = installer.pods_project.targets.detect {|t| t.name == "DatadogSDK" } + datadog_sdk_target = installer.pods_project.targets.detect {|t| ["DatadogCore", "DatadogRUM", "DatadogLogs", "DatadogInternal", "DatadogTrace", "DatadogCrashReporting"].include?(t.name) } datadog_sdk_target.build_configurations.each do |config| config.build_settings['SWIFT_ACTIVE_COMPILATION_CONDITIONS'] = '$(inherited) DD_SDK_COMPILED_FOR_TESTING' end diff --git a/packages/core/ios/Sources/DdSdkImplementation.swift b/packages/core/ios/Sources/DdSdkImplementation.swift index ae91ab140..09f88cc64 100644 --- a/packages/core/ios/Sources/DdSdkImplementation.swift +++ b/packages/core/ios/Sources/DdSdkImplementation.swift @@ -83,23 +83,26 @@ public class DdSdkImplementation: NSObject { let consent = self.buildTrackingConsent(consent: sdkConfiguration.trackingConsent) Datadog.initialize(with: sdkConfig, trackingConsent: consent) - let rumConfig = self.buildRUMConfiguration(configuration: sdkConfiguration) - RUM.enable(with: rumConfig) - - Logs.enable(with: Logs.Configuration()) - - Trace.enable(with: Trace.Configuration()) - - if sdkConfiguration.nativeCrashReportEnabled ?? false { - CrashReporting.enable() - } - + self.enableFeatures(sdkConfiguration: sdkConfiguration) self.sendConfigurationAsTelemetry(rnConfiguration: sdkConfiguration) self.startJSRefreshRateMonitoring(sdkConfiguration: sdkConfiguration) - + resolve(nil) } } + + func enableFeatures(sdkConfiguration: DdSdkConfiguration) { + let rumConfig = self.buildRUMConfiguration(configuration: sdkConfiguration) + RUM.enable(with: rumConfig) + + Logs.enable(with: Logs.Configuration()) + + Trace.enable(with: Trace.Configuration()) + + if sdkConfiguration.nativeCrashReportEnabled ?? false { + CrashReporting.enable() + } + } @objc public func setAttributes(attributes: NSDictionary, resolve:RCTPromiseResolveBlock, reject:RCTPromiseRejectBlock) -> Void { @@ -178,7 +181,7 @@ public class DdSdkImplementation: NSObject { uploadFrequency: configuration.uploadFrequency, proxyConfiguration: buildProxyConfiguration(config: configuration.additionalConfig) ) - if var additionalConfiguration = configuration.additionalConfig as? [String: Any] { + if let additionalConfiguration = configuration.additionalConfig as? [String: Any] { config._internal_mutation { $0.additionalConfiguration = additionalConfiguration } diff --git a/packages/core/ios/Tests/DdSdkTests.swift b/packages/core/ios/Tests/DdSdkTests.swift index 0600a0ea4..5d4a40be4 100644 --- a/packages/core/ios/Tests/DdSdkTests.swift +++ b/packages/core/ios/Tests/DdSdkTests.swift @@ -9,6 +9,9 @@ import XCTest @testable import DatadogCore @testable import DatadogRUM @testable import DatadogInternal +@testable import DatadogLogs +@testable import DatadogTrace +@testable import DatadogCrashReporting import DatadogLogs final class DispatchQueueMock: DispatchQueueType { @@ -201,6 +204,19 @@ internal class DdSdkTests: XCTestCase { Datadog.internalFlushAndDeinitialize() } + + func testEnableAllFeatures() { + let core = MockDatadogCore() + CoreRegistry.register(default: core) + let configuration: DdSdkConfiguration = .mockAny() + + DdSdkImplementation().enableFeatures(sdkConfiguration: configuration) + + XCTAssertNotNil(core.features[RUMFeature.name]) + XCTAssertNotNil(core.features[LogsFeature.name]) + XCTAssertNotNil(core.features[TraceFeature.name]) + CoreRegistry.unregisterDefault() + } func testBuildConfigurationDefaultEndpoint() { let configuration: DdSdkConfiguration = .mockAny() @@ -310,32 +326,36 @@ internal class DdSdkTests: XCTestCase { } func testBuildConfigurationNoCrashReportByDefault() { - // TODO: rewrite this test -// let configuration: DdSdkConfiguration = .mockAny(nativeCrashReportEnabled: nil) -// -// let ddConfig = DdSdkImplementation().buildSDKConfiguration(configuration: configuration) -// -// XCTAssertNil(ddConfig.crashReportingPlugin) + let core = MockDatadogCore() + CoreRegistry.register(default: core) + let configuration: DdSdkConfiguration = .mockAny(nativeCrashReportEnabled: nil) + + DdSdkImplementation().enableFeatures(sdkConfiguration: configuration) + + XCTAssertNil(core.features[CrashReportingFeature.name]) + CoreRegistry.unregisterDefault() } func testBuildConfigurationNoCrashReport() { - // TODO: rewrite this test -// let configuration: DdSdkConfiguration = .mockAny(nativeCrashReportEnabled: false) -// -// let ddConfig = DdSdkImplementation().buildSDKConfiguration(configuration: configuration) -// -// XCTAssertNil(ddConfig.crashReportingPlugin) + let core = MockDatadogCore() + CoreRegistry.register(default: core) + let configuration: DdSdkConfiguration = .mockAny(nativeCrashReportEnabled: false) + + DdSdkImplementation().enableFeatures(sdkConfiguration: configuration) + + XCTAssertNil(core.features[CrashReportingFeature.name]) + CoreRegistry.unregisterDefault() } func testBuildConfigurationWithCrashReport() { - // TODO: rewrite this test -// let configuration: DdSdkConfiguration = .mockAny( -// nativeCrashReportEnabled: true -// ) -// -// let ddConfig = DdSdkImplementation().buildSDKConfiguration(configuration: configuration) -// -// XCTAssertNotNil(ddConfig.crashReportingPlugin) + let core = MockDatadogCore() + CoreRegistry.register(default: core) + let configuration: DdSdkConfiguration = .mockAny(nativeCrashReportEnabled: true) + + DdSdkImplementation().enableFeatures(sdkConfiguration: configuration) + + XCTAssertNotNil(core.features[CrashReportingFeature.name]) + CoreRegistry.unregisterDefault() } func testBuildConfigurationWithVersionSuffix() { @@ -495,12 +515,17 @@ internal class DdSdkTests: XCTestCase { ]]) let ddConfig = DdSdkImplementation().buildRUMConfiguration(configuration: configuration) - - var firstPartyHosts: FirstPartyHosts? = FirstPartyHosts(["example.com": [.datadog, .b3]]) - firstPartyHosts += FirstPartyHosts(["datadog.com": [.b3multi, .tracecontext]]) - // TODO: rewrite this test -// XCTAssertEqual(ddConfig.urlSessionTracking?.firstPartyHostsTracing, firstPartyHosts!) + let expectedFirstPartyHosts: [String: Set]? = ["example.com": [.datadog, .b3], "datadog.com": [.b3multi, .tracecontext]] + var actualFirstPartyHosts: [String: Set]? + switch ddConfig.urlSessionTracking?.firstPartyHostsTracing { + case .trace(_,_): break + case let .traceWithHeaders(hostsWithHeaders, _): + return actualFirstPartyHosts = hostsWithHeaders + case .none: break + } + + XCTAssertEqual(actualFirstPartyHosts, expectedFirstPartyHosts) } func testBuildMalformedFirstPartyHosts() { @@ -510,10 +535,16 @@ internal class DdSdkTests: XCTestCase { let ddConfig = DdSdkImplementation().buildRUMConfiguration(configuration: configuration) - let firstPartyHosts: FirstPartyHosts? = FirstPartyHosts(["example.com": [.b3]]) + let expectedFirstPartyHosts: [String: Set]? = ["example.com": [.b3]] + var actualFirstPartyHosts: [String: Set]? + switch ddConfig.urlSessionTracking?.firstPartyHostsTracing { + case .trace(_,_): break + case let .traceWithHeaders(hostsWithHeaders, _): + return actualFirstPartyHosts = hostsWithHeaders + case .none: break + } - // TODO: rewrite this test -// XCTAssertEqual(ddConfig.firstPartyHosts, firstPartyHosts) + XCTAssertEqual(actualFirstPartyHosts, expectedFirstPartyHosts) } func testBuildFirstPartyHostsWithDuplicatedMatchKey() { @@ -524,10 +555,16 @@ internal class DdSdkTests: XCTestCase { let ddConfig = DdSdkImplementation().buildRUMConfiguration(configuration: configuration) - var firstPartyHosts: FirstPartyHosts? = FirstPartyHosts(["example.com": [.b3, .tracecontext]]) + let expectedFirstPartyHosts: [String: Set]? = ["example.com": [.b3, .tracecontext]] + var actualFirstPartyHosts: [String: Set]? + switch ddConfig.urlSessionTracking?.firstPartyHostsTracing { + case .trace(_,_): break + case let .traceWithHeaders(hostsWithHeaders, _): + return actualFirstPartyHosts = hostsWithHeaders + case .none: break + } - // TODO: rewrite this test -// XCTAssertEqual(ddConfig.firstPartyHosts, firstPartyHosts) + XCTAssertEqual(actualFirstPartyHosts, expectedFirstPartyHosts) } func testBuildTelemetrySampleRate() { @@ -1015,5 +1052,26 @@ extension DdSdkImplementation { RUMMonitorInternalProvider: { nil } ) } +} + +internal class MockDatadogCore: DatadogCoreProtocol { + func send(message: DatadogInternal.FeatureMessage, else fallback: @escaping () -> Void) {} + + private(set) var features: [String: DatadogFeature] = [:] + + func register(feature: T) throws where T : DatadogFeature { + features[T.name] = feature + } + + func get(feature type: T.Type) -> T? where T : DatadogFeature { + return nil + } + + func scope(for feature: String) -> FeatureScope? { + return nil + } + + func set(feature: String, attributes: @escaping () -> FeatureBaggage) {} + func update(feature: String, attributes: @escaping () -> FeatureBaggage) {} } From 9ed755f5edc216f54d3d2148223eca34e81e6e1e Mon Sep 17 00:00:00 2001 From: louiszawadzki Date: Thu, 7 Sep 2023 15:36:31 +0200 Subject: [PATCH 16/28] Add tests for telemetry override --- .../ios/Sources/DdSdkImplementation.swift | 23 ++-- packages/core/ios/Tests/DdSdkTests.swift | 122 +++++------------- 2 files changed, 46 insertions(+), 99 deletions(-) diff --git a/packages/core/ios/Sources/DdSdkImplementation.swift b/packages/core/ios/Sources/DdSdkImplementation.swift index 09f88cc64..a0a64450e 100644 --- a/packages/core/ios/Sources/DdSdkImplementation.swift +++ b/packages/core/ios/Sources/DdSdkImplementation.swift @@ -81,27 +81,28 @@ public class DdSdkImplementation: NSObject { let sdkConfig = self.buildSDKConfiguration(configuration: sdkConfiguration) let consent = self.buildTrackingConsent(consent: sdkConfiguration.trackingConsent) - Datadog.initialize(with: sdkConfig, trackingConsent: consent) + let core = Datadog.initialize(with: sdkConfig, trackingConsent: consent) - self.enableFeatures(sdkConfiguration: sdkConfiguration) - self.sendConfigurationAsTelemetry(rnConfiguration: sdkConfiguration) + self.enableFeatures(sdkConfiguration: sdkConfiguration, core: core) self.startJSRefreshRateMonitoring(sdkConfiguration: sdkConfiguration) resolve(nil) } } - func enableFeatures(sdkConfiguration: DdSdkConfiguration) { - let rumConfig = self.buildRUMConfiguration(configuration: sdkConfiguration) - RUM.enable(with: rumConfig) + func enableFeatures(sdkConfiguration: DdSdkConfiguration, core: DatadogCoreProtocol) { + let rumConfig = buildRUMConfiguration(configuration: sdkConfiguration) + RUM.enable(with: rumConfig, in: core) - Logs.enable(with: Logs.Configuration()) + Logs.enable(with: Logs.Configuration(), in: core) - Trace.enable(with: Trace.Configuration()) + Trace.enable(with: Trace.Configuration(), in: core) if sdkConfiguration.nativeCrashReportEnabled ?? false { - CrashReporting.enable() + CrashReporting.enable(in: core) } + + overrideReactNativeTelemetry(rnConfiguration: sdkConfiguration, core: core) } @objc @@ -157,9 +158,9 @@ public class DdSdkImplementation: NSObject { resolve(nil) } - func sendConfigurationAsTelemetry(rnConfiguration: DdSdkConfiguration) -> Void { + func overrideReactNativeTelemetry(rnConfiguration: DdSdkConfiguration, core: DatadogCoreProtocol) -> Void { // TODO: missing some keys: initializationType, reactVersion, reactNativeVersion, trackNativeErrors - let telemetry = TelemetryCore(core: CoreRegistry.default) + let telemetry = TelemetryCore(core: core) telemetry.configuration( trackCrossPlatformLongTasks: rnConfiguration.longTaskThresholdMs != 0, trackErrors: rnConfiguration.configurationForTelemetry?.trackErrors, diff --git a/packages/core/ios/Tests/DdSdkTests.swift b/packages/core/ios/Tests/DdSdkTests.swift index 5d4a40be4..81fcdeb50 100644 --- a/packages/core/ios/Tests/DdSdkTests.swift +++ b/packages/core/ios/Tests/DdSdkTests.swift @@ -207,15 +207,13 @@ internal class DdSdkTests: XCTestCase { func testEnableAllFeatures() { let core = MockDatadogCore() - CoreRegistry.register(default: core) let configuration: DdSdkConfiguration = .mockAny() - DdSdkImplementation().enableFeatures(sdkConfiguration: configuration) + DdSdkImplementation().enableFeatures(sdkConfiguration: configuration, core: core) XCTAssertNotNil(core.features[RUMFeature.name]) XCTAssertNotNil(core.features[LogsFeature.name]) XCTAssertNotNil(core.features[TraceFeature.name]) - CoreRegistry.unregisterDefault() } func testBuildConfigurationDefaultEndpoint() { @@ -327,35 +325,29 @@ internal class DdSdkTests: XCTestCase { func testBuildConfigurationNoCrashReportByDefault() { let core = MockDatadogCore() - CoreRegistry.register(default: core) let configuration: DdSdkConfiguration = .mockAny(nativeCrashReportEnabled: nil) - DdSdkImplementation().enableFeatures(sdkConfiguration: configuration) + DdSdkImplementation().enableFeatures(sdkConfiguration: configuration, core: core) XCTAssertNil(core.features[CrashReportingFeature.name]) - CoreRegistry.unregisterDefault() } func testBuildConfigurationNoCrashReport() { let core = MockDatadogCore() - CoreRegistry.register(default: core) let configuration: DdSdkConfiguration = .mockAny(nativeCrashReportEnabled: false) - DdSdkImplementation().enableFeatures(sdkConfiguration: configuration) + DdSdkImplementation().enableFeatures(sdkConfiguration: configuration, core: core) XCTAssertNil(core.features[CrashReportingFeature.name]) - CoreRegistry.unregisterDefault() } func testBuildConfigurationWithCrashReport() { let core = MockDatadogCore() - CoreRegistry.register(default: core) let configuration: DdSdkConfiguration = .mockAny(nativeCrashReportEnabled: true) - DdSdkImplementation().enableFeatures(sdkConfiguration: configuration) + DdSdkImplementation().enableFeatures(sdkConfiguration: configuration, core: core) XCTAssertNotNil(core.features[CrashReportingFeature.name]) - CoreRegistry.unregisterDefault() } func testBuildConfigurationWithVersionSuffix() { @@ -813,80 +805,27 @@ internal class DdSdkTests: XCTestCase { XCTAssertEqual(ddConfig.trackBackgroundEvents, false) } - func testConfigurationTelemetryEventMapper() throws { - //TODO: rewrite this test -// DdSdkImplementation( -// mainDispatchQueue: DispatchQueueMock(), -// jsDispatchQueue: DispatchQueueMock(), -// jsRefreshRateMonitor: JSRefreshRateMonitor()) -// .initialize( -// configuration: .mockAny( -// nativeCrashReportEnabled: false, -// nativeLongTaskThresholdMs: 0.0, -// longTaskThresholdMs: 0.1, -// configurationForTelemetry: ["initializationType": "LEGACY", "trackErrors": true, "trackInteractions": true, "trackNetworkRequests": true, "reactVersion": "18.2.0", "reactNativeVersion": "0.71.0"] -// ), -// resolve: mockResolve, -// reject: mockReject -// ) -// -// -// guard let configurationEventMapper = try XCTUnwrap(DD.telemetry as? RUMTelemetry).configurationEventMapper else { return } -// -// let mappedEvent = configurationEventMapper( -// TelemetryConfigurationEvent( -// dd: TelemetryConfigurationEvent.DD(), -// action: nil, -// application: nil, -// date: Int64(), -// experimentalFeatures: nil, -// service: "mockService", -// session: nil, -// source: .reactNative, -// telemetry: TelemetryConfigurationEvent.Telemetry( -// configuration: TelemetryConfigurationEvent.Telemetry.Configuration( -// actionNameAttribute: nil, -// batchSize: nil, -// batchUploadFrequency: nil, -// forwardConsoleLogs: nil, -// forwardErrorsToLogs: nil, -// forwardReports: nil, -// premiumSampleRate: nil, -// replaySampleRate: nil, -// selectedTracingPropagators: nil, -// sessionSampleRate: nil, -// silentMultipleInit: nil, -// telemetryConfigurationSampleRate: nil, -// telemetrySampleRate: nil, -// traceSampleRate: nil, -// trackSessionAcrossSubdomains: nil, -// useAllowedTracingOrigins: nil, -// useAllowedTracingUrls: nil, -// useBeforeSend: nil, -// useCrossSiteSessionCookie: nil, -// useExcludedActivityUrls: nil, -// useLocalEncryption: nil, -// useSecureSessionCookie: nil, -// useTracing: nil, -// viewTrackingStrategy: nil -// ) -// ), -// version: "1.0.0", -// view: nil -// ) -// ) -// -// XCTAssertEqual(mappedEvent.telemetry.configuration.initializationType, "LEGACY") -// XCTAssertEqual(mappedEvent.telemetry.configuration.trackErrors, true) -// XCTAssertEqual(mappedEvent.telemetry.configuration.trackInteractions, true) -// XCTAssertEqual(mappedEvent.telemetry.configuration.trackNetworkRequests, true) -// XCTAssertEqual(mappedEvent.telemetry.configuration.trackNativeErrors, false) -// XCTAssertEqual(mappedEvent.telemetry.configuration.trackNativeLongTasks, false) -// XCTAssertEqual(mappedEvent.telemetry.configuration.trackLongTask, true) -// XCTAssertEqual(mappedEvent.telemetry.configuration.reactVersion, "18.2.0") -// XCTAssertEqual(mappedEvent.telemetry.configuration.reactNativeVersion, "0.71.0") -// -// Datadog.internalFlushAndDeinitialize() + func testConfigurationTelemetryOverride() throws { + let core = MockDatadogCore() + let configuration: DdSdkConfiguration = .mockAny( + nativeCrashReportEnabled: false, + nativeLongTaskThresholdMs: 0.0, + longTaskThresholdMs: 0.1, + configurationForTelemetry: ["initializationType": "LEGACY", "trackErrors": true, "trackInteractions": true, "trackNetworkRequests": true, "reactVersion": "18.2.0", "reactNativeVersion": "0.71.0"] + ) + + DdSdkImplementation().overrideReactNativeTelemetry(rnConfiguration: configuration, core: core) + + // TODO: uncomment when all telemetry is supported +// XCTAssertEqual(mockTelemetry.configuration?.initializationType, "LEGACY") + XCTAssertEqual(core.configuration?.trackErrors, true) + XCTAssertEqual(core.configuration?.trackInteractions, true) + XCTAssertEqual(core.configuration?.trackNetworkRequests, true) +// XCTAssertEqual(core.configuration?.trackNativeErrors, false) + XCTAssertEqual(core.configuration?.trackNativeLongTasks, false) + XCTAssertEqual(core.configuration?.trackLongTask, true) +// XCTAssertEqual(core.configuration?.reactVersion, "18.2.0") +// XCTAssertEqual(core.configuration?.reactNativeVersion, "0.71.0") } func testDropsResourceMarkedAsDropped() throws { @@ -1055,8 +994,15 @@ extension DdSdkImplementation { } internal class MockDatadogCore: DatadogCoreProtocol { - func send(message: DatadogInternal.FeatureMessage, else fallback: @escaping () -> Void) {} - + func send(message: FeatureMessage, else fallback: @escaping () -> Void) { + if // Configuration Telemetry Message + case .telemetry(let telemetry) = message, + case .configuration(let configuration) = telemetry { + self.configuration = configuration + } + } + + private(set) var configuration: ConfigurationTelemetry? private(set) var features: [String: DatadogFeature] = [:] func register(feature: T) throws where T : DatadogFeature { From 21ca0295a33976e0064caa46ecdd5c1ddfbcf16b Mon Sep 17 00:00:00 2001 From: louiszawadzki Date: Thu, 7 Sep 2023 15:45:05 +0200 Subject: [PATCH 17/28] Fix timestamp key equality test --- packages/core/ios/Tests/DdRumTests.swift | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/packages/core/ios/Tests/DdRumTests.swift b/packages/core/ios/Tests/DdRumTests.swift index 45f7417bf..859a60912 100644 --- a/packages/core/ios/Tests/DdRumTests.swift +++ b/packages/core/ios/Tests/DdRumTests.swift @@ -40,10 +40,12 @@ internal class DdRumTests: XCTestCase { waitForExpectations(timeout: 0.5, handler: nil) } - // TODO: Fix this test by removing ambiguity in names -// func testInternalTimestampKeyValue() { -// XCTAssertEqual(DdRumImplementation.timestampKey, CrossPlatformAttributes.timestampInMilliseconds) -// } + func testInternalTimestampKeyValue() { + let key = "_dd.timestamp" + + XCTAssertEqual(DdRumImplementation.timestampKey, DatadogInternal.CrossPlatformAttributes.timestampInMilliseconds) + XCTAssertEqual(DdRumImplementation.timestampKey, DatadogSDKReactNative.CrossPlatformAttributes.timestampInMilliseconds) + } func testStartView() throws { rum.startView(key: "view key", name: "view name", context: ["foo": 123], timestampMs: randomTimestamp, resolve: mockResolve, reject: mockReject) From f19c35ff0ef467de0975f76cf63c59a1695cbd4d Mon Sep 17 00:00:00 2001 From: louiszawadzki Date: Tue, 12 Sep 2023 18:10:11 +0200 Subject: [PATCH 18/28] Update iOS SDK to get full v2 features --- example-new-architecture/ios/Podfile.lock | 46 ++++++++++---- example/ios/Podfile.lock | 68 ++++++++++----------- packages/core/DatadogSDKReactNative.podspec | 12 ++-- 3 files changed, 75 insertions(+), 51 deletions(-) diff --git a/example-new-architecture/ios/Podfile.lock b/example-new-architecture/ios/Podfile.lock index 9aa844b7c..2dbd3f333 100644 --- a/example-new-architecture/ios/Podfile.lock +++ b/example-new-architecture/ios/Podfile.lock @@ -1,13 +1,23 @@ PODS: - boost (1.76.0) - CocoaAsyncSocket (7.6.5) - - DatadogSDK (1.22.0) - - DatadogSDKCrashReporting (1.22.0): - - DatadogSDK (= 1.22.0) - - PLCrashReporter (~> 1.11.0) + - DatadogCore (2.2.1): + - DatadogInternal (= 2.2.1) + - DatadogCrashReporting (2.2.1): + - DatadogInternal (= 2.2.1) + - PLCrashReporter (~> 1.11.1) + - DatadogInternal (2.2.1) + - DatadogLogs (2.2.1): + - DatadogInternal (= 2.2.1) + - DatadogRUM (2.2.1): + - DatadogInternal (= 2.2.1) - DatadogSDKReactNative (1.8.5): - - DatadogSDK (~> 1.22.0) - - DatadogSDKCrashReporting (~> 1.22.0) + - DatadogCore (~> 2.2.0) + - DatadogCrashReporting (~> 2.2.0) + - DatadogLogs (~> 2.2.0) + - DatadogRUM (~> 2.2.0) + - DatadogTrace (~> 2.2.0) + - DatadogWebViewTracking (~> 2.2.0) - RCT-Folly (= 2021.07.22.00) - RCTRequired - RCTTypeSafety @@ -16,6 +26,10 @@ PODS: - React-RCTFabric - ReactCommon/turbomodule/bridging - ReactCommon/turbomodule/core + - DatadogTrace (2.2.1): + - DatadogInternal (= 2.2.1) + - DatadogWebViewTracking (2.2.1): + - DatadogInternal (= 2.2.1) - DoubleConversion (1.1.6) - FBLazyVector (0.71.10) - FBReactNativeSpec (0.71.10): @@ -839,8 +853,13 @@ DEPENDENCIES: SPEC REPOS: trunk: - CocoaAsyncSocket - - DatadogSDK - - DatadogSDKCrashReporting + - DatadogCore + - DatadogCrashReporting + - DatadogInternal + - DatadogLogs + - DatadogRUM + - DatadogTrace + - DatadogWebViewTracking - Flipper - Flipper-Boost-iOSX - Flipper-DoubleConversion @@ -940,9 +959,14 @@ EXTERNAL SOURCES: SPEC CHECKSUMS: boost: 57d2868c099736d80fcd648bf211b4431e51a558 CocoaAsyncSocket: 065fd1e645c7abab64f7a6a2007a48038fdc6a99 - DatadogSDK: 46e1a7363bc3130fae151ec4aedf11ea291517c5 - DatadogSDKCrashReporting: 24a0e6ec6db905cdeb174721962a7941b2f8a9d2 - DatadogSDKReactNative: f5aebd969f859454689ca16326520c65a4eb3725 + DatadogCore: 12218dd1bed5db394c5e26ec59dd793413ae55b9 + DatadogCrashReporting: d094c1eb1ecce59dbb6b1062b2e524dfa6579fc9 + DatadogInternal: bfa2b823bd47511425d696d36a1bc77c4d06b2f4 + DatadogLogs: a0eafa7bd2103511eac07bcd2ff95c851123e29b + DatadogRUM: 1e027ccfe4ba1eb81a185f3c58e0909bb12811be + DatadogSDKReactNative: eab3c6708f09e9bf877bf0fb0b861663812f1659 + DatadogTrace: 74dc91a7a80e746dc4ef1af6d0db1735b5bfd993 + DatadogWebViewTracking: 9ca93299a2c900c68ba080f6e800fae1fa3c6b61 DoubleConversion: 5189b271737e1565bdce30deb4a08d647e3f5f54 FBLazyVector: ddb55c55295ea51ed98aa7e2e08add2f826309d5 FBReactNativeSpec: 33a87f65f1a467d5f63d11d0cc106a10d3b0639d diff --git a/example/ios/Podfile.lock b/example/ios/Podfile.lock index b8a41248e..090585c72 100644 --- a/example/ios/Podfile.lock +++ b/example/ios/Podfile.lock @@ -1,35 +1,35 @@ PODS: - boost (1.76.0) - - DatadogCore (2.1.2): - - DatadogInternal (= 2.1.2) - - DatadogCrashReporting (2.1.2): - - DatadogInternal (= 2.1.2) + - DatadogCore (2.2.1): + - DatadogInternal (= 2.2.1) + - DatadogCrashReporting (2.2.1): + - DatadogInternal (= 2.2.1) - PLCrashReporter (~> 1.11.1) - - DatadogInternal (2.1.2) - - DatadogLogs (2.1.2): - - DatadogInternal (= 2.1.2) - - DatadogRUM (2.1.2): - - DatadogInternal (= 2.1.2) + - DatadogInternal (2.2.1) + - DatadogLogs (2.2.1): + - DatadogInternal (= 2.2.1) + - DatadogRUM (2.2.1): + - DatadogInternal (= 2.2.1) - DatadogSDKReactNative (1.8.5): - - DatadogCore (~> 2.1.2) - - DatadogCrashReporting (~> 2.1.2) - - DatadogLogs (~> 2.1.2) - - DatadogRUM (~> 2.1.2) - - DatadogTrace (~> 2.1.2) - - DatadogWebViewTracking (~> 2.1.2) + - DatadogCore (~> 2.2.0) + - DatadogCrashReporting (~> 2.2.0) + - DatadogLogs (~> 2.2.0) + - DatadogRUM (~> 2.2.0) + - DatadogTrace (~> 2.2.0) + - DatadogWebViewTracking (~> 2.2.0) - React-Core - DatadogSDKReactNative/Tests (1.8.5): - - DatadogCore (~> 2.1.2) - - DatadogCrashReporting (~> 2.1.2) - - DatadogLogs (~> 2.1.2) - - DatadogRUM (~> 2.1.2) - - DatadogTrace (~> 2.1.2) - - DatadogWebViewTracking (~> 2.1.2) + - DatadogCore (~> 2.2.0) + - DatadogCrashReporting (~> 2.2.0) + - DatadogLogs (~> 2.2.0) + - DatadogRUM (~> 2.2.0) + - DatadogTrace (~> 2.2.0) + - DatadogWebViewTracking (~> 2.2.0) - React-Core - - DatadogTrace (2.1.2): - - DatadogInternal (= 2.1.2) - - DatadogWebViewTracking (2.1.2): - - DatadogInternal (= 2.1.2) + - DatadogTrace (2.2.1): + - DatadogInternal (= 2.2.1) + - DatadogWebViewTracking (2.2.1): + - DatadogInternal (= 2.2.1) - DoubleConversion (1.1.6) - FBLazyVector (0.71.10) - FBReactNativeSpec (0.71.10): @@ -556,14 +556,14 @@ EXTERNAL SOURCES: SPEC CHECKSUMS: boost: 57d2868c099736d80fcd648bf211b4431e51a558 - DatadogCore: 24190ba2cf526577212a9a6dd99e323684a867c1 - DatadogCrashReporting: ace454b37c3e8bb3e343823301dd2bf8f7da2e6f - DatadogInternal: 5b02abb37a3ea80b86b0b02463d305b53f76d8d0 - DatadogLogs: 612176842ed36a796b9dc6c8a28c079faa721d19 - DatadogRUM: 5372a3c69f865a0f98870818144bf0b6c3282136 - DatadogSDKReactNative: 4ba919b617e60dd5ada3e8e053e45797e3b062c4 - DatadogTrace: 61c815e87bd4d2e232cbc03e1c05cb9f61a34834 - DatadogWebViewTracking: b7b0b70263dfdf9abb16fecb654d7ad669cfc5db + DatadogCore: 12218dd1bed5db394c5e26ec59dd793413ae55b9 + DatadogCrashReporting: d094c1eb1ecce59dbb6b1062b2e524dfa6579fc9 + DatadogInternal: bfa2b823bd47511425d696d36a1bc77c4d06b2f4 + DatadogLogs: a0eafa7bd2103511eac07bcd2ff95c851123e29b + DatadogRUM: 1e027ccfe4ba1eb81a185f3c58e0909bb12811be + DatadogSDKReactNative: 99327113b9cc8c8b024e2f23a67e9ebc5929e52b + DatadogTrace: 74dc91a7a80e746dc4ef1af6d0db1735b5bfd993 + DatadogWebViewTracking: 9ca93299a2c900c68ba080f6e800fae1fa3c6b61 DoubleConversion: 5189b271737e1565bdce30deb4a08d647e3f5f54 FBLazyVector: ddb55c55295ea51ed98aa7e2e08add2f826309d5 FBReactNativeSpec: 90fc1a90b4b7a171e0a7c20ea426c1bf6ce4399c @@ -609,6 +609,6 @@ SPEC CHECKSUMS: RNScreens: f7ad633b2e0190b77b6a7aab7f914fad6f198d8d Yoga: e7ea9e590e27460d28911403b894722354d73479 -PODFILE CHECKSUM: 32a6101a728d3e9718c34a74bebf1924834aef29 +PODFILE CHECKSUM: 59a4878659fbb7b053887dd9eec3df44ca9e0b28 COCOAPODS: 1.12.1 diff --git a/packages/core/DatadogSDKReactNative.podspec b/packages/core/DatadogSDKReactNative.podspec index f2386589e..e8ebb02b8 100644 --- a/packages/core/DatadogSDKReactNative.podspec +++ b/packages/core/DatadogSDKReactNative.podspec @@ -17,12 +17,12 @@ Pod::Spec.new do |s| s.source_files = "ios/Sources/*.{h,m,mm,swift}" s.dependency "React-Core" - s.dependency 'DatadogCore', '~> 2.1.2' - s.dependency 'DatadogLogs', '~> 2.1.2' - s.dependency 'DatadogTrace', '~> 2.1.2' - s.dependency 'DatadogRUM', '~> 2.1.2' - s.dependency 'DatadogCrashReporting', '~> 2.1.2' - s.dependency 'DatadogWebViewTracking', '~> 2.1.2' + s.dependency 'DatadogCore', '~> 2.2.0' + s.dependency 'DatadogLogs', '~> 2.2.0' + s.dependency 'DatadogTrace', '~> 2.2.0' + s.dependency 'DatadogRUM', '~> 2.2.0' + s.dependency 'DatadogCrashReporting', '~> 2.2.0' + s.dependency 'DatadogWebViewTracking', '~> 2.2.0' s.test_spec 'Tests' do |test_spec| test_spec.source_files = 'ios/Tests/*.swift' From f0b3ca0a3a99ec14ca7ae88874225b41ec7392ed Mon Sep 17 00:00:00 2001 From: louiszawadzki Date: Tue, 12 Sep 2023 18:25:16 +0200 Subject: [PATCH 19/28] Add all fields to iOS configuration telemetry --- packages/core/ios/Sources/DdSdkImplementation.swift | 8 +++++--- packages/core/ios/Tests/DdSdkTests.swift | 9 ++++----- 2 files changed, 9 insertions(+), 8 deletions(-) diff --git a/packages/core/ios/Sources/DdSdkImplementation.swift b/packages/core/ios/Sources/DdSdkImplementation.swift index a0a64450e..7369f9f28 100644 --- a/packages/core/ios/Sources/DdSdkImplementation.swift +++ b/packages/core/ios/Sources/DdSdkImplementation.swift @@ -159,13 +159,15 @@ public class DdSdkImplementation: NSObject { } func overrideReactNativeTelemetry(rnConfiguration: DdSdkConfiguration, core: DatadogCoreProtocol) -> Void { - // TODO: missing some keys: initializationType, reactVersion, reactNativeVersion, trackNativeErrors - let telemetry = TelemetryCore(core: core) - telemetry.configuration( + core.telemetry.configuration( + initializationType: rnConfiguration.configurationForTelemetry?.initializationType as? String, + reactNativeVersion: rnConfiguration.configurationForTelemetry?.reactNativeVersion as? String, + reactVersion: rnConfiguration.configurationForTelemetry?.reactVersion as? String, trackCrossPlatformLongTasks: rnConfiguration.longTaskThresholdMs != 0, trackErrors: rnConfiguration.configurationForTelemetry?.trackErrors, trackInteractions: rnConfiguration.configurationForTelemetry?.trackInteractions, trackLongTask: rnConfiguration.longTaskThresholdMs != 0, + trackNativeErrors: rnConfiguration.nativeLongTaskThresholdMs != 0, trackNativeLongTasks: rnConfiguration.nativeLongTaskThresholdMs != 0, trackNetworkRequests: rnConfiguration.configurationForTelemetry?.trackNetworkRequests ) diff --git a/packages/core/ios/Tests/DdSdkTests.swift b/packages/core/ios/Tests/DdSdkTests.swift index 81fcdeb50..1ca76c08f 100644 --- a/packages/core/ios/Tests/DdSdkTests.swift +++ b/packages/core/ios/Tests/DdSdkTests.swift @@ -816,16 +816,15 @@ internal class DdSdkTests: XCTestCase { DdSdkImplementation().overrideReactNativeTelemetry(rnConfiguration: configuration, core: core) - // TODO: uncomment when all telemetry is supported -// XCTAssertEqual(mockTelemetry.configuration?.initializationType, "LEGACY") + XCTAssertEqual(core.configuration?.initializationType, "LEGACY") XCTAssertEqual(core.configuration?.trackErrors, true) XCTAssertEqual(core.configuration?.trackInteractions, true) XCTAssertEqual(core.configuration?.trackNetworkRequests, true) -// XCTAssertEqual(core.configuration?.trackNativeErrors, false) + XCTAssertEqual(core.configuration?.trackNativeErrors, false) XCTAssertEqual(core.configuration?.trackNativeLongTasks, false) XCTAssertEqual(core.configuration?.trackLongTask, true) -// XCTAssertEqual(core.configuration?.reactVersion, "18.2.0") -// XCTAssertEqual(core.configuration?.reactNativeVersion, "0.71.0") + XCTAssertEqual(core.configuration?.reactVersion, "18.2.0") + XCTAssertEqual(core.configuration?.reactNativeVersion, "0.71.0") } func testDropsResourceMarkedAsDropped() throws { From e89e12c0ada188db71f75c9f3763551778e8856d Mon Sep 17 00:00:00 2001 From: louiszawadzki Date: Tue, 12 Sep 2023 18:34:43 +0200 Subject: [PATCH 20/28] Enable setting custom version on iOS --- packages/core/ios/Sources/DdSdkImplementation.swift | 11 ++++++++--- packages/core/ios/Tests/DdSdkTests.swift | 11 +++++------ 2 files changed, 13 insertions(+), 9 deletions(-) diff --git a/packages/core/ios/Sources/DdSdkImplementation.swift b/packages/core/ios/Sources/DdSdkImplementation.swift index 7369f9f28..b7b4821ef 100644 --- a/packages/core/ios/Sources/DdSdkImplementation.swift +++ b/packages/core/ios/Sources/DdSdkImplementation.swift @@ -173,8 +173,7 @@ public class DdSdkImplementation: NSObject { ) } - func buildSDKConfiguration(configuration: DdSdkConfiguration) -> Datadog.Configuration { - // TODO: Add version to config once this is released on iOS + func buildSDKConfiguration(configuration: DdSdkConfiguration, defaultAppVersion: String = getDefaultAppVersion()) -> Datadog.Configuration { var config = Datadog.Configuration( clientToken: configuration.clientToken, env: configuration.env, @@ -184,7 +183,13 @@ public class DdSdkImplementation: NSObject { uploadFrequency: configuration.uploadFrequency, proxyConfiguration: buildProxyConfiguration(config: configuration.additionalConfig) ) - if let additionalConfiguration = configuration.additionalConfig as? [String: Any] { + + if var additionalConfiguration = configuration.additionalConfig as? [String: Any] { + if let versionSuffix = additionalConfiguration[InternalConfigurationAttributes.versionSuffix] as? String { + let datadogVersion = defaultAppVersion + versionSuffix + additionalConfiguration[CrossPlatformAttributes.version] = datadogVersion + } + config._internal_mutation { $0.additionalConfiguration = additionalConfiguration } diff --git a/packages/core/ios/Tests/DdSdkTests.swift b/packages/core/ios/Tests/DdSdkTests.swift index 1ca76c08f..df4a4c840 100644 --- a/packages/core/ios/Tests/DdSdkTests.swift +++ b/packages/core/ios/Tests/DdSdkTests.swift @@ -351,12 +351,11 @@ internal class DdSdkTests: XCTestCase { } func testBuildConfigurationWithVersionSuffix() { - // TODO: Re-enable this test when function is supported -// let configuration: DdSdkConfiguration = .mockAny(additionalConfig: ["_dd.version_suffix": ":codepush-3"]) -// -// let ddConfig = DdSdkImplementation().buildRUMConfiguration(configuration: configuration, defaultAppVersion: "1.2.3") -// -// XCTAssertEqual(ddConfig.additionalConfiguration["_dd.version"] as! String, "1.2.3:codepush-3") + let configuration: DdSdkConfiguration = .mockAny(additionalConfig: ["_dd.version_suffix": ":codepush-3"]) + + let ddConfig = DdSdkImplementation().buildSDKConfiguration(configuration: configuration, defaultAppVersion: "1.2.3") + + XCTAssertEqual(ddConfig.additionalConfiguration["_dd.version"] as! String, "1.2.3:codepush-3") } func testBuildConfigurationFrustrationTrackingEnabledByDefault() { From 86bd6c1931a4852334ee0b781d585fd0e8abc1fd Mon Sep 17 00:00:00 2001 From: louiszawadzki Date: Wed, 13 Sep 2023 14:10:19 +0200 Subject: [PATCH 21/28] Reenable ErrorSource iOS tests --- packages/core/ios/Tests/DdRumTests.swift | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/packages/core/ios/Tests/DdRumTests.swift b/packages/core/ios/Tests/DdRumTests.swift index 859a60912..393dd5fb5 100644 --- a/packages/core/ios/Tests/DdRumTests.swift +++ b/packages/core/ios/Tests/DdRumTests.swift @@ -269,11 +269,11 @@ internal class DdRumTests: XCTestCase { } func testRumErrorSourceMapping() throws { -// XCTAssertEqual(RUMErrorSource(from: "source"), RUMErrorSource.source) -// XCTAssertEqual(RUMErrorSource(from: "network"), RUMErrorSource.network) -// XCTAssertEqual(RUMErrorSource(from: "webview"), RUMErrorSource.webview) -// XCTAssertEqual(RUMErrorSource(from: "console"), RUMErrorSource.console) -// XCTAssertEqual(RUMErrorSource(from: "foobar"), RUMErrorSource.custom) + XCTAssertEqual(RUMErrorSource(from: "source"), RUMErrorSource.source) + XCTAssertEqual(RUMErrorSource(from: "network"), RUMErrorSource.network) + XCTAssertEqual(RUMErrorSource(from: "webview"), RUMErrorSource.webview) + XCTAssertEqual(RUMErrorSource(from: "console"), RUMErrorSource.console) + XCTAssertEqual(RUMErrorSource(from: "foobar"), RUMErrorSource.custom) } private func nanoTimeToDate(timestampNs: Int64) -> Date { From 511de06b6e7244206d38257ed846bdadf349ca7e Mon Sep 17 00:00:00 2001 From: louiszawadzki Date: Wed, 13 Sep 2023 14:10:19 +0200 Subject: [PATCH 22/28] Reenable ErrorSource iOS tests --- packages/core/ios/Tests/DdRumTests.swift | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/packages/core/ios/Tests/DdRumTests.swift b/packages/core/ios/Tests/DdRumTests.swift index 393dd5fb5..1c3304de3 100644 --- a/packages/core/ios/Tests/DdRumTests.swift +++ b/packages/core/ios/Tests/DdRumTests.swift @@ -269,11 +269,11 @@ internal class DdRumTests: XCTestCase { } func testRumErrorSourceMapping() throws { - XCTAssertEqual(RUMErrorSource(from: "source"), RUMErrorSource.source) - XCTAssertEqual(RUMErrorSource(from: "network"), RUMErrorSource.network) - XCTAssertEqual(RUMErrorSource(from: "webview"), RUMErrorSource.webview) - XCTAssertEqual(RUMErrorSource(from: "console"), RUMErrorSource.console) - XCTAssertEqual(RUMErrorSource(from: "foobar"), RUMErrorSource.custom) + XCTAssertEqual(RUMErrorSource(from: "source"), RUMErrorSource.source) + XCTAssertEqual(RUMErrorSource(from: "network"), RUMErrorSource.network) + XCTAssertEqual(RUMErrorSource(from: "webview"), RUMErrorSource.webview) + XCTAssertEqual(RUMErrorSource(from: "console"), RUMErrorSource.console) + XCTAssertEqual(RUMErrorSource(from: "foobar"), RUMErrorSource.custom) } private func nanoTimeToDate(timestampNs: Int64) -> Date { From eb2eeead52da9a7596970f7b6dd1ec64b33e0d05 Mon Sep 17 00:00:00 2001 From: louiszawadzki Date: Thu, 14 Sep 2023 11:08:15 +0200 Subject: [PATCH 23/28] Memoize webview message emitter --- .../ios/Sources/DdSdkImplementation.swift | 9 ++++---- packages/core/ios/Tests/DdSdkTests.swift | 21 +++++++++++++++++++ 2 files changed, 26 insertions(+), 4 deletions(-) diff --git a/packages/core/ios/Sources/DdSdkImplementation.swift b/packages/core/ios/Sources/DdSdkImplementation.swift index b7b4821ef..d97445df5 100644 --- a/packages/core/ios/Sources/DdSdkImplementation.swift +++ b/packages/core/ios/Sources/DdSdkImplementation.swift @@ -27,7 +27,8 @@ public class DdSdkImplementation: NSObject { let mainDispatchQueue: DispatchQueueType let RUMMonitorProvider: () -> RUMMonitorProtocol let RUMMonitorInternalProvider: () -> RUMMonitorInternalProtocol? - + var webviewMessageEmitter: InternalExtension.AbstractMessageEmitter? + private let jsLongTaskThresholdInSeconds: TimeInterval = 0.1; @objc @@ -101,6 +102,8 @@ public class DdSdkImplementation: NSObject { if sdkConfiguration.nativeCrashReportEnabled ?? false { CrashReporting.enable(in: core) } + + self.webviewMessageEmitter = WebViewTracking._internal.messageEmitter(in: core) overrideReactNativeTelemetry(rnConfiguration: sdkConfiguration, core: core) } @@ -149,9 +152,7 @@ public class DdSdkImplementation: NSObject { @objc public func consumeWebviewEvent(message: NSString, resolve:RCTPromiseResolveBlock, reject:RCTPromiseRejectBlock) -> Void { do{ - // TODO: memoize message emitter once core is initialized - let messageEmitter = WebViewTracking._internal.messageEmitter(in: CoreRegistry.default) - try messageEmitter.send(body: message) + try self.webviewMessageEmitter?.send(body: message) } catch { Datadog._internal.telemetry.error(id: "datadog_react_native:\(error.localizedDescription)", message: "The message being sent was:\(message)" as String, kind: "WebViewEventBridgeError" as String, stack: String(describing: error) as String) } diff --git a/packages/core/ios/Tests/DdSdkTests.swift b/packages/core/ios/Tests/DdSdkTests.swift index df4a4c840..557f0c18d 100644 --- a/packages/core/ios/Tests/DdSdkTests.swift +++ b/packages/core/ios/Tests/DdSdkTests.swift @@ -874,6 +874,22 @@ internal class DdSdkTests: XCTestCase { Datadog.internalFlushAndDeinitialize() } + + func testConsumeWebviewEventBeforeInitialization() throws { + XCTAssertNoThrow(try DdSdkImplementation().consumeWebviewEvent(message: "TestMessage", resolve: mockResolve, reject: mockReject)) + } + + func testConsumeWebviewEvent() throws { + let sdk = DdSdkImplementation() + let configuration: DdSdkConfiguration = .mockAny() + let core = MockDatadogCore() + + sdk.enableFeatures(sdkConfiguration: configuration, core: core) + + sdk.consumeWebviewEvent(message: "{\"eventType\":\"RUM\",\"event\":{\"blabla\":\"custom message\"}}", resolve: mockResolve, reject: mockReject) + + XCTAssertNotNil(core.baggages["browser-rum-event"]) + } } private final class MockJSRefreshRateMonitor: RefreshRateMonitor { @@ -998,10 +1014,15 @@ internal class MockDatadogCore: DatadogCoreProtocol { case .configuration(let configuration) = telemetry { self.configuration = configuration } + + if case .baggage(let key, let baggage) = message { + self.baggages[key] = baggage + } } private(set) var configuration: ConfigurationTelemetry? private(set) var features: [String: DatadogFeature] = [:] + private(set) var baggages: [String: Any] = [:] func register(feature: T) throws where T : DatadogFeature { features[T.name] = feature From 221fbb2318a4dad29e71417fb48dcd0a6e6e16d6 Mon Sep 17 00:00:00 2001 From: louiszawadzki Date: Tue, 19 Sep 2023 16:20:23 +0200 Subject: [PATCH 24/28] Make new arch example app compile on Android --- .../android/app/build.gradle | 9 ++++++ example-new-architecture/metro.config.js | 32 +++++++++++++++++++ 2 files changed, 41 insertions(+) diff --git a/example-new-architecture/android/app/build.gradle b/example-new-architecture/android/app/build.gradle index 972cde170..26e1bd033 100644 --- a/example-new-architecture/android/app/build.gradle +++ b/example-new-architecture/android/app/build.gradle @@ -153,6 +153,15 @@ dependencies { } else { implementation jscFlavor } + + constraints { + implementation("org.jetbrains.kotlin:kotlin-stdlib-jdk7:1.8.0") { + because("kotlin-stdlib-jdk7 is now a part of kotlin-stdlib") + } + implementation("org.jetbrains.kotlin:kotlin-stdlib-jdk8:1.8.0") { + because("kotlin-stdlib-jdk8 is now a part of kotlin-stdlib") + } + } } apply from: file("../../node_modules/@react-native-community/cli-platform-android/native_modules.gradle"); applyNativeModulesAppBuildGradle(project) diff --git a/example-new-architecture/metro.config.js b/example-new-architecture/metro.config.js index b011c48c7..2f9c5a36e 100644 --- a/example-new-architecture/metro.config.js +++ b/example-new-architecture/metro.config.js @@ -1,4 +1,36 @@ +const path = require('path'); +const exclusionList = require('metro-config/src/defaults/exclusionList'); +const escape = require('escape-string-regexp'); +const pakCore = require('../packages/core/package.json'); + +const root = path.resolve(__dirname, '..'); + +const modules = Object.keys({ + ...pakCore.peerDependencies, +}); + module.exports = { + projectRoot: __dirname, + watchFolders: [root], + + // We need to make sure that only one version is loaded for peerDependencies + // So we blacklist them at the root, and alias them to the versions in example's node_modules + // This block is very important, because otherwise things like React can be packed multiple times + // while it should be only one React instance in the runtime. exclusionList relies on the modules which are + // declared as peer dependencies in the core package. + resolver: { + blacklistRE: exclusionList( + modules.map( + m => new RegExp(`^${escape(path.join(root, 'node_modules', m))}\\/.*$`), + ), + ), + + extraNodeModules: modules.reduce((acc, name) => { + acc[name] = path.join(__dirname, 'node_modules', name); + return acc; + }, {}), + }, + transformer: { getTransformOptions: async () => ({ transform: { From 53c39fe7ea354a3b1fcc8a5926bc63c18c8e0ffa Mon Sep 17 00:00:00 2001 From: louiszawadzki Date: Tue, 19 Sep 2023 16:20:35 +0200 Subject: [PATCH 25/28] Make example app compile on Android --- example/android/app/build.gradle | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/example/android/app/build.gradle b/example/android/app/build.gradle index 65e1fc93a..ebd59c582 100644 --- a/example/android/app/build.gradle +++ b/example/android/app/build.gradle @@ -166,6 +166,15 @@ dependencies { } else { implementation jscFlavor } + + constraints { + implementation("org.jetbrains.kotlin:kotlin-stdlib-jdk7:1.8.0") { + because("kotlin-stdlib-jdk7 is now a part of kotlin-stdlib") + } + implementation("org.jetbrains.kotlin:kotlin-stdlib-jdk8:1.8.0") { + because("kotlin-stdlib-jdk8 is now a part of kotlin-stdlib") + } + } } apply from: file("../../node_modules/@react-native-community/cli-platform-android/native_modules.gradle"); applyNativeModulesAppBuildGradle(project) From b8eeb997d1ab14e0f858f8510a18faf0b20fbcf5 Mon Sep 17 00:00:00 2001 From: louiszawadzki Date: Tue, 19 Sep 2023 17:18:12 +0200 Subject: [PATCH 26/28] Use backed fields for android proxies --- .../datadog/reactnative/DatadogSDKWrapper.kt | 49 ++++++++++--------- 1 file changed, 25 insertions(+), 24 deletions(-) diff --git a/packages/core/android/src/main/kotlin/com/datadog/reactnative/DatadogSDKWrapper.kt b/packages/core/android/src/main/kotlin/com/datadog/reactnative/DatadogSDKWrapper.kt index e2b5b89cc..d037f8bdd 100644 --- a/packages/core/android/src/main/kotlin/com/datadog/reactnative/DatadogSDKWrapper.kt +++ b/packages/core/android/src/main/kotlin/com/datadog/reactnative/DatadogSDKWrapper.kt @@ -8,6 +8,7 @@ package com.datadog.reactnative import android.content.Context import com.datadog.android.Datadog +import com.datadog.android._InternalProxy import com.datadog.android.core.configuration.Configuration import com.datadog.android.log.Logs import com.datadog.android.log.LogsConfiguration @@ -22,15 +23,27 @@ import com.datadog.android.webview.WebViewTracking internal class DatadogSDKWrapper : DatadogWrapper { - // lazy here is on purpose. The thing is that this class will be instantiated even before - // Sdk.initialize is called, but telemetry proxy can be created only after SDK is initialized. - private val telemetryProxy by lazy { Datadog._internalProxy() } + // We use Kotlin backing field here to initialize once the telemetry proxy + // and make sure it is only after SDK is initialized. + private var telemetryProxy: _InternalProxy._TelemetryProxy? = null + get() { + if (field == null && isInitialized()) { + field = Datadog._internalProxy()._telemetry + } - // lazy here is on purpose. The thing is that this class will be instantiated even before - // Sdk.initialize is called, but webview proxy can be created only after SDK is initialized. - private val webViewProxy by lazy { - WebViewTracking._InternalWebViewProxy(Datadog.getInstance()) - } + return field + } + + // We use Kotlin backing field here to initialize once the telemetry proxy + // and make sure it is only after SDK is initialized. + private var webViewProxy: WebViewTracking._InternalWebViewProxy? = null + get() { + if (field == null && isInitialized()) { + field = WebViewTracking._InternalWebViewProxy(Datadog.getInstance()) + } + + return field + } override fun setVerbosity(level: Int) { Datadog.setVerbosity(level) @@ -77,31 +90,19 @@ internal class DatadogSDKWrapper : DatadogWrapper { } override fun telemetryDebug(message: String) { - // Do not initialize the telemetry proxy before SDK is initialized - if (isInitialized()) { - telemetryProxy._telemetry.debug(message) - } + telemetryProxy?.debug(message) } override fun telemetryError(message: String, stack: String?, kind: String?) { - // Do not initialize the telemetry proxy before SDK is initialized - if (isInitialized()) { - telemetryProxy._telemetry.error(message, stack, kind) - } + telemetryProxy?.error(message, stack, kind) } override fun telemetryError(message: String, throwable: Throwable?) { - // Do not initialize the telemetry proxy before SDK is initialized - if (isInitialized()) { - telemetryProxy._telemetry.error(message, throwable) - } + telemetryProxy?.error(message, throwable) } override fun consumeWebviewEvent(message: String) { - // Do not initialize the webview proxy before SDK is initialized - if (isInitialized()) { - webViewProxy.consumeWebviewEvent(message) - } + webViewProxy?.consumeWebviewEvent(message) } override fun isInitialized(): Boolean { From eee8f6918245b3eb149aed6673c6191f09ce6ae0 Mon Sep 17 00:00:00 2001 From: louiszawadzki Date: Wed, 20 Sep 2023 14:18:29 +0200 Subject: [PATCH 27/28] Update iOS SDK to 2.2.1 --- example-new-architecture/ios/Podfile.lock | 14 +++++------ example/ios/Podfile.lock | 26 ++++++++++----------- packages/core/DatadogSDKReactNative.podspec | 12 +++++----- 3 files changed, 26 insertions(+), 26 deletions(-) diff --git a/example-new-architecture/ios/Podfile.lock b/example-new-architecture/ios/Podfile.lock index 2dbd3f333..8d125979a 100644 --- a/example-new-architecture/ios/Podfile.lock +++ b/example-new-architecture/ios/Podfile.lock @@ -12,12 +12,12 @@ PODS: - DatadogRUM (2.2.1): - DatadogInternal (= 2.2.1) - DatadogSDKReactNative (1.8.5): - - DatadogCore (~> 2.2.0) - - DatadogCrashReporting (~> 2.2.0) - - DatadogLogs (~> 2.2.0) - - DatadogRUM (~> 2.2.0) - - DatadogTrace (~> 2.2.0) - - DatadogWebViewTracking (~> 2.2.0) + - DatadogCore (~> 2.2.1) + - DatadogCrashReporting (~> 2.2.1) + - DatadogLogs (~> 2.2.1) + - DatadogRUM (~> 2.2.1) + - DatadogTrace (~> 2.2.1) + - DatadogWebViewTracking (~> 2.2.1) - RCT-Folly (= 2021.07.22.00) - RCTRequired - RCTTypeSafety @@ -964,7 +964,7 @@ SPEC CHECKSUMS: DatadogInternal: bfa2b823bd47511425d696d36a1bc77c4d06b2f4 DatadogLogs: a0eafa7bd2103511eac07bcd2ff95c851123e29b DatadogRUM: 1e027ccfe4ba1eb81a185f3c58e0909bb12811be - DatadogSDKReactNative: eab3c6708f09e9bf877bf0fb0b861663812f1659 + DatadogSDKReactNative: 1c9c8a495f19bc77059c4d131d5b3be91b34bb7e DatadogTrace: 74dc91a7a80e746dc4ef1af6d0db1735b5bfd993 DatadogWebViewTracking: 9ca93299a2c900c68ba080f6e800fae1fa3c6b61 DoubleConversion: 5189b271737e1565bdce30deb4a08d647e3f5f54 diff --git a/example/ios/Podfile.lock b/example/ios/Podfile.lock index 090585c72..4744edc89 100644 --- a/example/ios/Podfile.lock +++ b/example/ios/Podfile.lock @@ -11,20 +11,20 @@ PODS: - DatadogRUM (2.2.1): - DatadogInternal (= 2.2.1) - DatadogSDKReactNative (1.8.5): - - DatadogCore (~> 2.2.0) - - DatadogCrashReporting (~> 2.2.0) - - DatadogLogs (~> 2.2.0) - - DatadogRUM (~> 2.2.0) - - DatadogTrace (~> 2.2.0) - - DatadogWebViewTracking (~> 2.2.0) + - DatadogCore (~> 2.2.1) + - DatadogCrashReporting (~> 2.2.1) + - DatadogLogs (~> 2.2.1) + - DatadogRUM (~> 2.2.1) + - DatadogTrace (~> 2.2.1) + - DatadogWebViewTracking (~> 2.2.1) - React-Core - DatadogSDKReactNative/Tests (1.8.5): - - DatadogCore (~> 2.2.0) - - DatadogCrashReporting (~> 2.2.0) - - DatadogLogs (~> 2.2.0) - - DatadogRUM (~> 2.2.0) - - DatadogTrace (~> 2.2.0) - - DatadogWebViewTracking (~> 2.2.0) + - DatadogCore (~> 2.2.1) + - DatadogCrashReporting (~> 2.2.1) + - DatadogLogs (~> 2.2.1) + - DatadogRUM (~> 2.2.1) + - DatadogTrace (~> 2.2.1) + - DatadogWebViewTracking (~> 2.2.1) - React-Core - DatadogTrace (2.2.1): - DatadogInternal (= 2.2.1) @@ -561,7 +561,7 @@ SPEC CHECKSUMS: DatadogInternal: bfa2b823bd47511425d696d36a1bc77c4d06b2f4 DatadogLogs: a0eafa7bd2103511eac07bcd2ff95c851123e29b DatadogRUM: 1e027ccfe4ba1eb81a185f3c58e0909bb12811be - DatadogSDKReactNative: 99327113b9cc8c8b024e2f23a67e9ebc5929e52b + DatadogSDKReactNative: 6f16f15e8b3d5a60c5799d604843a0feb2010c9b DatadogTrace: 74dc91a7a80e746dc4ef1af6d0db1735b5bfd993 DatadogWebViewTracking: 9ca93299a2c900c68ba080f6e800fae1fa3c6b61 DoubleConversion: 5189b271737e1565bdce30deb4a08d647e3f5f54 diff --git a/packages/core/DatadogSDKReactNative.podspec b/packages/core/DatadogSDKReactNative.podspec index e8ebb02b8..25a954606 100644 --- a/packages/core/DatadogSDKReactNative.podspec +++ b/packages/core/DatadogSDKReactNative.podspec @@ -17,12 +17,12 @@ Pod::Spec.new do |s| s.source_files = "ios/Sources/*.{h,m,mm,swift}" s.dependency "React-Core" - s.dependency 'DatadogCore', '~> 2.2.0' - s.dependency 'DatadogLogs', '~> 2.2.0' - s.dependency 'DatadogTrace', '~> 2.2.0' - s.dependency 'DatadogRUM', '~> 2.2.0' - s.dependency 'DatadogCrashReporting', '~> 2.2.0' - s.dependency 'DatadogWebViewTracking', '~> 2.2.0' + s.dependency 'DatadogCore', '~> 2.2.1' + s.dependency 'DatadogLogs', '~> 2.2.1' + s.dependency 'DatadogTrace', '~> 2.2.1' + s.dependency 'DatadogRUM', '~> 2.2.1' + s.dependency 'DatadogCrashReporting', '~> 2.2.1' + s.dependency 'DatadogWebViewTracking', '~> 2.2.1' s.test_spec 'Tests' do |test_spec| test_spec.source_files = 'ios/Tests/*.swift' From e2ef3067a265413d1c5ab6b78724cd0d055889cb Mon Sep 17 00:00:00 2001 From: louiszawadzki Date: Wed, 20 Sep 2023 15:32:08 +0200 Subject: [PATCH 28/28] Remove force unwrap for attributes --- .../kotlin/com/datadog/reactnative/DdSdkImplementation.kt | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/packages/core/android/src/main/kotlin/com/datadog/reactnative/DdSdkImplementation.kt b/packages/core/android/src/main/kotlin/com/datadog/reactnative/DdSdkImplementation.kt index fac7489ab..bcafd72c3 100644 --- a/packages/core/android/src/main/kotlin/com/datadog/reactnative/DdSdkImplementation.kt +++ b/packages/core/android/src/main/kotlin/com/datadog/reactnative/DdSdkImplementation.kt @@ -324,9 +324,8 @@ class DdSdkImplementation( } configBuilder.setAdditionalConfiguration( additionalConfig?.filterValues { it != null }?.mapValues { - it.value!! - } - ?: emptyMap() + it.value + } as Map? ?: emptyMap() ) configBuilder.setCrashReportsEnabled(configuration.nativeCrashReportEnabled ?: false)