diff --git a/dd-sdk-android/apiSurface b/dd-sdk-android/apiSurface index b6ba829dcf..266595e849 100644 --- a/dd-sdk-android/apiSurface +++ b/dd-sdk-android/apiSurface @@ -405,7 +405,7 @@ enum com.datadog.android.rum.RumResourceKind interface com.datadog.android.rum.RumSessionListener fun onSessionStarted(String, Boolean) data class com.datadog.android.rum.model.ActionEvent - constructor(kotlin.Long, Application, kotlin.String? = null, ActionEventSession, Source? = null, View, Usr? = null, Connectivity? = null, Synthetics? = null, CiTest? = null, Dd, Context? = null, Action) + constructor(kotlin.Long, Application, kotlin.String? = null, ActionEventSession, Source? = null, View, Usr? = null, Connectivity? = null, Synthetics? = null, CiTest? = null, Os? = null, Device? = null, Dd, Context? = null, Action) val type: kotlin.String fun toJson(): com.google.gson.JsonElement companion object @@ -445,6 +445,16 @@ data class com.datadog.android.rum.model.ActionEvent fun toJson(): com.google.gson.JsonElement companion object fun fromJson(kotlin.String): CiTest + data class Os + constructor(kotlin.String, kotlin.String, kotlin.String) + fun toJson(): com.google.gson.JsonElement + companion object + fun fromJson(kotlin.String): Os + data class Device + constructor(DeviceType, kotlin.String? = null, kotlin.String? = null, kotlin.String? = null) + fun toJson(): com.google.gson.JsonElement + companion object + fun fromJson(kotlin.String): Device data class Dd constructor(DdSession? = null, kotlin.String? = null) val formatVersion: kotlin.Long @@ -536,6 +546,18 @@ data class com.datadog.android.rum.model.ActionEvent fun toJson(): com.google.gson.JsonElement companion object fun fromJson(kotlin.String): Interface + enum DeviceType + constructor(kotlin.String) + - MOBILE + - DESKTOP + - TABLET + - TV + - GAMING_CONSOLE + - BOT + - OTHER + fun toJson(): com.google.gson.JsonElement + companion object + fun fromJson(kotlin.String): DeviceType enum ActionType constructor(kotlin.String) - CUSTOM @@ -556,7 +578,7 @@ data class com.datadog.android.rum.model.ActionEvent companion object fun fromJson(kotlin.String): Plan data class com.datadog.android.rum.model.ErrorEvent - constructor(kotlin.Long, Application, kotlin.String? = null, ErrorEventSession, ErrorEventSource? = null, View, Usr? = null, Connectivity? = null, Synthetics? = null, CiTest? = null, Dd, Context? = null, Error, Action? = null) + constructor(kotlin.Long, Application, kotlin.String? = null, ErrorEventSession, ErrorEventSource? = null, View, Usr? = null, Connectivity? = null, Synthetics? = null, CiTest? = null, Os? = null, Device? = null, Dd, Context? = null, Error, Action? = null) val type: kotlin.String fun toJson(): com.google.gson.JsonElement companion object @@ -596,6 +618,16 @@ data class com.datadog.android.rum.model.ErrorEvent fun toJson(): com.google.gson.JsonElement companion object fun fromJson(kotlin.String): CiTest + data class Os + constructor(kotlin.String, kotlin.String, kotlin.String) + fun toJson(): com.google.gson.JsonElement + companion object + fun fromJson(kotlin.String): Os + data class Device + constructor(DeviceType, kotlin.String? = null, kotlin.String? = null, kotlin.String? = null) + fun toJson(): com.google.gson.JsonElement + companion object + fun fromJson(kotlin.String): Device data class Dd constructor(DdSession? = null, kotlin.String? = null) val formatVersion: kotlin.Long @@ -677,6 +709,18 @@ data class com.datadog.android.rum.model.ErrorEvent fun toJson(): com.google.gson.JsonElement companion object fun fromJson(kotlin.String): Interface + enum DeviceType + constructor(kotlin.String) + - MOBILE + - DESKTOP + - TABLET + - TV + - GAMING_CONSOLE + - BOT + - OTHER + fun toJson(): com.google.gson.JsonElement + companion object + fun fromJson(kotlin.String): DeviceType enum ErrorSource constructor(kotlin.String) - NETWORK @@ -745,7 +789,7 @@ data class com.datadog.android.rum.model.ErrorEvent companion object fun fromJson(kotlin.String): ProviderType data class com.datadog.android.rum.model.LongTaskEvent - constructor(kotlin.Long, Application, kotlin.String? = null, LongTaskEventSession, Source? = null, View, Usr? = null, Connectivity? = null, Synthetics? = null, CiTest? = null, Dd, Context? = null, LongTask, Action? = null) + constructor(kotlin.Long, Application, kotlin.String? = null, LongTaskEventSession, Source? = null, View, Usr? = null, Connectivity? = null, Synthetics? = null, CiTest? = null, Os? = null, Device? = null, Dd, Context? = null, LongTask, Action? = null) val type: kotlin.String fun toJson(): com.google.gson.JsonElement companion object @@ -756,7 +800,7 @@ data class com.datadog.android.rum.model.LongTaskEvent companion object fun fromJson(kotlin.String): Application data class LongTaskEventSession - constructor(kotlin.String, Type, kotlin.Boolean? = null) + constructor(kotlin.String, LongTaskEventSessionType, kotlin.Boolean? = null) fun toJson(): com.google.gson.JsonElement companion object fun fromJson(kotlin.String): LongTaskEventSession @@ -785,6 +829,16 @@ data class com.datadog.android.rum.model.LongTaskEvent fun toJson(): com.google.gson.JsonElement companion object fun fromJson(kotlin.String): CiTest + data class Os + constructor(kotlin.String, kotlin.String, kotlin.String) + fun toJson(): com.google.gson.JsonElement + companion object + fun fromJson(kotlin.String): Os + data class Device + constructor(DeviceType, kotlin.String? = null, kotlin.String? = null, kotlin.String? = null) + fun toJson(): com.google.gson.JsonElement + companion object + fun fromJson(kotlin.String): Device data class Dd constructor(DdSession? = null, kotlin.String? = null) val formatVersion: kotlin.Long @@ -826,14 +880,14 @@ data class com.datadog.android.rum.model.LongTaskEvent fun toJson(): com.google.gson.JsonElement companion object fun fromJson(kotlin.String): Source - enum Type + enum LongTaskEventSessionType constructor(kotlin.String) - USER - SYNTHETICS - CI_TEST fun toJson(): com.google.gson.JsonElement companion object - fun fromJson(kotlin.String): Type + fun fromJson(kotlin.String): LongTaskEventSessionType enum Status constructor(kotlin.String) - CONNECTED @@ -856,6 +910,18 @@ data class com.datadog.android.rum.model.LongTaskEvent fun toJson(): com.google.gson.JsonElement companion object fun fromJson(kotlin.String): Interface + enum DeviceType + constructor(kotlin.String) + - MOBILE + - DESKTOP + - TABLET + - TV + - GAMING_CONSOLE + - BOT + - OTHER + fun toJson(): com.google.gson.JsonElement + companion object + fun fromJson(kotlin.String): DeviceType enum Plan constructor(kotlin.Number) - PLAN_1 @@ -864,7 +930,7 @@ data class com.datadog.android.rum.model.LongTaskEvent companion object fun fromJson(kotlin.String): Plan data class com.datadog.android.rum.model.ResourceEvent - constructor(kotlin.Long, Application, kotlin.String? = null, ResourceEventSession, Source? = null, View, Usr? = null, Connectivity? = null, Synthetics? = null, CiTest? = null, Dd, Context? = null, Resource, Action? = null) + constructor(kotlin.Long, Application, kotlin.String? = null, ResourceEventSession, Source? = null, View, Usr? = null, Connectivity? = null, Synthetics? = null, CiTest? = null, Os? = null, Device? = null, Dd, Context? = null, Resource, Action? = null) val type: kotlin.String fun toJson(): com.google.gson.JsonElement companion object @@ -904,6 +970,16 @@ data class com.datadog.android.rum.model.ResourceEvent fun toJson(): com.google.gson.JsonElement companion object fun fromJson(kotlin.String): CiTest + data class Os + constructor(kotlin.String, kotlin.String, kotlin.String) + fun toJson(): com.google.gson.JsonElement + companion object + fun fromJson(kotlin.String): Os + data class Device + constructor(DeviceType, kotlin.String? = null, kotlin.String? = null, kotlin.String? = null) + fun toJson(): com.google.gson.JsonElement + companion object + fun fromJson(kotlin.String): Device data class Dd constructor(DdSession? = null, kotlin.String? = null, kotlin.String? = null, kotlin.String? = null) val formatVersion: kotlin.Long @@ -1010,6 +1086,18 @@ data class com.datadog.android.rum.model.ResourceEvent fun toJson(): com.google.gson.JsonElement companion object fun fromJson(kotlin.String): Interface + enum DeviceType + constructor(kotlin.String) + - MOBILE + - DESKTOP + - TABLET + - TV + - GAMING_CONSOLE + - BOT + - OTHER + fun toJson(): com.google.gson.JsonElement + companion object + fun fromJson(kotlin.String): DeviceType enum ResourceType constructor(kotlin.String) - DOCUMENT @@ -1064,7 +1152,7 @@ data class com.datadog.android.rum.model.ResourceEvent companion object fun fromJson(kotlin.String): ProviderType data class com.datadog.android.rum.model.ViewEvent - constructor(kotlin.Long, Application, kotlin.String? = null, ViewEventSession, Source? = null, View, Usr? = null, Connectivity? = null, Synthetics? = null, CiTest? = null, Dd, Context? = null) + constructor(kotlin.Long, Application, kotlin.String? = null, ViewEventSession, Source? = null, View, Usr? = null, Connectivity? = null, Synthetics? = null, CiTest? = null, Os? = null, Device? = null, Dd, Context? = null) val type: kotlin.String fun toJson(): com.google.gson.JsonElement companion object @@ -1075,7 +1163,7 @@ data class com.datadog.android.rum.model.ViewEvent companion object fun fromJson(kotlin.String): Application data class ViewEventSession - constructor(kotlin.String, Type, kotlin.Boolean? = null) + constructor(kotlin.String, ViewEventSessionType, kotlin.Boolean? = null) fun toJson(): com.google.gson.JsonElement companion object fun fromJson(kotlin.String): ViewEventSession @@ -1104,6 +1192,16 @@ data class com.datadog.android.rum.model.ViewEvent fun toJson(): com.google.gson.JsonElement companion object fun fromJson(kotlin.String): CiTest + data class Os + constructor(kotlin.String, kotlin.String, kotlin.String) + fun toJson(): com.google.gson.JsonElement + companion object + fun fromJson(kotlin.String): Os + data class Device + constructor(DeviceType, kotlin.String? = null, kotlin.String? = null, kotlin.String? = null) + fun toJson(): com.google.gson.JsonElement + companion object + fun fromJson(kotlin.String): Device data class Dd constructor(DdSession? = null, kotlin.String? = null, kotlin.Long) val formatVersion: kotlin.Long @@ -1175,14 +1273,14 @@ data class com.datadog.android.rum.model.ViewEvent fun toJson(): com.google.gson.JsonElement companion object fun fromJson(kotlin.String): Source - enum Type + enum ViewEventSessionType constructor(kotlin.String) - USER - SYNTHETICS - CI_TEST fun toJson(): com.google.gson.JsonElement companion object - fun fromJson(kotlin.String): Type + fun fromJson(kotlin.String): ViewEventSessionType enum LoadingType constructor(kotlin.String) - INITIAL_LOAD @@ -1218,6 +1316,18 @@ data class com.datadog.android.rum.model.ViewEvent fun toJson(): com.google.gson.JsonElement companion object fun fromJson(kotlin.String): Interface + enum DeviceType + constructor(kotlin.String) + - MOBILE + - DESKTOP + - TABLET + - TV + - GAMING_CONSOLE + - BOT + - OTHER + fun toJson(): com.google.gson.JsonElement + companion object + fun fromJson(kotlin.String): DeviceType enum Plan constructor(kotlin.Number) - PLAN_1 diff --git a/dd-sdk-android/src/main/json/rum/_common-schema.json b/dd-sdk-android/src/main/json/rum/_common-schema.json index 783e3abd3f..bc163b2379 100644 --- a/dd-sdk-android/src/main/json/rum/_common-schema.json +++ b/dd-sdk-android/src/main/json/rum/_common-schema.json @@ -199,6 +199,70 @@ }, "readOnly": true }, + "os": { + "type": "object", + "description": "Operating system properties", + "required": [ + "name", + "version", + "version_major" + ], + "properties": { + "name": { + "type": "string", + "description": "Operating system name, e.g. Android, iOS", + "readOnly": true + }, + "version": { + "type": "string", + "description": "Full operating system version, e.g. 8.1.1", + "readOnly": true + }, + "version_major": { + "type": "string", + "description": "Major operating system version, e.g. 8", + "readOnly": true + } + } + }, + "device": { + "type": "object", + "description": "Device properties", + "required": [ + "type" + ], + "properties": { + "type": { + "type": "string", + "description": "Device type info", + "enum": [ + "mobile", + "desktop", + "tablet", + "tv", + "gaming_console", + "bot", + "other" + ], + "readOnly": true + }, + "name": { + "type": "string", + "description": "Device marketing name, e.g. Xiaomi Redmi Note 8 Pro, Pixel 5, etc.", + "readOnly": true + }, + "model": { + "type": "string", + "description": "Device SKU model, e.g. Samsung SM-988GN, etc. Quite often name and model can be the same.", + "readOnly": true + }, + "brand": { + "type": "string", + "description": "Device marketing brand, e.g. Apple, OPPO, Xiaomi, etc.", + "readOnly": true + } + } + }, "_dd": { "type": "object", "description": "Internal properties", diff --git a/dd-sdk-android/src/main/kotlin/com/datadog/android/core/internal/CoreFeature.kt b/dd-sdk-android/src/main/kotlin/com/datadog/android/core/internal/CoreFeature.kt index 044317c176..70e631f5a5 100644 --- a/dd-sdk-android/src/main/kotlin/com/datadog/android/core/internal/CoreFeature.kt +++ b/dd-sdk-android/src/main/kotlin/com/datadog/android/core/internal/CoreFeature.kt @@ -31,7 +31,10 @@ import com.datadog.android.core.internal.persistence.file.batch.BatchFileHandler import com.datadog.android.core.internal.privacy.ConsentProvider import com.datadog.android.core.internal.privacy.NoOpConsentProvider import com.datadog.android.core.internal.privacy.TrackingConsentProvider +import com.datadog.android.core.internal.system.AndroidInfoProvider import com.datadog.android.core.internal.system.BroadcastReceiverSystemInfoProvider +import com.datadog.android.core.internal.system.DefaultAndroidInfoProvider +import com.datadog.android.core.internal.system.NoOpAndroidInfoProvider import com.datadog.android.core.internal.system.NoOpSystemInfoProvider import com.datadog.android.core.internal.system.SystemInfoProvider import com.datadog.android.core.internal.time.KronosTimeProvider @@ -148,6 +151,7 @@ internal object CoreFeature { internal lateinit var persistenceExecutorService: ExecutorService internal var localDataEncryption: Encryption? = null internal lateinit var webViewTrackingHosts: List + internal lateinit var androidInfoProvider: AndroidInfoProvider // TESTS ONLY, to prevent Kronos spinning sync threads in unit-tests internal var disableKronosBackgroundSync = false @@ -168,6 +172,7 @@ internal object CoreFeature { setupOkHttpClient(configuration) firstPartyHostDetector.addKnownHosts(configuration.firstPartyHosts) webViewTrackingHosts = configuration.webViewTrackingHosts + androidInfoProvider = DefaultAndroidInfoProvider(appContext) setupExecutors() // Time Provider timeProvider = KronosTimeProvider(kronosClock) @@ -261,7 +266,8 @@ internal object CoreFeature { UserInfoDeserializer(sdkLogger), sdkLogger, timeProvider, - BatchFileHandler.create(sdkLogger, localDataEncryption) + BatchFileHandler.create(sdkLogger, localDataEncryption), + androidInfoProvider = androidInfoProvider ) ndkCrashHandler.prepareData() } @@ -462,6 +468,7 @@ internal object CoreFeature { timeProvider = NoOpTimeProvider() trackingConsentProvider = NoOpConsentProvider() userInfoProvider = NoOpMutableUserInfoProvider() + androidInfoProvider = NoOpAndroidInfoProvider() } // endregion diff --git a/dd-sdk-android/src/main/kotlin/com/datadog/android/core/internal/net/DataOkHttpUploaderV2.kt b/dd-sdk-android/src/main/kotlin/com/datadog/android/core/internal/net/DataOkHttpUploaderV2.kt index d6a13b5982..3fff255cd3 100644 --- a/dd-sdk-android/src/main/kotlin/com/datadog/android/core/internal/net/DataOkHttpUploaderV2.kt +++ b/dd-sdk-android/src/main/kotlin/com/datadog/android/core/internal/net/DataOkHttpUploaderV2.kt @@ -38,9 +38,9 @@ internal abstract class DataOkHttpUploaderV2( System.getProperty(SYSTEM_UA).let { if (it.isNullOrBlank()) { "Datadog/$sdkVersion " + - "(Linux; U; Android ${androidInfoProvider.getDeviceVersion()}; " + - "${androidInfoProvider.getDeviceModel()} " + - "Build/${androidInfoProvider.getDeviceBuildId()})" + "(Linux; U; Android ${androidInfoProvider.osVersion}; " + + "${androidInfoProvider.deviceModel} " + + "Build/${androidInfoProvider.deviceBuildId})" } else { it } diff --git a/dd-sdk-android/src/main/kotlin/com/datadog/android/core/internal/system/AndroidInfoProvider.kt b/dd-sdk-android/src/main/kotlin/com/datadog/android/core/internal/system/AndroidInfoProvider.kt index 25abb6f33d..d4b10a62ca 100644 --- a/dd-sdk-android/src/main/kotlin/com/datadog/android/core/internal/system/AndroidInfoProvider.kt +++ b/dd-sdk-android/src/main/kotlin/com/datadog/android/core/internal/system/AndroidInfoProvider.kt @@ -8,9 +8,19 @@ package com.datadog.android.core.internal.system internal interface AndroidInfoProvider { - fun getDeviceModel(): String + val deviceName: String - fun getDeviceBuildId(): String + val deviceBrand: String - fun getDeviceVersion(): String + val deviceModel: String + + val deviceType: DeviceType + + val deviceBuildId: String + + val osName: String + + val osMajorVersion: String + + val osVersion: String } diff --git a/dd-sdk-android/src/main/kotlin/com/datadog/android/core/internal/system/DefaultAndroidInfoProvider.kt b/dd-sdk-android/src/main/kotlin/com/datadog/android/core/internal/system/DefaultAndroidInfoProvider.kt new file mode 100644 index 0000000000..6dca671f9b --- /dev/null +++ b/dd-sdk-android/src/main/kotlin/com/datadog/android/core/internal/system/DefaultAndroidInfoProvider.kt @@ -0,0 +1,142 @@ +/* + * 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 2016-Present Datadog, Inc. + */ + +package com.datadog.android.core.internal.system + +import android.app.UiModeManager +import android.content.Context +import android.content.pm.PackageManager +import android.content.res.Configuration +import android.os.Build +import android.telephony.TelephonyManager +import java.util.Locale + +internal class DefaultAndroidInfoProvider( + appContext: Context, + sdkVersionProvider: BuildSdkVersionProvider = DefaultBuildSdkVersionProvider() +) : AndroidInfoProvider { + + // lazy is just to avoid breaking the tests (because without lazy type is resolved at the + // construction time and Build.MODEL is null in unit-tests) and also to have value resolved + // once to avoid different values for foldables during the application lifecycle + override val deviceType: DeviceType by lazy { + resolveDeviceType( + appContext, + sdkVersionProvider + ) + } + + override val deviceName: String + get() { + return if (deviceBrand.isEmpty()) { + deviceModel + } else if (deviceModel.contains(deviceBrand)) { + deviceModel + } else { + "$deviceBrand $deviceModel" + } + } + + override val deviceBrand: String + get() { + return Build.BRAND.replaceFirstChar { + if (it.isLowerCase()) it.titlecase(Locale.US) else it.toString() + } + } + + override val deviceModel: String + get() { + return Build.MODEL + } + + override val deviceBuildId: String + get() { + return Build.ID + } + + override val osName: String = "Android" + + override val osVersion: String + get() { + return Build.VERSION.RELEASE + } + + override val osMajorVersion: String + get() { + // result of split always have at least 1 element + @Suppress("UnsafeThirdPartyFunctionCall") + return osVersion.split('.').first() + } + + companion object { + + const val FEATURE_GOOGLE_ANDROID_TV = "com.google.android.tv" + const val MIN_TABLET_WIDTH_DP = 800 + + private fun resolveDeviceType( + appContext: Context, + sdkVersionProvider: BuildSdkVersionProvider + ): DeviceType { + return if (isTv(appContext, sdkVersionProvider)) { + DeviceType.TV + } else if (isTablet(appContext)) { + DeviceType.TABLET + } else if (isMobile(appContext)) { + DeviceType.MOBILE + } else { + DeviceType.OTHER + } + } + + private fun isTv( + appContext: Context, + sdkVersionProvider: BuildSdkVersionProvider + ): Boolean { + val uiModeManager = + appContext.getSystemService(Context.UI_MODE_SERVICE) as? UiModeManager + if (uiModeManager?.currentModeType == Configuration.UI_MODE_TYPE_TELEVISION) { + return true + } + + return hasTvFeature(appContext.packageManager, sdkVersionProvider) + } + + private fun hasTvFeature( + packageManager: PackageManager, + sdkVersionProvider: BuildSdkVersionProvider + ): Boolean { + val sdkVersion = sdkVersionProvider.version() + return when { + sdkVersion >= Build.VERSION_CODES.LOLLIPOP && + packageManager.hasSystemFeature(PackageManager.FEATURE_LEANBACK) -> true + sdkVersion < Build.VERSION_CODES.LOLLIPOP && + @Suppress("DEPRECATION") + packageManager.hasSystemFeature(PackageManager.FEATURE_TELEVISION) -> true + packageManager.hasSystemFeature(FEATURE_GOOGLE_ANDROID_TV) -> true + else -> false + } + } + + private fun isTablet( + appContext: Context + ): Boolean { + with(Build.MODEL.lowercase(Locale.US)) { + if (contains("tablet") || contains("sm-t")) return true + } + return appContext.resources.configuration.smallestScreenWidthDp >= MIN_TABLET_WIDTH_DP + } + + private fun isMobile( + appContext: Context + ): Boolean { + if (Build.MODEL.lowercase(Locale.US).contains("phone")) return true + + val telephonyManager = + appContext.getSystemService(Context.TELEPHONY_SERVICE) as? TelephonyManager + return telephonyManager?.phoneType != TelephonyManager.PHONE_TYPE_NONE + } + } +} diff --git a/dd-sdk-android/src/main/kotlin/com/datadog/android/core/internal/system/StaticAndroidInfoProvider.kt b/dd-sdk-android/src/main/kotlin/com/datadog/android/core/internal/system/DeviceType.kt similarity index 52% rename from dd-sdk-android/src/main/kotlin/com/datadog/android/core/internal/system/StaticAndroidInfoProvider.kt rename to dd-sdk-android/src/main/kotlin/com/datadog/android/core/internal/system/DeviceType.kt index 1fd85ee195..7a12d0572b 100644 --- a/dd-sdk-android/src/main/kotlin/com/datadog/android/core/internal/system/StaticAndroidInfoProvider.kt +++ b/dd-sdk-android/src/main/kotlin/com/datadog/android/core/internal/system/DeviceType.kt @@ -6,12 +6,10 @@ package com.datadog.android.core.internal.system -import android.os.Build - -internal object StaticAndroidInfoProvider : AndroidInfoProvider { - override fun getDeviceModel(): String = Build.MODEL - - override fun getDeviceBuildId(): String = Build.ID - - override fun getDeviceVersion(): String = Build.VERSION.RELEASE +internal enum class DeviceType { + MOBILE, + TABLET, + TV, + DESKTOP, + OTHER } diff --git a/dd-sdk-android/src/main/kotlin/com/datadog/android/core/internal/system/NoOpAndroidInfoProvider.kt b/dd-sdk-android/src/main/kotlin/com/datadog/android/core/internal/system/NoOpAndroidInfoProvider.kt new file mode 100644 index 0000000000..b2100c1acc --- /dev/null +++ b/dd-sdk-android/src/main/kotlin/com/datadog/android/core/internal/system/NoOpAndroidInfoProvider.kt @@ -0,0 +1,18 @@ +/* + * 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 2016-Present Datadog, Inc. + */ + +package com.datadog.android.core.internal.system + +internal class NoOpAndroidInfoProvider : AndroidInfoProvider { + override val deviceName: String = "" + override val deviceBrand: String = "" + override val deviceModel: String = "" + override val deviceType: DeviceType = DeviceType.MOBILE + override val deviceBuildId: String = "" + override val osName: String = "" + override val osMajorVersion: String = "" + override val osVersion: String = "" +} diff --git a/dd-sdk-android/src/main/kotlin/com/datadog/android/error/internal/CrashReportsFeature.kt b/dd-sdk-android/src/main/kotlin/com/datadog/android/error/internal/CrashReportsFeature.kt index 3aebc4f722..4b8e250411 100644 --- a/dd-sdk-android/src/main/kotlin/com/datadog/android/error/internal/CrashReportsFeature.kt +++ b/dd-sdk-android/src/main/kotlin/com/datadog/android/error/internal/CrashReportsFeature.kt @@ -12,7 +12,6 @@ import com.datadog.android.core.internal.CoreFeature import com.datadog.android.core.internal.SdkFeature import com.datadog.android.core.internal.net.DataUploader import com.datadog.android.core.internal.persistence.PersistenceStrategy -import com.datadog.android.core.internal.system.StaticAndroidInfoProvider import com.datadog.android.core.internal.utils.sdkLogger import com.datadog.android.log.internal.domain.LogGenerator import com.datadog.android.log.internal.net.LogsOkHttpUploaderV2 @@ -54,7 +53,7 @@ internal object CrashReportsFeature : SdkFeature() CoreFeature.sourceName, CoreFeature.sdkVersion, CoreFeature.okHttpClient, - StaticAndroidInfoProvider, + CoreFeature.androidInfoProvider, sdkLogger ) } diff --git a/dd-sdk-android/src/main/kotlin/com/datadog/android/rum/RumMonitor.kt b/dd-sdk-android/src/main/kotlin/com/datadog/android/rum/RumMonitor.kt index a482b801e5..1ce8a697da 100644 --- a/dd-sdk-android/src/main/kotlin/com/datadog/android/rum/RumMonitor.kt +++ b/dd-sdk-android/src/main/kotlin/com/datadog/android/rum/RumMonitor.kt @@ -318,7 +318,8 @@ interface RumMonitor { frameRateVitalMonitor = RumFeature.frameRateVitalMonitor, backgroundTrackingEnabled = RumFeature.backgroundEventTracking, timeProvider = CoreFeature.timeProvider, - sessionListener = sessionListener + sessionListener = sessionListener, + androidInfoProvider = CoreFeature.androidInfoProvider ) } } diff --git a/dd-sdk-android/src/main/kotlin/com/datadog/android/rum/internal/RumFeature.kt b/dd-sdk-android/src/main/kotlin/com/datadog/android/rum/internal/RumFeature.kt index 8bad33425c..dd4bedd0cc 100644 --- a/dd-sdk-android/src/main/kotlin/com/datadog/android/rum/internal/RumFeature.kt +++ b/dd-sdk-android/src/main/kotlin/com/datadog/android/rum/internal/RumFeature.kt @@ -18,7 +18,6 @@ import com.datadog.android.core.internal.SdkFeature import com.datadog.android.core.internal.event.NoOpEventMapper import com.datadog.android.core.internal.net.DataUploader import com.datadog.android.core.internal.persistence.PersistenceStrategy -import com.datadog.android.core.internal.system.StaticAndroidInfoProvider import com.datadog.android.core.internal.thread.NoOpScheduledExecutorService import com.datadog.android.core.internal.utils.devLogger import com.datadog.android.core.internal.utils.executeSafe @@ -138,7 +137,7 @@ internal object RumFeature : SdkFeature() { CoreFeature.sourceName, CoreFeature.sdkVersion, CoreFeature.okHttpClient, - StaticAndroidInfoProvider + CoreFeature.androidInfoProvider ) } diff --git a/dd-sdk-android/src/main/kotlin/com/datadog/android/rum/internal/domain/scope/RumActionScope.kt b/dd-sdk-android/src/main/kotlin/com/datadog/android/rum/internal/domain/scope/RumActionScope.kt index d220a1e7b6..3fd057f620 100644 --- a/dd-sdk-android/src/main/kotlin/com/datadog/android/rum/internal/domain/scope/RumActionScope.kt +++ b/dd-sdk-android/src/main/kotlin/com/datadog/android/rum/internal/domain/scope/RumActionScope.kt @@ -8,6 +8,7 @@ package com.datadog.android.rum.internal.domain.scope import com.datadog.android.core.internal.CoreFeature import com.datadog.android.core.internal.persistence.DataWriter +import com.datadog.android.core.internal.system.AndroidInfoProvider import com.datadog.android.rum.GlobalRum import com.datadog.android.rum.RumActionType import com.datadog.android.rum.internal.domain.RumContext @@ -29,7 +30,8 @@ internal class RumActionScope( serverTimeOffsetInMs: Long, inactivityThresholdMs: Long = ACTION_INACTIVITY_MS, maxDurationMs: Long = ACTION_MAX_DURATION_MS, - private val rumEventSourceProvider: RumEventSourceProvider + private val rumEventSourceProvider: RumEventSourceProvider, + private val androidInfoProvider: AndroidInfoProvider ) : RumScope { private val inactivityThresholdNs = TimeUnit.MILLISECONDS.toNanos(inactivityThresholdMs) @@ -215,6 +217,17 @@ internal class RumActionScope( email = user.email, additionalProperties = user.additionalProperties ), + os = ActionEvent.Os( + name = androidInfoProvider.osName, + version = androidInfoProvider.osVersion, + versionMajor = androidInfoProvider.osMajorVersion + ), + device = ActionEvent.Device( + type = androidInfoProvider.deviceType.toActionSchemaType(), + name = androidInfoProvider.deviceName, + model = androidInfoProvider.deviceModel, + brand = androidInfoProvider.deviceBrand + ), context = ActionEvent.Context(additionalProperties = attributes), dd = ActionEvent.Dd(session = ActionEvent.DdSession(plan = ActionEvent.Plan.PLAN_1)) ) @@ -233,7 +246,8 @@ internal class RumActionScope( parentScope: RumScope, event: RumRawEvent.StartAction, timestampOffset: Long, - eventSourceProvider: RumEventSourceProvider + eventSourceProvider: RumEventSourceProvider, + androidInfoProvider: AndroidInfoProvider ): RumScope { return RumActionScope( parentScope, @@ -243,7 +257,8 @@ internal class RumActionScope( event.name, event.attributes, timestampOffset, - rumEventSourceProvider = eventSourceProvider + rumEventSourceProvider = eventSourceProvider, + androidInfoProvider = androidInfoProvider ) } } diff --git a/dd-sdk-android/src/main/kotlin/com/datadog/android/rum/internal/domain/scope/RumApplicationScope.kt b/dd-sdk-android/src/main/kotlin/com/datadog/android/rum/internal/domain/scope/RumApplicationScope.kt index d35a661e98..1bdc08b64d 100644 --- a/dd-sdk-android/src/main/kotlin/com/datadog/android/rum/internal/domain/scope/RumApplicationScope.kt +++ b/dd-sdk-android/src/main/kotlin/com/datadog/android/rum/internal/domain/scope/RumApplicationScope.kt @@ -9,6 +9,7 @@ package com.datadog.android.rum.internal.domain.scope import com.datadog.android.core.internal.CoreFeature import com.datadog.android.core.internal.net.FirstPartyHostDetector import com.datadog.android.core.internal.persistence.DataWriter +import com.datadog.android.core.internal.system.AndroidInfoProvider import com.datadog.android.core.internal.time.TimeProvider import com.datadog.android.rum.RumSessionListener import com.datadog.android.rum.internal.domain.RumContext @@ -24,7 +25,8 @@ internal class RumApplicationScope( memoryVitalMonitor: VitalMonitor, frameRateVitalMonitor: VitalMonitor, timeProvider: TimeProvider, - sessionListener: RumSessionListener? + sessionListener: RumSessionListener?, + androidInfoProvider: AndroidInfoProvider ) : RumScope { private val rumEventSourceProvider = RumEventSourceProvider(CoreFeature.sourceName) @@ -39,7 +41,8 @@ internal class RumApplicationScope( frameRateVitalMonitor, timeProvider, sessionListener, - rumEventSourceProvider + rumEventSourceProvider, + androidInfoProvider = androidInfoProvider ) // region RumScope diff --git a/dd-sdk-android/src/main/kotlin/com/datadog/android/rum/internal/domain/scope/RumEventExt.kt b/dd-sdk-android/src/main/kotlin/com/datadog/android/rum/internal/domain/scope/RumEventExt.kt index 575261a238..d33db3a54c 100644 --- a/dd-sdk-android/src/main/kotlin/com/datadog/android/rum/internal/domain/scope/RumEventExt.kt +++ b/dd-sdk-android/src/main/kotlin/com/datadog/android/rum/internal/domain/scope/RumEventExt.kt @@ -7,6 +7,7 @@ package com.datadog.android.rum.internal.domain.scope +import com.datadog.android.core.internal.system.DeviceType import com.datadog.android.core.internal.utils.sdkLogger import com.datadog.android.core.model.NetworkInfo import com.datadog.android.log.internal.utils.errorWithTelemetry @@ -19,6 +20,7 @@ import com.datadog.android.rum.model.ActionEvent import com.datadog.android.rum.model.ErrorEvent import com.datadog.android.rum.model.LongTaskEvent import com.datadog.android.rum.model.ResourceEvent +import com.datadog.android.rum.model.ViewEvent import java.util.Locale internal fun String.toMethod(): ResourceEvent.Method { @@ -116,6 +118,8 @@ internal fun RumActionType.toSchemaType(): ActionEvent.ActionType { } } +// region NetworkInfo conversion + internal fun NetworkInfo.toResourceConnectivity(): ResourceEvent.Connectivity { val status = if (isConnected()) { ResourceEvent.Status.CONNECTED @@ -227,3 +231,59 @@ internal fun NetworkInfo.toLongTaskConnectivity(): LongTaskEvent.Connectivity { internal fun NetworkInfo.isConnected(): Boolean { return connectivity != NetworkInfo.Connectivity.NETWORK_NOT_CONNECTED } + +// endregion + +// region DeviceType conversion + +internal fun DeviceType.toViewSchemaType(): ViewEvent.DeviceType { + return when (this) { + DeviceType.MOBILE -> ViewEvent.DeviceType.MOBILE + DeviceType.TABLET -> ViewEvent.DeviceType.TABLET + DeviceType.TV -> ViewEvent.DeviceType.TV + DeviceType.DESKTOP -> ViewEvent.DeviceType.DESKTOP + else -> ViewEvent.DeviceType.OTHER + } +} + +internal fun DeviceType.toActionSchemaType(): ActionEvent.DeviceType { + return when (this) { + DeviceType.MOBILE -> ActionEvent.DeviceType.MOBILE + DeviceType.TABLET -> ActionEvent.DeviceType.TABLET + DeviceType.TV -> ActionEvent.DeviceType.TV + DeviceType.DESKTOP -> ActionEvent.DeviceType.DESKTOP + else -> ActionEvent.DeviceType.OTHER + } +} + +internal fun DeviceType.toLongTaskSchemaType(): LongTaskEvent.DeviceType { + return when (this) { + DeviceType.MOBILE -> LongTaskEvent.DeviceType.MOBILE + DeviceType.TABLET -> LongTaskEvent.DeviceType.TABLET + DeviceType.TV -> LongTaskEvent.DeviceType.TV + DeviceType.DESKTOP -> LongTaskEvent.DeviceType.DESKTOP + else -> LongTaskEvent.DeviceType.OTHER + } +} + +internal fun DeviceType.toResourceSchemaType(): ResourceEvent.DeviceType { + return when (this) { + DeviceType.MOBILE -> ResourceEvent.DeviceType.MOBILE + DeviceType.TABLET -> ResourceEvent.DeviceType.TABLET + DeviceType.TV -> ResourceEvent.DeviceType.TV + DeviceType.DESKTOP -> ResourceEvent.DeviceType.DESKTOP + else -> ResourceEvent.DeviceType.OTHER + } +} + +internal fun DeviceType.toErrorSchemaType(): ErrorEvent.DeviceType { + return when (this) { + DeviceType.MOBILE -> ErrorEvent.DeviceType.MOBILE + DeviceType.TABLET -> ErrorEvent.DeviceType.TABLET + DeviceType.TV -> ErrorEvent.DeviceType.TV + DeviceType.DESKTOP -> ErrorEvent.DeviceType.DESKTOP + else -> ErrorEvent.DeviceType.OTHER + } +} + +// endregion diff --git a/dd-sdk-android/src/main/kotlin/com/datadog/android/rum/internal/domain/scope/RumResourceScope.kt b/dd-sdk-android/src/main/kotlin/com/datadog/android/rum/internal/domain/scope/RumResourceScope.kt index 5921994b26..d3d2097a71 100644 --- a/dd-sdk-android/src/main/kotlin/com/datadog/android/rum/internal/domain/scope/RumResourceScope.kt +++ b/dd-sdk-android/src/main/kotlin/com/datadog/android/rum/internal/domain/scope/RumResourceScope.kt @@ -9,6 +9,7 @@ package com.datadog.android.rum.internal.domain.scope import com.datadog.android.core.internal.CoreFeature import com.datadog.android.core.internal.net.FirstPartyHostDetector import com.datadog.android.core.internal.persistence.DataWriter +import com.datadog.android.core.internal.system.AndroidInfoProvider import com.datadog.android.core.internal.utils.devLogger import com.datadog.android.core.internal.utils.loggableStackTrace import com.datadog.android.rum.GlobalRum @@ -35,7 +36,8 @@ internal class RumResourceScope( initialAttributes: Map, serverTimeOffsetInMs: Long, internal val firstPartyHostDetector: FirstPartyHostDetector, - private val rumEventSourceProvider: RumEventSourceProvider + private val rumEventSourceProvider: RumEventSourceProvider, + private val androidInfoProvider: AndroidInfoProvider ) : RumScope { internal val resourceId: String = UUID.randomUUID().toString() @@ -206,6 +208,17 @@ internal class RumResourceScope( type = ResourceEvent.ResourceEventSessionType.USER ), source = rumEventSourceProvider.resourceEventSource, + os = ResourceEvent.Os( + name = androidInfoProvider.osName, + version = androidInfoProvider.osVersion, + versionMajor = androidInfoProvider.osMajorVersion + ), + device = ResourceEvent.Device( + type = androidInfoProvider.deviceType.toResourceSchemaType(), + name = androidInfoProvider.deviceName, + model = androidInfoProvider.deviceModel, + brand = androidInfoProvider.deviceBrand + ), context = ResourceEvent.Context(additionalProperties = attributes), dd = ResourceEvent.Dd( traceId = traceId, @@ -286,6 +299,17 @@ internal class RumResourceScope( type = ErrorEvent.ErrorEventSessionType.USER ), source = rumEventSourceProvider.errorEventSource, + os = ErrorEvent.Os( + name = androidInfoProvider.osName, + version = androidInfoProvider.osVersion, + versionMajor = androidInfoProvider.osMajorVersion + ), + device = ErrorEvent.Device( + type = androidInfoProvider.deviceType.toErrorSchemaType(), + name = androidInfoProvider.deviceName, + model = androidInfoProvider.deviceModel, + brand = androidInfoProvider.deviceBrand + ), context = ErrorEvent.Context(additionalProperties = attributes), dd = ErrorEvent.Dd(session = ErrorEvent.DdSession(plan = ErrorEvent.Plan.PLAN_1)) ) @@ -320,13 +344,14 @@ internal class RumResourceScope( "resource: %s was 0 or negative. In order to keep the resource event" + " we forced it to 1ns." + @Suppress("LongParameterList") fun fromEvent( parentScope: RumScope, event: RumRawEvent.StartResource, firstPartyHostDetector: FirstPartyHostDetector, timestampOffset: Long, - rumEventSourceProvider: RumEventSourceProvider - + rumEventSourceProvider: RumEventSourceProvider, + androidInfoProvider: AndroidInfoProvider ): RumScope { return RumResourceScope( parentScope, @@ -337,7 +362,8 @@ internal class RumResourceScope( event.attributes, timestampOffset, firstPartyHostDetector, - rumEventSourceProvider + rumEventSourceProvider, + androidInfoProvider ) } } diff --git a/dd-sdk-android/src/main/kotlin/com/datadog/android/rum/internal/domain/scope/RumSessionScope.kt b/dd-sdk-android/src/main/kotlin/com/datadog/android/rum/internal/domain/scope/RumSessionScope.kt index 987f5445cf..707b8f95bf 100644 --- a/dd-sdk-android/src/main/kotlin/com/datadog/android/rum/internal/domain/scope/RumSessionScope.kt +++ b/dd-sdk-android/src/main/kotlin/com/datadog/android/rum/internal/domain/scope/RumSessionScope.kt @@ -16,6 +16,7 @@ import com.datadog.android.core.internal.CoreFeature import com.datadog.android.core.internal.net.FirstPartyHostDetector import com.datadog.android.core.internal.persistence.DataWriter import com.datadog.android.core.internal.persistence.NoOpDataWriter +import com.datadog.android.core.internal.system.AndroidInfoProvider import com.datadog.android.core.internal.system.BuildSdkVersionProvider import com.datadog.android.core.internal.system.DefaultBuildSdkVersionProvider import com.datadog.android.core.internal.time.TimeProvider @@ -44,7 +45,8 @@ internal class RumSessionScope( private val rumEventSourceProvider: RumEventSourceProvider, private val buildSdkVersionProvider: BuildSdkVersionProvider = DefaultBuildSdkVersionProvider(), private val sessionInactivityNanos: Long = DEFAULT_SESSION_INACTIVITY_NS, - private val sessionMaxDurationNanos: Long = DEFAULT_SESSION_MAX_DURATION_NS + private val sessionMaxDurationNanos: Long = DEFAULT_SESSION_MAX_DURATION_NS, + private val androidInfoProvider: AndroidInfoProvider ) : RumScope { internal val childrenScopes = mutableListOf() @@ -98,7 +100,8 @@ internal class RumSessionScope( memoryVitalMonitor, frameRateVitalMonitor, timeProvider, - rumEventSourceProvider + rumEventSourceProvider, + androidInfoProvider ) onViewDisplayed(event, viewScope, actualWriter) childrenScopes.add(viewScope) @@ -174,7 +177,7 @@ internal class RumSessionScope( } } - internal fun createBackgroundViewScope(event: RumRawEvent): RumViewScope { + private fun createBackgroundViewScope(event: RumRawEvent): RumViewScope { return RumViewScope( this, RUM_BACKGROUND_VIEW_URL, @@ -187,11 +190,12 @@ internal class RumSessionScope( NoOpVitalMonitor(), timeProvider, rumEventSourceProvider, - type = RumViewScope.RumViewType.BACKGROUND + type = RumViewScope.RumViewType.BACKGROUND, + androidInfoProvider = androidInfoProvider ) } - internal fun createAppLaunchViewScope(event: RumRawEvent): RumViewScope { + private fun createAppLaunchViewScope(event: RumRawEvent): RumViewScope { return RumViewScope( this, RUM_APP_LAUNCH_VIEW_URL, @@ -204,7 +208,8 @@ internal class RumSessionScope( NoOpVitalMonitor(), timeProvider, rumEventSourceProvider, - type = RumViewScope.RumViewType.APPLICATION_LAUNCH + type = RumViewScope.RumViewType.APPLICATION_LAUNCH, + androidInfoProvider = androidInfoProvider ) } diff --git a/dd-sdk-android/src/main/kotlin/com/datadog/android/rum/internal/domain/scope/RumViewScope.kt b/dd-sdk-android/src/main/kotlin/com/datadog/android/rum/internal/domain/scope/RumViewScope.kt index c4c856bc42..0677677de2 100644 --- a/dd-sdk-android/src/main/kotlin/com/datadog/android/rum/internal/domain/scope/RumViewScope.kt +++ b/dd-sdk-android/src/main/kotlin/com/datadog/android/rum/internal/domain/scope/RumViewScope.kt @@ -15,6 +15,7 @@ import androidx.fragment.app.Fragment import com.datadog.android.core.internal.CoreFeature import com.datadog.android.core.internal.net.FirstPartyHostDetector import com.datadog.android.core.internal.persistence.DataWriter +import com.datadog.android.core.internal.system.AndroidInfoProvider import com.datadog.android.core.internal.system.BuildSdkVersionProvider import com.datadog.android.core.internal.system.DefaultBuildSdkVersionProvider import com.datadog.android.core.internal.time.TimeProvider @@ -43,7 +44,7 @@ import java.util.UUID import java.util.concurrent.TimeUnit import kotlin.math.max -@Suppress("LargeClass") +@Suppress("LargeClass", "LongParameterList") internal open class RumViewScope( private val parentScope: RumScope, key: Any, @@ -58,7 +59,8 @@ internal open class RumViewScope( private val rumEventSourceProvider: RumEventSourceProvider, private val buildSdkVersionProvider: BuildSdkVersionProvider = DefaultBuildSdkVersionProvider(), private val viewUpdatePredicate: ViewUpdatePredicate = DefaultViewUpdatePredicate(), - internal val type: RumViewType = RumViewType.FOREGROUND + internal val type: RumViewType = RumViewType.FOREGROUND, + private val androidInfoProvider: AndroidInfoProvider ) : RumScope { internal val url = key.resolveViewUrl().replace('.', '/') @@ -275,7 +277,8 @@ internal open class RumViewScope( this, event, serverTimeOffsetInMs, - rumEventSourceProvider + rumEventSourceProvider, + androidInfoProvider ) pendingActionCount++ customActionScope.handleEvent(RumRawEvent.SendCustomActionNow(), writer) @@ -291,7 +294,8 @@ internal open class RumViewScope( this, event, serverTimeOffsetInMs, - rumEventSourceProvider + rumEventSourceProvider, + androidInfoProvider ) ) pendingActionCount++ @@ -312,12 +316,13 @@ internal open class RumViewScope( updatedEvent, firstPartyHostDetector, serverTimeOffsetInMs, - rumEventSourceProvider + rumEventSourceProvider, + androidInfoProvider ) pendingResourceCount++ } - @Suppress("ComplexMethod") + @Suppress("ComplexMethod", "LongMethod") private fun onAddError( event: RumRawEvent.AddError, writer: DataWriter @@ -366,6 +371,17 @@ internal open class RumViewScope( type = ErrorEvent.ErrorEventSessionType.USER ), source = rumEventSourceProvider.errorEventSource, + os = ErrorEvent.Os( + name = androidInfoProvider.osName, + version = androidInfoProvider.osVersion, + versionMajor = androidInfoProvider.osMajorVersion + ), + device = ErrorEvent.Device( + type = androidInfoProvider.deviceType.toErrorSchemaType(), + name = androidInfoProvider.deviceName, + model = androidInfoProvider.deviceModel, + brand = androidInfoProvider.deviceBrand + ), context = ErrorEvent.Context(additionalProperties = updatedAttributes), dd = ErrorEvent.Dd(session = ErrorEvent.DdSession(plan = ErrorEvent.Plan.PLAN_1)) ) @@ -579,9 +595,20 @@ internal open class RumViewScope( application = ViewEvent.Application(context.applicationId), session = ViewEvent.ViewEventSession( id = context.sessionId, - type = ViewEvent.Type.USER + type = ViewEvent.ViewEventSessionType.USER ), source = rumEventSourceProvider.viewEventSource, + os = ViewEvent.Os( + name = androidInfoProvider.osName, + version = androidInfoProvider.osVersion, + versionMajor = androidInfoProvider.osMajorVersion + ), + device = ViewEvent.Device( + type = androidInfoProvider.deviceType.toViewSchemaType(), + name = androidInfoProvider.deviceName, + model = androidInfoProvider.deviceModel, + brand = androidInfoProvider.deviceBrand + ), context = ViewEvent.Context(additionalProperties = attributes), dd = ViewEvent.Dd( documentVersion = version, @@ -667,6 +694,17 @@ internal open class RumViewScope( type = ActionEvent.ActionEventSessionType.USER ), source = rumEventSourceProvider.actionEventSource, + os = ActionEvent.Os( + name = androidInfoProvider.osName, + version = androidInfoProvider.osVersion, + versionMajor = androidInfoProvider.osMajorVersion + ), + device = ActionEvent.Device( + type = androidInfoProvider.deviceType.toActionSchemaType(), + name = androidInfoProvider.deviceName, + model = androidInfoProvider.deviceModel, + brand = androidInfoProvider.deviceBrand + ), context = ActionEvent.Context(additionalProperties = GlobalRum.globalAttributes), dd = ActionEvent.Dd(session = ActionEvent.DdSession(ActionEvent.Plan.PLAN_1)) ) @@ -713,9 +751,20 @@ internal open class RumViewScope( application = LongTaskEvent.Application(context.applicationId), session = LongTaskEvent.LongTaskEventSession( id = context.sessionId, - type = LongTaskEvent.Type.USER + type = LongTaskEvent.LongTaskEventSessionType.USER ), source = rumEventSourceProvider.longTaskEventSource, + os = LongTaskEvent.Os( + name = androidInfoProvider.osName, + version = androidInfoProvider.osVersion, + versionMajor = androidInfoProvider.osMajorVersion + ), + device = LongTaskEvent.Device( + type = androidInfoProvider.deviceType.toLongTaskSchemaType(), + name = androidInfoProvider.deviceName, + model = androidInfoProvider.deviceModel, + brand = androidInfoProvider.deviceBrand + ), context = LongTaskEvent.Context(additionalProperties = updatedAttributes), dd = LongTaskEvent.Dd(session = LongTaskEvent.DdSession(LongTaskEvent.Plan.PLAN_1)) ) @@ -793,7 +842,8 @@ internal open class RumViewScope( memoryVitalMonitor: VitalMonitor, frameRateVitalMonitor: VitalMonitor, timeProvider: TimeProvider, - rumEventSourceProvider: RumEventSourceProvider + rumEventSourceProvider: RumEventSourceProvider, + androidInfoProvider: AndroidInfoProvider ): RumViewScope { return RumViewScope( parentScope, @@ -806,7 +856,8 @@ internal open class RumViewScope( memoryVitalMonitor, frameRateVitalMonitor, timeProvider, - rumEventSourceProvider + rumEventSourceProvider, + androidInfoProvider = androidInfoProvider ) } } diff --git a/dd-sdk-android/src/main/kotlin/com/datadog/android/rum/internal/monitor/DatadogRumMonitor.kt b/dd-sdk-android/src/main/kotlin/com/datadog/android/rum/internal/monitor/DatadogRumMonitor.kt index f07fa2dd54..59e5a64aec 100644 --- a/dd-sdk-android/src/main/kotlin/com/datadog/android/rum/internal/monitor/DatadogRumMonitor.kt +++ b/dd-sdk-android/src/main/kotlin/com/datadog/android/rum/internal/monitor/DatadogRumMonitor.kt @@ -9,6 +9,7 @@ package com.datadog.android.rum.internal.monitor import android.os.Handler import com.datadog.android.core.internal.net.FirstPartyHostDetector import com.datadog.android.core.internal.persistence.DataWriter +import com.datadog.android.core.internal.system.AndroidInfoProvider import com.datadog.android.core.internal.time.TimeProvider import com.datadog.android.core.internal.utils.devLogger import com.datadog.android.rum.RumActionType @@ -53,7 +54,8 @@ internal class DatadogRumMonitor( frameRateVitalMonitor: VitalMonitor, timeProvider: TimeProvider, sessionListener: RumSessionListener?, - private val executorService: ExecutorService = Executors.newSingleThreadExecutor() + private val executorService: ExecutorService = Executors.newSingleThreadExecutor(), + androidInfoProvider: AndroidInfoProvider ) : RumMonitor, AdvancedRumMonitor { internal var rootScope: RumScope = RumApplicationScope( @@ -69,7 +71,8 @@ internal class DatadogRumMonitor( CombinedRumSessionListener(sessionListener, telemetryEventHandler) } else { telemetryEventHandler - } + }, + androidInfoProvider ) internal val keepAliveRunnable = Runnable { diff --git a/dd-sdk-android/src/main/kotlin/com/datadog/android/rum/internal/ndk/DatadogNdkCrashHandler.kt b/dd-sdk-android/src/main/kotlin/com/datadog/android/rum/internal/ndk/DatadogNdkCrashHandler.kt index af1629f39b..d081800576 100644 --- a/dd-sdk-android/src/main/kotlin/com/datadog/android/rum/internal/ndk/DatadogNdkCrashHandler.kt +++ b/dd-sdk-android/src/main/kotlin/com/datadog/android/rum/internal/ndk/DatadogNdkCrashHandler.kt @@ -14,6 +14,7 @@ import com.datadog.android.core.internal.persistence.file.FileHandler import com.datadog.android.core.internal.persistence.file.existsSafe import com.datadog.android.core.internal.persistence.file.listFilesSafe import com.datadog.android.core.internal.persistence.file.readTextSafe +import com.datadog.android.core.internal.system.AndroidInfoProvider import com.datadog.android.core.internal.time.TimeProvider import com.datadog.android.core.internal.utils.join import com.datadog.android.core.model.NetworkInfo @@ -24,6 +25,7 @@ import com.datadog.android.log.internal.domain.LogGenerator import com.datadog.android.log.internal.utils.errorWithTelemetry import com.datadog.android.log.model.LogEvent import com.datadog.android.rum.internal.domain.event.RumEventSourceProvider +import com.datadog.android.rum.internal.domain.scope.toErrorSchemaType import com.datadog.android.rum.model.ErrorEvent import com.datadog.android.rum.model.ViewEvent import java.io.File @@ -44,7 +46,8 @@ internal class DatadogNdkCrashHandler( private val timeProvider: TimeProvider, private val fileHandler: FileHandler, private val rumEventSourceProvider: RumEventSourceProvider = - RumEventSourceProvider(CoreFeature.sourceName) + RumEventSourceProvider(CoreFeature.sourceName), + private val androidInfoProvider: AndroidInfoProvider ) : NdkCrashHandler { private val ndkCrashDataDirectory: File = getNdkGrantedDir(appContext) @@ -300,6 +303,17 @@ internal class DatadogNdkCrashHandler( additionalUserProperties ), connectivity = connectivity, + os = ErrorEvent.Os( + name = androidInfoProvider.osName, + version = androidInfoProvider.osVersion, + versionMajor = androidInfoProvider.osMajorVersion + ), + device = ErrorEvent.Device( + type = androidInfoProvider.deviceType.toErrorSchemaType(), + name = androidInfoProvider.deviceName, + model = androidInfoProvider.deviceModel, + brand = androidInfoProvider.deviceBrand + ), dd = ErrorEvent.Dd(session = ErrorEvent.DdSession(plan = ErrorEvent.Plan.PLAN_1)), context = ErrorEvent.Context(additionalProperties = additionalProperties), error = ErrorEvent.Error( diff --git a/dd-sdk-android/src/main/kotlin/com/datadog/android/tracing/internal/TracingFeature.kt b/dd-sdk-android/src/main/kotlin/com/datadog/android/tracing/internal/TracingFeature.kt index 7fd95c4616..975e56bc02 100644 --- a/dd-sdk-android/src/main/kotlin/com/datadog/android/tracing/internal/TracingFeature.kt +++ b/dd-sdk-android/src/main/kotlin/com/datadog/android/tracing/internal/TracingFeature.kt @@ -12,7 +12,6 @@ import com.datadog.android.core.internal.CoreFeature import com.datadog.android.core.internal.SdkFeature import com.datadog.android.core.internal.net.DataUploader import com.datadog.android.core.internal.persistence.PersistenceStrategy -import com.datadog.android.core.internal.system.StaticAndroidInfoProvider import com.datadog.android.core.internal.utils.sdkLogger import com.datadog.android.tracing.internal.domain.TracesFilePersistenceStrategy import com.datadog.android.tracing.internal.net.TracesOkHttpUploaderV2 @@ -49,7 +48,7 @@ internal object TracingFeature : SdkFeature() CoreFeature.sourceName, CoreFeature.sdkVersion, CoreFeature.okHttpClient, - StaticAndroidInfoProvider + CoreFeature.androidInfoProvider ) } } diff --git a/dd-sdk-android/src/test/kotlin/com/datadog/android/core/internal/net/DataOkHttpUploaderV2Test.kt b/dd-sdk-android/src/test/kotlin/com/datadog/android/core/internal/net/DataOkHttpUploaderV2Test.kt index d27b3ee24b..b052c70491 100644 --- a/dd-sdk-android/src/test/kotlin/com/datadog/android/core/internal/net/DataOkHttpUploaderV2Test.kt +++ b/dd-sdk-android/src/test/kotlin/com/datadog/android/core/internal/net/DataOkHttpUploaderV2Test.kt @@ -92,9 +92,9 @@ internal abstract class DataOkHttpUploaderV2Test { open fun `set up`(forge: Forge) { whenever(mockCallFactory.newCall(any())) doReturn mockCall - whenever(mockAndroidInfoProvider.getDeviceVersion()) doReturn fakeDeviceVersion - whenever(mockAndroidInfoProvider.getDeviceModel()) doReturn fakeDeviceModel - whenever(mockAndroidInfoProvider.getDeviceBuildId()) doReturn fakeDeviceBuildId + whenever(mockAndroidInfoProvider.osVersion) doReturn fakeDeviceVersion + whenever(mockAndroidInfoProvider.deviceModel) doReturn fakeDeviceModel + whenever(mockAndroidInfoProvider.deviceBuildId) doReturn fakeDeviceBuildId fakeUserAgent = if (forge.aBool()) forge.anAlphaNumericalString() else "" System.setProperty("http.agent", fakeUserAgent) diff --git a/dd-sdk-android/src/test/kotlin/com/datadog/android/core/internal/system/DefaultAndroidInfoProviderTest.kt b/dd-sdk-android/src/test/kotlin/com/datadog/android/core/internal/system/DefaultAndroidInfoProviderTest.kt new file mode 100644 index 0000000000..7408958841 --- /dev/null +++ b/dd-sdk-android/src/test/kotlin/com/datadog/android/core/internal/system/DefaultAndroidInfoProviderTest.kt @@ -0,0 +1,431 @@ +/* + * 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 2016-Present Datadog, Inc. + */ + +package com.datadog.android.core.internal.system + +import android.app.UiModeManager +import android.content.Context +import android.content.pm.PackageManager +import android.content.res.Configuration +import android.content.res.Resources +import android.os.Build +import android.telephony.TelephonyManager +import com.datadog.android.utils.forge.Configurator +import com.datadog.tools.unit.setStaticValue +import com.nhaarman.mockitokotlin2.doReturn +import com.nhaarman.mockitokotlin2.mock +import com.nhaarman.mockitokotlin2.whenever +import fr.xgouchet.elmyr.Forge +import fr.xgouchet.elmyr.annotation.IntForgery +import fr.xgouchet.elmyr.annotation.StringForgery +import fr.xgouchet.elmyr.annotation.StringForgeryType +import fr.xgouchet.elmyr.junit5.ForgeConfiguration +import fr.xgouchet.elmyr.junit5.ForgeExtension +import java.util.Locale +import org.assertj.core.api.Assertions.assertThat +import org.junit.jupiter.api.AfterEach +import org.junit.jupiter.api.BeforeEach +import org.junit.jupiter.api.Test +import org.junit.jupiter.api.extension.ExtendWith +import org.junit.jupiter.api.extension.Extensions +import org.junit.jupiter.params.ParameterizedTest +import org.junit.jupiter.params.provider.MethodSource +import org.mockito.Mock +import org.mockito.junit.jupiter.MockitoExtension +import org.mockito.junit.jupiter.MockitoSettings +import org.mockito.quality.Strictness + +@Extensions( + ExtendWith(MockitoExtension::class), + ExtendWith(ForgeExtension::class) +) +@MockitoSettings(strictness = Strictness.LENIENT) +@ForgeConfiguration(Configurator::class) +internal class DefaultAndroidInfoProviderTest { + + private lateinit var testedProvider: AndroidInfoProvider + + @Mock + lateinit var mockSdkVersionProvider: BuildSdkVersionProvider + + @Mock + lateinit var mockContext: Context + + @Mock + lateinit var mockUiModeManager: UiModeManager + + @Mock + lateinit var mockTelephonyManager: TelephonyManager + + @Mock + lateinit var mockPackageManager: PackageManager + + @Mock + lateinit var mockResources: Resources + + @BeforeEach + fun setUp(forge: Forge) { + whenever(mockContext.getSystemService(Context.UI_MODE_SERVICE)) doReturn + mockUiModeManager + whenever(mockContext.getSystemService(Context.TELEPHONY_SERVICE)) doReturn + mockTelephonyManager + whenever(mockSdkVersionProvider.version()) doReturn + forge.anInt(min = Build.VERSION_CODES.BASE) + whenever(mockContext.packageManager) doReturn mockPackageManager + whenever(mockContext.resources) doReturn mockResources + whenever(mockResources.configuration) doReturn Configuration() + + Build::class.java.setStaticValue("MODEL", "") + } + + @AfterEach + fun tearDown() { + Build::class.java.setStaticValue("MODEL", "") + Build.VERSION::class.java.setStaticValue("RELEASE", "") + } + + // region device type + + @Test + fun `𝕄 return TV type 𝕎 deviceType { UI_MODE_TYPE_TELEVISION }`() { + // Given + whenever(mockUiModeManager.currentModeType) doReturn Configuration.UI_MODE_TYPE_TELEVISION + testedProvider = createProvider() + + // When + val type = testedProvider.deviceType + + // Then + assertThat(type).isEqualTo(DeviceType.TV) + } + + @Test + fun `𝕄 return TV type 𝕎 deviceType { Lollipop & FEATURE_LEANBACK }`( + @IntForgery( + min = Build.VERSION_CODES.LOLLIPOP + ) fakeSdkVersion: Int + ) { + // Given + whenever(mockSdkVersionProvider.version()) doReturn fakeSdkVersion + whenever( + mockPackageManager.hasSystemFeature(PackageManager.FEATURE_LEANBACK) + ) doReturn true + testedProvider = createProvider() + + // When + val type = testedProvider.deviceType + + // Then + assertThat(type).isEqualTo(DeviceType.TV) + } + + @Test + fun `𝕄 return TV type 𝕎 deviceType { pre-Lollipop & FEATURE_TELEVISION }`( + @IntForgery( + min = Build.VERSION_CODES.BASE, + max = Build.VERSION_CODES.LOLLIPOP + ) fakeSdkVersion: Int + ) { + // Given + whenever(mockSdkVersionProvider.version()) doReturn fakeSdkVersion + @Suppress("DEPRECATION") + whenever( + mockPackageManager.hasSystemFeature(PackageManager.FEATURE_TELEVISION) + ) doReturn true + testedProvider = createProvider() + + // When + val type = testedProvider.deviceType + + // Then + assertThat(type).isEqualTo(DeviceType.TV) + } + + @Test + fun `𝕄 return TV type 𝕎 deviceType { FEATURE_GOOGLE_ANDROID_TV }`() { + // Given + whenever( + mockPackageManager.hasSystemFeature( + DefaultAndroidInfoProvider.FEATURE_GOOGLE_ANDROID_TV + ) + ) doReturn true + testedProvider = createProvider() + + // When + val type = testedProvider.deviceType + + // Then + assertThat(type).isEqualTo(DeviceType.TV) + } + + @Test + fun `𝕄 return Tablet type 𝕎 deviceType { Samsung SM-T series model }`( + forge: Forge + ) { + // Given + Build::class.java.setStaticValue("MODEL", "SM-T${forge.aPositiveInt()}") + testedProvider = createProvider() + + // When + val type = testedProvider.deviceType + + // Then + assertThat(type).isEqualTo(DeviceType.TABLET) + } + + @Test + fun `𝕄 return Tablet type 𝕎 deviceType { tablet word in model name }`( + @StringForgery(regex = "[a-zA-Z1-9 ]{0,9}Tablet[a-zA-Z1-9 ]{0,9}") fakeModel: String + ) { + // Given + Build::class.java.setStaticValue("MODEL", fakeModel) + testedProvider = createProvider() + + // When + val type = testedProvider.deviceType + + // Then + assertThat(type).isEqualTo(DeviceType.TABLET) + } + + @Test + fun `𝕄 return Tablet type 𝕎 deviceType { smallest screen width more than 800dp }`( + @IntForgery(min = DefaultAndroidInfoProvider.MIN_TABLET_WIDTH_DP) fakeWidth: Int + ) { + // Given + val mockResources = mock() + val fakeConfiguration = Configuration().apply { + smallestScreenWidthDp = fakeWidth + } + + whenever(mockContext.resources) doReturn mockResources + whenever(mockResources.configuration) doReturn fakeConfiguration + testedProvider = createProvider() + + // When + val type = testedProvider.deviceType + + // Then + assertThat(type).isEqualTo(DeviceType.TABLET) + } + + @Test + fun `𝕄 return Mobile type 𝕎 deviceType { phone word in model name }`( + @StringForgery(regex = "[a-zA-Z1-9 ]{0,9}Phone[a-zA-Z1-9 ]{0,9}") fakeModel: String + ) { + // Given + Build::class.java.setStaticValue("MODEL", fakeModel) + + testedProvider = createProvider() + + // When + val type = testedProvider.deviceType + + // Then + assertThat(type).isEqualTo(DeviceType.MOBILE) + } + + @ParameterizedTest + @MethodSource("phoneTypesWithDescription") + fun `𝕄 return Mobile type 𝕎 deviceType {smallest screen width less than 800dp + telephony}`( + phoneType: PhoneType, + @IntForgery( + min = 0, + max = DefaultAndroidInfoProvider.MIN_TABLET_WIDTH_DP + ) fakeWidth: Int + ) { + // Given + val mockResources = mock() + val fakeConfiguration = Configuration().apply { + smallestScreenWidthDp = fakeWidth + } + + whenever(mockContext.resources) doReturn mockResources + whenever(mockResources.configuration) doReturn fakeConfiguration + whenever(mockTelephonyManager.phoneType) doReturn phoneType.value + + testedProvider = createProvider() + + // When + val type = testedProvider.deviceType + + // Then + assertThat(type).isEqualTo(DeviceType.MOBILE) + } + + @Test + fun `𝕄 return Other type 𝕎 deviceType { no tv, table or mobile properties }`( + @IntForgery( + min = 0, + max = DefaultAndroidInfoProvider.MIN_TABLET_WIDTH_DP + ) fakeWidth: Int + ) { + // Given + val mockResources = mock() + val fakeConfiguration = Configuration().apply { + smallestScreenWidthDp = fakeWidth + } + + whenever(mockContext.resources) doReturn mockResources + whenever(mockResources.configuration) doReturn fakeConfiguration + whenever(mockTelephonyManager.phoneType) doReturn TelephonyManager.PHONE_TYPE_NONE + + testedProvider = createProvider() + + // When + val type = testedProvider.deviceType + + // Then + assertThat(type).isEqualTo(DeviceType.OTHER) + } + + // endregion + + // region os version + major version + + @Test + fun `𝕄 return full version 𝕎 osVersion`( + @StringForgery(regex = "[1-9]{1,3}\\.[1-9]{1,3}\\.[1-9]{1,3}") fakeVersion: String + ) { + // Given + Build.VERSION::class.java.setStaticValue("RELEASE", fakeVersion) + testedProvider = createProvider() + + // When + val osVersion = testedProvider.osVersion + + // Then + assertThat(osVersion).isEqualTo(fakeVersion) + } + + @Test + fun `𝕄 return major version 𝕎 osMajorVersion { major - minor - patch format}`( + @StringForgery(regex = "[1-9]{1,3}\\.[1-9]{1,3}\\.[1-9]{1,3}") fakeVersion: String + ) { + // Given + Build.VERSION::class.java.setStaticValue("RELEASE", fakeVersion) + testedProvider = createProvider() + + // When + val osMajorVersion = testedProvider.osMajorVersion + + // Then + assertThat(osMajorVersion).isEqualTo(fakeVersion.split(".").first()) + } + + @Test + fun `𝕄 return major version 𝕎 osMajorVersion { generic format }`( + @StringForgery(type = StringForgeryType.ALPHA_NUMERICAL) fakeVersion: String + ) { + // Given + Build.VERSION::class.java.setStaticValue("RELEASE", fakeVersion) + testedProvider = createProvider() + + // When + val osMajorVersion = testedProvider.osMajorVersion + + // Then + assertThat(osMajorVersion).isEqualTo(fakeVersion) + } + + // endregion + + // region device name + + @Test + fun `𝕄 return device name 𝕎 deviceName { brand is blank }`( + @StringForgery fakeModel: String + ) { + // Given + Build::class.java.setStaticValue("BRAND", "") + Build::class.java.setStaticValue("MODEL", fakeModel) + testedProvider = createProvider() + + // When + val deviceName = testedProvider.deviceName + + // Then + assertThat(deviceName).isEqualTo(fakeModel) + } + + @Test + fun `𝕄 return device name 𝕎 deviceName { model contains brand }`( + @StringForgery fakeBrand: String, + @StringForgery modelPrefix: String, + @StringForgery modelSuffix: String + ) { + // Given + val deviceModel = modelPrefix + fakeBrand.capitalize() + modelSuffix + Build::class.java.setStaticValue("BRAND", fakeBrand) + Build::class.java.setStaticValue("MODEL", deviceModel) + testedProvider = createProvider() + + // When + val deviceName = testedProvider.deviceName + + // Then + assertThat(deviceName).isEqualTo(deviceModel) + } + + @Test + fun `𝕄 return device name 𝕎 deviceName { model doesn't contain brand }`( + @StringForgery fakeBrand: String, + @StringForgery fakeModel: String + ) { + // Given + Build::class.java.setStaticValue("BRAND", fakeBrand) + Build::class.java.setStaticValue("MODEL", fakeModel) + testedProvider = createProvider() + + // When + val deviceName = testedProvider.deviceName + + // Then + assertThat(deviceName).isEqualTo("${fakeBrand.capitalize()} $fakeModel") + } + + // endregion + + @Test + fun `𝕄 return device brand 𝕎 deviceBrand { model doesn't contain brand }`( + @StringForgery fakeBrand: String + ) { + // Given + Build::class.java.setStaticValue("BRAND", fakeBrand) + testedProvider = createProvider() + + // When + val deviceBrand = testedProvider.deviceBrand + + // Then + assertThat(deviceBrand).isEqualTo(fakeBrand.capitalize()) + } + + // region private + + private fun createProvider(): AndroidInfoProvider = + DefaultAndroidInfoProvider(mockContext, mockSdkVersionProvider) + + private fun String.capitalize() = + replaceFirstChar { if (it.isLowerCase()) it.titlecase(Locale.US) else it.toString() } + + companion object { + + @Suppress("unused") + @JvmStatic + fun phoneTypesWithDescription(): List { + return listOf( + PhoneType("gsm", TelephonyManager.PHONE_TYPE_GSM), + PhoneType("cdma", TelephonyManager.PHONE_TYPE_CDMA), + PhoneType("sip", TelephonyManager.PHONE_TYPE_SIP) + ) + } + } + + data class PhoneType(val name: String, val value: Int) + + // endregion +} diff --git a/dd-sdk-android/src/test/kotlin/com/datadog/android/rum/assertj/ActionEventAssert.kt b/dd-sdk-android/src/test/kotlin/com/datadog/android/rum/assertj/ActionEventAssert.kt index 8da9217aee..6b75181161 100644 --- a/dd-sdk-android/src/test/kotlin/com/datadog/android/rum/assertj/ActionEventAssert.kt +++ b/dd-sdk-android/src/test/kotlin/com/datadog/android/rum/assertj/ActionEventAssert.kt @@ -288,6 +288,59 @@ internal class ActionEventAssert(actual: ActionEvent) : return this } + fun hasDeviceInfo( + name: String, + model: String, + brand: String, + type: ActionEvent.DeviceType + ): ActionEventAssert { + assertThat(actual.device?.name) + .overridingErrorMessage( + "Expected event data to have device.name $name but was ${actual.device?.name}" + ) + .isEqualTo(name) + assertThat(actual.device?.model) + .overridingErrorMessage( + "Expected event data to have device.model $model but was ${actual.device?.model}" + ) + .isEqualTo(model) + assertThat(actual.device?.brand) + .overridingErrorMessage( + "Expected event data to have device.brand $brand but was ${actual.device?.brand}" + ) + .isEqualTo(brand) + assertThat(actual.device?.type) + .overridingErrorMessage( + "Expected event data to have device.type $type but was ${actual.device?.type}" + ) + .isEqualTo(type) + return this + } + + fun hasOsInfo( + name: String, + version: String, + versionMajor: String + ): ActionEventAssert { + assertThat(actual.os?.name) + .overridingErrorMessage( + "Expected event data to have os.name $name but was ${actual.os?.name}" + ) + .isEqualTo(name) + assertThat(actual.os?.version) + .overridingErrorMessage( + "Expected event data to have os.version $version but was ${actual.os?.version}" + ) + .isEqualTo(version) + assertThat(actual.os?.versionMajor) + .overridingErrorMessage( + "Expected event data to have os.version_major $versionMajor" + + " but was ${actual.os?.versionMajor}" + ) + .isEqualTo(versionMajor) + return this + } + companion object { internal const val TIMESTAMP_THRESHOLD_MS = 50L internal fun assertThat(actual: ActionEvent): ActionEventAssert = diff --git a/dd-sdk-android/src/test/kotlin/com/datadog/android/rum/assertj/ErrorEventAssert.kt b/dd-sdk-android/src/test/kotlin/com/datadog/android/rum/assertj/ErrorEventAssert.kt index ab46dfd436..56f935b50b 100644 --- a/dd-sdk-android/src/test/kotlin/com/datadog/android/rum/assertj/ErrorEventAssert.kt +++ b/dd-sdk-android/src/test/kotlin/com/datadog/android/rum/assertj/ErrorEventAssert.kt @@ -363,6 +363,59 @@ internal class ErrorEventAssert(actual: ErrorEvent) : return this } + fun hasDeviceInfo( + name: String, + model: String, + brand: String, + type: ErrorEvent.DeviceType + ): ErrorEventAssert { + assertThat(actual.device?.name) + .overridingErrorMessage( + "Expected event data to have device.name $name but was ${actual.device?.name}" + ) + .isEqualTo(name) + assertThat(actual.device?.model) + .overridingErrorMessage( + "Expected event data to have device.model $model but was ${actual.device?.model}" + ) + .isEqualTo(model) + assertThat(actual.device?.brand) + .overridingErrorMessage( + "Expected event data to have device.brand $brand but was ${actual.device?.brand}" + ) + .isEqualTo(brand) + assertThat(actual.device?.type) + .overridingErrorMessage( + "Expected event data to have device.type $type but was ${actual.device?.type}" + ) + .isEqualTo(type) + return this + } + + fun hasOsInfo( + name: String, + version: String, + versionMajor: String + ): ErrorEventAssert { + assertThat(actual.os?.name) + .overridingErrorMessage( + "Expected event data to have os.name $name but was ${actual.os?.name}" + ) + .isEqualTo(name) + assertThat(actual.os?.version) + .overridingErrorMessage( + "Expected event data to have os.version $version but was ${actual.os?.version}" + ) + .isEqualTo(version) + assertThat(actual.os?.versionMajor) + .overridingErrorMessage( + "Expected event data to have os.version_major $versionMajor" + + " but was ${actual.os?.versionMajor}" + ) + .isEqualTo(versionMajor) + return this + } + companion object { internal const val TIMESTAMP_THRESHOLD_MS = 50L internal fun assertThat(actual: ErrorEvent): ErrorEventAssert = diff --git a/dd-sdk-android/src/test/kotlin/com/datadog/android/rum/assertj/LongTaskEventAssert.kt b/dd-sdk-android/src/test/kotlin/com/datadog/android/rum/assertj/LongTaskEventAssert.kt index 555fea1220..6e291b116b 100644 --- a/dd-sdk-android/src/test/kotlin/com/datadog/android/rum/assertj/LongTaskEventAssert.kt +++ b/dd-sdk-android/src/test/kotlin/com/datadog/android/rum/assertj/LongTaskEventAssert.kt @@ -9,7 +9,6 @@ package com.datadog.android.rum.assertj import com.datadog.android.core.model.NetworkInfo import com.datadog.android.core.model.UserInfo import com.datadog.android.rum.internal.domain.scope.isConnected -import com.datadog.android.rum.model.ErrorEvent import com.datadog.android.rum.model.LongTaskEvent import org.assertj.core.api.AbstractObjectAssert import org.assertj.core.api.Assertions.assertThat @@ -187,37 +186,6 @@ internal class LongTaskEventAssert(actual: LongTaskEvent) : return this } - fun hasConnectivityStatus(expected: ErrorEvent.Status?): LongTaskEventAssert { - assertThat(actual.connectivity?.status) - .overridingErrorMessage( - "Expected event data to have connectivity status: $expected" + - " but was: ${actual.connectivity?.status} " - ) - .isEqualTo(expected) - return this - } - - fun hasConnectivityInterface(expected: List?): LongTaskEventAssert { - val interfaces = actual.connectivity?.interfaces - assertThat(interfaces) - .overridingErrorMessage( - "Expected event data to have connectivity interfaces: $expected" + - " but was: $interfaces " - ) - .isEqualTo(expected) - return this - } - - fun hasConnectivityCellular(expected: ErrorEvent.Cellular?): LongTaskEventAssert { - assertThat(actual.connectivity?.cellular) - .overridingErrorMessage( - "Expected event data to have connectivity cellular: $expected" + - " but was: ${actual.connectivity?.cellular} " - ) - .isEqualTo(expected) - return this - } - fun hasLiteSessionPlan(): LongTaskEventAssert { assertThat(actual.dd.session?.plan) .overridingErrorMessage( @@ -240,6 +208,59 @@ internal class LongTaskEventAssert(actual: LongTaskEvent) : return this } + fun hasDeviceInfo( + name: String, + model: String, + brand: String, + type: LongTaskEvent.DeviceType + ): LongTaskEventAssert { + assertThat(actual.device?.name) + .overridingErrorMessage( + "Expected event data to have device.name $name but was ${actual.device?.name}" + ) + .isEqualTo(name) + assertThat(actual.device?.model) + .overridingErrorMessage( + "Expected event data to have device.model $model but was ${actual.device?.model}" + ) + .isEqualTo(model) + assertThat(actual.device?.brand) + .overridingErrorMessage( + "Expected event data to have device.brand $brand but was ${actual.device?.brand}" + ) + .isEqualTo(brand) + assertThat(actual.device?.type) + .overridingErrorMessage( + "Expected event data to have device.type $type but was ${actual.device?.type}" + ) + .isEqualTo(type) + return this + } + + fun hasOsInfo( + name: String, + version: String, + versionMajor: String + ): LongTaskEventAssert { + assertThat(actual.os?.name) + .overridingErrorMessage( + "Expected event data to have os.name $name but was ${actual.os?.name}" + ) + .isEqualTo(name) + assertThat(actual.os?.version) + .overridingErrorMessage( + "Expected event data to have os.version $version but was ${actual.os?.version}" + ) + .isEqualTo(version) + assertThat(actual.os?.versionMajor) + .overridingErrorMessage( + "Expected event data to have os.version_major $versionMajor" + + " but was ${actual.os?.versionMajor}" + ) + .isEqualTo(versionMajor) + return this + } + companion object { internal const val TIMESTAMP_THRESHOLD_MS = 50L internal fun assertThat(actual: LongTaskEvent): LongTaskEventAssert = diff --git a/dd-sdk-android/src/test/kotlin/com/datadog/android/rum/assertj/ResourceEventAssert.kt b/dd-sdk-android/src/test/kotlin/com/datadog/android/rum/assertj/ResourceEventAssert.kt index 73b0dfaa75..08e875490c 100644 --- a/dd-sdk-android/src/test/kotlin/com/datadog/android/rum/assertj/ResourceEventAssert.kt +++ b/dd-sdk-android/src/test/kotlin/com/datadog/android/rum/assertj/ResourceEventAssert.kt @@ -461,6 +461,59 @@ internal class ResourceEventAssert(actual: ResourceEvent) : return this } + fun hasDeviceInfo( + name: String, + model: String, + brand: String, + type: ResourceEvent.DeviceType + ): ResourceEventAssert { + assertThat(actual.device?.name) + .overridingErrorMessage( + "Expected event data to have device.name $name but was ${actual.device?.name}" + ) + .isEqualTo(name) + assertThat(actual.device?.model) + .overridingErrorMessage( + "Expected event data to have device.model $model but was ${actual.device?.model}" + ) + .isEqualTo(model) + assertThat(actual.device?.brand) + .overridingErrorMessage( + "Expected event data to have device.brand $brand but was ${actual.device?.brand}" + ) + .isEqualTo(brand) + assertThat(actual.device?.type) + .overridingErrorMessage( + "Expected event data to have device.type $type but was ${actual.device?.type}" + ) + .isEqualTo(type) + return this + } + + fun hasOsInfo( + name: String, + version: String, + versionMajor: String + ): ResourceEventAssert { + assertThat(actual.os?.name) + .overridingErrorMessage( + "Expected event data to have os.name $name but was ${actual.os?.name}" + ) + .isEqualTo(name) + assertThat(actual.os?.version) + .overridingErrorMessage( + "Expected event data to have os.version $version but was ${actual.os?.version}" + ) + .isEqualTo(version) + assertThat(actual.os?.versionMajor) + .overridingErrorMessage( + "Expected event data to have os.version_major $versionMajor" + + " but was ${actual.os?.versionMajor}" + ) + .isEqualTo(versionMajor) + return this + } + companion object { internal const val TIMESTAMP_THRESHOLD_MS = 50L diff --git a/dd-sdk-android/src/test/kotlin/com/datadog/android/rum/assertj/ViewEventAssert.kt b/dd-sdk-android/src/test/kotlin/com/datadog/android/rum/assertj/ViewEventAssert.kt index bfe835a90d..828399b0e9 100644 --- a/dd-sdk-android/src/test/kotlin/com/datadog/android/rum/assertj/ViewEventAssert.kt +++ b/dd-sdk-android/src/test/kotlin/com/datadog/android/rum/assertj/ViewEventAssert.kt @@ -408,6 +408,59 @@ internal class ViewEventAssert(actual: ViewEvent) : return this } + fun hasDeviceInfo( + name: String, + model: String, + brand: String, + type: ViewEvent.DeviceType + ): ViewEventAssert { + assertThat(actual.device?.name) + .overridingErrorMessage( + "Expected event data to have device.name $name but was ${actual.device?.name}" + ) + .isEqualTo(name) + assertThat(actual.device?.model) + .overridingErrorMessage( + "Expected event data to have device.model $model but was ${actual.device?.model}" + ) + .isEqualTo(model) + assertThat(actual.device?.brand) + .overridingErrorMessage( + "Expected event data to have device.brand $brand but was ${actual.device?.brand}" + ) + .isEqualTo(brand) + assertThat(actual.device?.type) + .overridingErrorMessage( + "Expected event data to have device.type $type but was ${actual.device?.type}" + ) + .isEqualTo(type) + return this + } + + fun hasOsInfo( + name: String, + version: String, + versionMajor: String + ): ViewEventAssert { + assertThat(actual.os?.name) + .overridingErrorMessage( + "Expected event data to have os.name $name but was ${actual.os?.name}" + ) + .isEqualTo(name) + assertThat(actual.os?.version) + .overridingErrorMessage( + "Expected event data to have os.version $version but was ${actual.os?.version}" + ) + .isEqualTo(version) + assertThat(actual.os?.versionMajor) + .overridingErrorMessage( + "Expected event data to have os.version_major $versionMajor" + + " but was ${actual.os?.versionMajor}" + ) + .isEqualTo(versionMajor) + return this + } + companion object { internal val ONE_SECOND_NS = TimeUnit.SECONDS.toNanos(1) diff --git a/dd-sdk-android/src/test/kotlin/com/datadog/android/rum/internal/domain/scope/RumActionScopeTest.kt b/dd-sdk-android/src/test/kotlin/com/datadog/android/rum/internal/domain/scope/RumActionScopeTest.kt index 41cf0631bb..f01af3a0c9 100644 --- a/dd-sdk-android/src/test/kotlin/com/datadog/android/rum/internal/domain/scope/RumActionScopeTest.kt +++ b/dd-sdk-android/src/test/kotlin/com/datadog/android/rum/internal/domain/scope/RumActionScopeTest.kt @@ -8,6 +8,7 @@ package com.datadog.android.rum.internal.domain.scope import android.content.Context import com.datadog.android.core.internal.persistence.DataWriter +import com.datadog.android.core.internal.system.AndroidInfoProvider import com.datadog.android.core.model.UserInfo import com.datadog.android.rum.GlobalRum import com.datadog.android.rum.RumActionType @@ -84,6 +85,9 @@ internal class RumActionScopeTest { @Forgery lateinit var fakeUserInfo: UserInfo + @Forgery + lateinit var fakeAndroidInfoProvider: AndroidInfoProvider + lateinit var fakeEventTime: Time lateinit var fakeEvent: RumRawEvent @@ -126,7 +130,8 @@ internal class RumActionScopeTest { fakeServerOffset, TEST_INACTIVITY_MS, TEST_MAX_DURATION_MS, - mockRumEventSourceProvider + mockRumEventSourceProvider, + fakeAndroidInfoProvider ) } @@ -193,6 +198,17 @@ internal class RumActionScopeTest { hasLiteSessionPlan() containsExactlyContextAttributes(fakeAttributes) hasSource(fakeSourceActionEvent) + hasDeviceInfo( + fakeAndroidInfoProvider.deviceName, + fakeAndroidInfoProvider.deviceModel, + fakeAndroidInfoProvider.deviceBrand, + fakeAndroidInfoProvider.deviceType.toActionSchemaType() + ) + hasOsInfo( + fakeAndroidInfoProvider.osName, + fakeAndroidInfoProvider.osVersion, + fakeAndroidInfoProvider.osMajorVersion + ) } } verify(mockParentScope, never()).handleEvent(any(), any()) @@ -276,6 +292,17 @@ internal class RumActionScopeTest { hasLiteSessionPlan() containsExactlyContextAttributes(fakeAttributes) hasSource(fakeSourceActionEvent) + hasDeviceInfo( + fakeAndroidInfoProvider.deviceName, + fakeAndroidInfoProvider.deviceModel, + fakeAndroidInfoProvider.deviceBrand, + fakeAndroidInfoProvider.deviceType.toActionSchemaType() + ) + hasOsInfo( + fakeAndroidInfoProvider.osName, + fakeAndroidInfoProvider.osVersion, + fakeAndroidInfoProvider.osMajorVersion + ) } } verify(mockParentScope, never()).handleEvent(any(), any()) @@ -336,6 +363,17 @@ internal class RumActionScopeTest { hasSessionId(fakeParentContext.sessionId) hasLiteSessionPlan() containsExactlyContextAttributes(fakeAttributes) + hasDeviceInfo( + fakeAndroidInfoProvider.deviceName, + fakeAndroidInfoProvider.deviceModel, + fakeAndroidInfoProvider.deviceBrand, + fakeAndroidInfoProvider.deviceType.toActionSchemaType() + ) + hasOsInfo( + fakeAndroidInfoProvider.osName, + fakeAndroidInfoProvider.osVersion, + fakeAndroidInfoProvider.osMajorVersion + ) } } verify(mockParentScope, never()).handleEvent(any(), any()) @@ -455,6 +493,17 @@ internal class RumActionScopeTest { hasLiteSessionPlan() containsExactlyContextAttributes(fakeAttributes) hasSource(fakeSourceActionEvent) + hasDeviceInfo( + fakeAndroidInfoProvider.deviceName, + fakeAndroidInfoProvider.deviceModel, + fakeAndroidInfoProvider.deviceBrand, + fakeAndroidInfoProvider.deviceType.toActionSchemaType() + ) + hasOsInfo( + fakeAndroidInfoProvider.osName, + fakeAndroidInfoProvider.osVersion, + fakeAndroidInfoProvider.osMajorVersion + ) } } verify(mockParentScope, never()).handleEvent(any(), any()) @@ -503,6 +552,17 @@ internal class RumActionScopeTest { hasLiteSessionPlan() containsExactlyContextAttributes(fakeAttributes) hasSource(fakeSourceActionEvent) + hasDeviceInfo( + fakeAndroidInfoProvider.deviceName, + fakeAndroidInfoProvider.deviceModel, + fakeAndroidInfoProvider.deviceBrand, + fakeAndroidInfoProvider.deviceType.toActionSchemaType() + ) + hasOsInfo( + fakeAndroidInfoProvider.osName, + fakeAndroidInfoProvider.osVersion, + fakeAndroidInfoProvider.osMajorVersion + ) } } verify(mockParentScope, never()).handleEvent(any(), any()) @@ -542,6 +602,17 @@ internal class RumActionScopeTest { hasLiteSessionPlan() containsExactlyContextAttributes(fakeAttributes) hasSource(fakeSourceActionEvent) + hasDeviceInfo( + fakeAndroidInfoProvider.deviceName, + fakeAndroidInfoProvider.deviceModel, + fakeAndroidInfoProvider.deviceBrand, + fakeAndroidInfoProvider.deviceType.toActionSchemaType() + ) + hasOsInfo( + fakeAndroidInfoProvider.osName, + fakeAndroidInfoProvider.osVersion, + fakeAndroidInfoProvider.osMajorVersion + ) } } verify(mockParentScope, never()).handleEvent(any(), any()) @@ -587,6 +658,17 @@ internal class RumActionScopeTest { hasLiteSessionPlan() containsExactlyContextAttributes(fakeAttributes) hasSource(fakeSourceActionEvent) + hasDeviceInfo( + fakeAndroidInfoProvider.deviceName, + fakeAndroidInfoProvider.deviceModel, + fakeAndroidInfoProvider.deviceBrand, + fakeAndroidInfoProvider.deviceType.toActionSchemaType() + ) + hasOsInfo( + fakeAndroidInfoProvider.osName, + fakeAndroidInfoProvider.osVersion, + fakeAndroidInfoProvider.osMajorVersion + ) } } verify(mockParentScope, never()).handleEvent(any(), any()) @@ -626,6 +708,17 @@ internal class RumActionScopeTest { hasLiteSessionPlan() containsExactlyContextAttributes(fakeAttributes) hasSource(fakeSourceActionEvent) + hasDeviceInfo( + fakeAndroidInfoProvider.deviceName, + fakeAndroidInfoProvider.deviceModel, + fakeAndroidInfoProvider.deviceBrand, + fakeAndroidInfoProvider.deviceType.toActionSchemaType() + ) + hasOsInfo( + fakeAndroidInfoProvider.osName, + fakeAndroidInfoProvider.osVersion, + fakeAndroidInfoProvider.osMajorVersion + ) } } verify(mockParentScope, never()).handleEvent(any(), any()) @@ -666,6 +759,17 @@ internal class RumActionScopeTest { hasLiteSessionPlan() containsExactlyContextAttributes(fakeAttributes) hasSource(fakeSourceActionEvent) + hasDeviceInfo( + fakeAndroidInfoProvider.deviceName, + fakeAndroidInfoProvider.deviceModel, + fakeAndroidInfoProvider.deviceBrand, + fakeAndroidInfoProvider.deviceType.toActionSchemaType() + ) + hasOsInfo( + fakeAndroidInfoProvider.osName, + fakeAndroidInfoProvider.osVersion, + fakeAndroidInfoProvider.osMajorVersion + ) } } verify(mockParentScope, never()).handleEvent(any(), any()) @@ -705,6 +809,17 @@ internal class RumActionScopeTest { hasLiteSessionPlan() containsExactlyContextAttributes(fakeAttributes) hasSource(fakeSourceActionEvent) + hasDeviceInfo( + fakeAndroidInfoProvider.deviceName, + fakeAndroidInfoProvider.deviceModel, + fakeAndroidInfoProvider.deviceBrand, + fakeAndroidInfoProvider.deviceType.toActionSchemaType() + ) + hasOsInfo( + fakeAndroidInfoProvider.osName, + fakeAndroidInfoProvider.osVersion, + fakeAndroidInfoProvider.osMajorVersion + ) } } verify(mockParentScope, never()).handleEvent(any(), any()) @@ -745,6 +860,17 @@ internal class RumActionScopeTest { hasLiteSessionPlan() containsExactlyContextAttributes(fakeAttributes) hasSource(fakeSourceActionEvent) + hasDeviceInfo( + fakeAndroidInfoProvider.deviceName, + fakeAndroidInfoProvider.deviceModel, + fakeAndroidInfoProvider.deviceBrand, + fakeAndroidInfoProvider.deviceType.toActionSchemaType() + ) + hasOsInfo( + fakeAndroidInfoProvider.osName, + fakeAndroidInfoProvider.osVersion, + fakeAndroidInfoProvider.osMajorVersion + ) } } verify(mockParentScope, never()).handleEvent(any(), any()) @@ -787,6 +913,17 @@ internal class RumActionScopeTest { hasLiteSessionPlan() containsExactlyContextAttributes(fakeAttributes) hasSource(fakeSourceActionEvent) + hasDeviceInfo( + fakeAndroidInfoProvider.deviceName, + fakeAndroidInfoProvider.deviceModel, + fakeAndroidInfoProvider.deviceBrand, + fakeAndroidInfoProvider.deviceType.toActionSchemaType() + ) + hasOsInfo( + fakeAndroidInfoProvider.osName, + fakeAndroidInfoProvider.osVersion, + fakeAndroidInfoProvider.osMajorVersion + ) } } verify(mockParentScope, never()).handleEvent(any(), any()) @@ -825,6 +962,17 @@ internal class RumActionScopeTest { hasLiteSessionPlan() containsExactlyContextAttributes(fakeAttributes) hasSource(fakeSourceActionEvent) + hasDeviceInfo( + fakeAndroidInfoProvider.deviceName, + fakeAndroidInfoProvider.deviceModel, + fakeAndroidInfoProvider.deviceBrand, + fakeAndroidInfoProvider.deviceType.toActionSchemaType() + ) + hasOsInfo( + fakeAndroidInfoProvider.osName, + fakeAndroidInfoProvider.osVersion, + fakeAndroidInfoProvider.osMajorVersion + ) } } verify(mockParentScope, never()).handleEvent(any(), any()) @@ -863,6 +1011,17 @@ internal class RumActionScopeTest { hasLiteSessionPlan() containsExactlyContextAttributes(fakeAttributes) hasSource(fakeSourceActionEvent) + hasDeviceInfo( + fakeAndroidInfoProvider.deviceName, + fakeAndroidInfoProvider.deviceModel, + fakeAndroidInfoProvider.deviceBrand, + fakeAndroidInfoProvider.deviceType.toActionSchemaType() + ) + hasOsInfo( + fakeAndroidInfoProvider.osName, + fakeAndroidInfoProvider.osVersion, + fakeAndroidInfoProvider.osMajorVersion + ) } } verify(mockParentScope, never()).handleEvent(any(), any()) @@ -902,6 +1061,17 @@ internal class RumActionScopeTest { hasLiteSessionPlan() containsExactlyContextAttributes(fakeAttributes) hasSource(fakeSourceActionEvent) + hasDeviceInfo( + fakeAndroidInfoProvider.deviceName, + fakeAndroidInfoProvider.deviceModel, + fakeAndroidInfoProvider.deviceBrand, + fakeAndroidInfoProvider.deviceType.toActionSchemaType() + ) + hasOsInfo( + fakeAndroidInfoProvider.osName, + fakeAndroidInfoProvider.osVersion, + fakeAndroidInfoProvider.osMajorVersion + ) } } verify(mockParentScope, never()).handleEvent(any(), any()) @@ -943,6 +1113,17 @@ internal class RumActionScopeTest { hasLiteSessionPlan() containsExactlyContextAttributes(fakeAttributes) hasSource(fakeSourceActionEvent) + hasDeviceInfo( + fakeAndroidInfoProvider.deviceName, + fakeAndroidInfoProvider.deviceModel, + fakeAndroidInfoProvider.deviceBrand, + fakeAndroidInfoProvider.deviceType.toActionSchemaType() + ) + hasOsInfo( + fakeAndroidInfoProvider.osName, + fakeAndroidInfoProvider.osVersion, + fakeAndroidInfoProvider.osMajorVersion + ) } } verify(mockParentScope, never()).handleEvent(any(), any()) @@ -972,7 +1153,8 @@ internal class RumActionScopeTest { fakeServerOffset, TEST_INACTIVITY_MS, TEST_MAX_DURATION_MS, - mockRumEventSourceProvider + mockRumEventSourceProvider, + fakeAndroidInfoProvider ) fakeGlobalAttributes.keys.forEach { GlobalRum.globalAttributes.remove(it) } @@ -1001,6 +1183,17 @@ internal class RumActionScopeTest { hasLiteSessionPlan() containsExactlyContextAttributes(expectedAttributes) hasSource(fakeSourceActionEvent) + hasDeviceInfo( + fakeAndroidInfoProvider.deviceName, + fakeAndroidInfoProvider.deviceModel, + fakeAndroidInfoProvider.deviceBrand, + fakeAndroidInfoProvider.deviceType.toActionSchemaType() + ) + hasOsInfo( + fakeAndroidInfoProvider.osName, + fakeAndroidInfoProvider.osVersion, + fakeAndroidInfoProvider.osMajorVersion + ) } } verify(mockParentScope, never()).handleEvent(any(), any()) @@ -1046,6 +1239,17 @@ internal class RumActionScopeTest { hasLiteSessionPlan() containsExactlyContextAttributes(expectedAttributes) hasSource(fakeSourceActionEvent) + hasDeviceInfo( + fakeAndroidInfoProvider.deviceName, + fakeAndroidInfoProvider.deviceModel, + fakeAndroidInfoProvider.deviceBrand, + fakeAndroidInfoProvider.deviceType.toActionSchemaType() + ) + hasOsInfo( + fakeAndroidInfoProvider.osName, + fakeAndroidInfoProvider.osVersion, + fakeAndroidInfoProvider.osMajorVersion + ) } } verify(mockParentScope, never()).handleEvent(any(), any()) @@ -1082,6 +1286,17 @@ internal class RumActionScopeTest { hasLiteSessionPlan() containsExactlyContextAttributes(fakeAttributes) hasSource(fakeSourceActionEvent) + hasDeviceInfo( + fakeAndroidInfoProvider.deviceName, + fakeAndroidInfoProvider.deviceModel, + fakeAndroidInfoProvider.deviceBrand, + fakeAndroidInfoProvider.deviceType.toActionSchemaType() + ) + hasOsInfo( + fakeAndroidInfoProvider.osName, + fakeAndroidInfoProvider.osVersion, + fakeAndroidInfoProvider.osMajorVersion + ) } } verify(mockParentScope, never()).handleEvent(any(), any()) @@ -1121,6 +1336,17 @@ internal class RumActionScopeTest { hasLiteSessionPlan() containsExactlyContextAttributes(fakeAttributes) hasSource(fakeSourceActionEvent) + hasDeviceInfo( + fakeAndroidInfoProvider.deviceName, + fakeAndroidInfoProvider.deviceModel, + fakeAndroidInfoProvider.deviceBrand, + fakeAndroidInfoProvider.deviceType.toActionSchemaType() + ) + hasOsInfo( + fakeAndroidInfoProvider.osName, + fakeAndroidInfoProvider.osVersion, + fakeAndroidInfoProvider.osMajorVersion + ) } } verify(mockParentScope, never()).handleEvent(any(), any()) @@ -1160,6 +1386,17 @@ internal class RumActionScopeTest { hasLiteSessionPlan() containsExactlyContextAttributes(fakeAttributes) hasSource(fakeSourceActionEvent) + hasDeviceInfo( + fakeAndroidInfoProvider.deviceName, + fakeAndroidInfoProvider.deviceModel, + fakeAndroidInfoProvider.deviceBrand, + fakeAndroidInfoProvider.deviceType.toActionSchemaType() + ) + hasOsInfo( + fakeAndroidInfoProvider.osName, + fakeAndroidInfoProvider.osVersion, + fakeAndroidInfoProvider.osMajorVersion + ) } } verify(mockParentScope, never()).handleEvent(any(), any()) @@ -1200,6 +1437,17 @@ internal class RumActionScopeTest { hasLiteSessionPlan() containsExactlyContextAttributes(fakeAttributes) hasSource(fakeSourceActionEvent) + hasDeviceInfo( + fakeAndroidInfoProvider.deviceName, + fakeAndroidInfoProvider.deviceModel, + fakeAndroidInfoProvider.deviceBrand, + fakeAndroidInfoProvider.deviceType.toActionSchemaType() + ) + hasOsInfo( + fakeAndroidInfoProvider.osName, + fakeAndroidInfoProvider.osVersion, + fakeAndroidInfoProvider.osMajorVersion + ) } } verify(mockParentScope, never()).handleEvent(any(), any()) @@ -1235,6 +1483,17 @@ internal class RumActionScopeTest { hasLiteSessionPlan() containsExactlyContextAttributes(fakeAttributes) hasSource(fakeSourceActionEvent) + hasDeviceInfo( + fakeAndroidInfoProvider.deviceName, + fakeAndroidInfoProvider.deviceModel, + fakeAndroidInfoProvider.deviceBrand, + fakeAndroidInfoProvider.deviceType.toActionSchemaType() + ) + hasOsInfo( + fakeAndroidInfoProvider.osName, + fakeAndroidInfoProvider.osVersion, + fakeAndroidInfoProvider.osMajorVersion + ) } } verify(mockParentScope, never()).handleEvent(any(), any()) @@ -1277,6 +1536,17 @@ internal class RumActionScopeTest { hasLiteSessionPlan() containsExactlyContextAttributes(fakeAttributes) hasSource(fakeSourceActionEvent) + hasDeviceInfo( + fakeAndroidInfoProvider.deviceName, + fakeAndroidInfoProvider.deviceModel, + fakeAndroidInfoProvider.deviceBrand, + fakeAndroidInfoProvider.deviceType.toActionSchemaType() + ) + hasOsInfo( + fakeAndroidInfoProvider.osName, + fakeAndroidInfoProvider.osVersion, + fakeAndroidInfoProvider.osMajorVersion + ) } } assertThat(result).isNull() @@ -1317,6 +1587,17 @@ internal class RumActionScopeTest { hasLiteSessionPlan() containsExactlyContextAttributes(fakeAttributes) hasSource(fakeSourceActionEvent) + hasDeviceInfo( + fakeAndroidInfoProvider.deviceName, + fakeAndroidInfoProvider.deviceModel, + fakeAndroidInfoProvider.deviceBrand, + fakeAndroidInfoProvider.deviceType.toActionSchemaType() + ) + hasOsInfo( + fakeAndroidInfoProvider.osName, + fakeAndroidInfoProvider.osVersion, + fakeAndroidInfoProvider.osMajorVersion + ) } } verify(mockParentScope, never()).handleEvent(any(), any()) @@ -1355,6 +1636,17 @@ internal class RumActionScopeTest { hasLiteSessionPlan() containsExactlyContextAttributes(fakeAttributes) hasSource(fakeSourceActionEvent) + hasDeviceInfo( + fakeAndroidInfoProvider.deviceName, + fakeAndroidInfoProvider.deviceModel, + fakeAndroidInfoProvider.deviceBrand, + fakeAndroidInfoProvider.deviceType.toActionSchemaType() + ) + hasOsInfo( + fakeAndroidInfoProvider.osName, + fakeAndroidInfoProvider.osVersion, + fakeAndroidInfoProvider.osMajorVersion + ) } } assertThat(result).isNull() @@ -1393,6 +1685,17 @@ internal class RumActionScopeTest { hasLiteSessionPlan() containsExactlyContextAttributes(fakeAttributes) hasSource(fakeSourceActionEvent) + hasDeviceInfo( + fakeAndroidInfoProvider.deviceName, + fakeAndroidInfoProvider.deviceModel, + fakeAndroidInfoProvider.deviceBrand, + fakeAndroidInfoProvider.deviceType.toActionSchemaType() + ) + hasOsInfo( + fakeAndroidInfoProvider.osName, + fakeAndroidInfoProvider.osVersion, + fakeAndroidInfoProvider.osMajorVersion + ) } } verify(mockParentScope, never()).handleEvent(any(), any()) @@ -1433,6 +1736,17 @@ internal class RumActionScopeTest { hasLiteSessionPlan() containsExactlyContextAttributes(fakeAttributes) hasSource(fakeSourceActionEvent) + hasDeviceInfo( + fakeAndroidInfoProvider.deviceName, + fakeAndroidInfoProvider.deviceModel, + fakeAndroidInfoProvider.deviceBrand, + fakeAndroidInfoProvider.deviceType.toActionSchemaType() + ) + hasOsInfo( + fakeAndroidInfoProvider.osName, + fakeAndroidInfoProvider.osVersion, + fakeAndroidInfoProvider.osMajorVersion + ) } } verify(mockParentScope, never()).handleEvent(any(), any()) @@ -1503,6 +1817,17 @@ internal class RumActionScopeTest { hasLiteSessionPlan() containsExactlyContextAttributes(fakeAttributes) hasSource(fakeSourceActionEvent) + hasDeviceInfo( + fakeAndroidInfoProvider.deviceName, + fakeAndroidInfoProvider.deviceModel, + fakeAndroidInfoProvider.deviceBrand, + fakeAndroidInfoProvider.deviceType.toActionSchemaType() + ) + hasOsInfo( + fakeAndroidInfoProvider.osName, + fakeAndroidInfoProvider.osVersion, + fakeAndroidInfoProvider.osMajorVersion + ) } } verify(mockParentScope, never()).handleEvent(any(), any()) @@ -1538,6 +1863,17 @@ internal class RumActionScopeTest { hasLiteSessionPlan() containsExactlyContextAttributes(fakeAttributes) hasSource(fakeSourceActionEvent) + hasDeviceInfo( + fakeAndroidInfoProvider.deviceName, + fakeAndroidInfoProvider.deviceModel, + fakeAndroidInfoProvider.deviceBrand, + fakeAndroidInfoProvider.deviceType.toActionSchemaType() + ) + hasOsInfo( + fakeAndroidInfoProvider.osName, + fakeAndroidInfoProvider.osVersion, + fakeAndroidInfoProvider.osMajorVersion + ) } } verify(mockParentScope, never()).handleEvent(any(), any()) @@ -1573,6 +1909,17 @@ internal class RumActionScopeTest { hasLiteSessionPlan() containsExactlyContextAttributes(fakeAttributes) hasSource(fakeSourceActionEvent) + hasDeviceInfo( + fakeAndroidInfoProvider.deviceName, + fakeAndroidInfoProvider.deviceModel, + fakeAndroidInfoProvider.deviceBrand, + fakeAndroidInfoProvider.deviceType.toActionSchemaType() + ) + hasOsInfo( + fakeAndroidInfoProvider.osName, + fakeAndroidInfoProvider.osVersion, + fakeAndroidInfoProvider.osMajorVersion + ) } } verify(mockParentScope, never()).handleEvent(any(), any()) @@ -1608,6 +1955,17 @@ internal class RumActionScopeTest { hasLiteSessionPlan() containsExactlyContextAttributes(fakeAttributes) hasSource(fakeSourceActionEvent) + hasDeviceInfo( + fakeAndroidInfoProvider.deviceName, + fakeAndroidInfoProvider.deviceModel, + fakeAndroidInfoProvider.deviceBrand, + fakeAndroidInfoProvider.deviceType.toActionSchemaType() + ) + hasOsInfo( + fakeAndroidInfoProvider.osName, + fakeAndroidInfoProvider.osVersion, + fakeAndroidInfoProvider.osMajorVersion + ) } } verify(mockParentScope, never()).handleEvent(any(), any()) diff --git a/dd-sdk-android/src/test/kotlin/com/datadog/android/rum/internal/domain/scope/RumApplicationScopeTest.kt b/dd-sdk-android/src/test/kotlin/com/datadog/android/rum/internal/domain/scope/RumApplicationScopeTest.kt index 857e419690..9763a10bef 100644 --- a/dd-sdk-android/src/test/kotlin/com/datadog/android/rum/internal/domain/scope/RumApplicationScopeTest.kt +++ b/dd-sdk-android/src/test/kotlin/com/datadog/android/rum/internal/domain/scope/RumApplicationScopeTest.kt @@ -8,6 +8,7 @@ package com.datadog.android.rum.internal.domain.scope import com.datadog.android.core.internal.net.FirstPartyHostDetector import com.datadog.android.core.internal.persistence.DataWriter +import com.datadog.android.core.internal.system.AndroidInfoProvider import com.datadog.android.core.internal.time.TimeProvider import com.datadog.android.rum.RumSessionListener import com.datadog.android.rum.internal.vitals.VitalMonitor @@ -21,7 +22,6 @@ import fr.xgouchet.elmyr.annotation.StringForgery import fr.xgouchet.elmyr.junit5.ForgeConfiguration import fr.xgouchet.elmyr.junit5.ForgeExtension import org.assertj.core.api.Assertions.assertThat -import org.junit.jupiter.api.AfterEach import org.junit.jupiter.api.BeforeEach import org.junit.jupiter.api.Test import org.junit.jupiter.api.extension.ExtendWith @@ -68,6 +68,9 @@ internal class RumApplicationScopeTest { @Mock lateinit var mockSessionListener: RumSessionListener + @Mock + lateinit var mockAndroidInfoProvider: AndroidInfoProvider + @StringForgery(regex = "[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}") lateinit var fakeApplicationId: String @@ -88,14 +91,11 @@ internal class RumApplicationScopeTest { mockMemoryVitalMonitor, mockFrameRateVitalMonitor, mockTimeProvider, - mockSessionListener + mockSessionListener, + mockAndroidInfoProvider ) } - @AfterEach - fun `tear down`() { - } - @Test fun `create child session scope with sampling rate`() { val childScope = testedScope.childScope @@ -110,7 +110,7 @@ internal class RumApplicationScopeTest { fun `always returns the same applicationId`() { val context = testedScope.getRumContext() - assertThat(context.applicationId).isEqualTo(fakeApplicationId.toString()) + assertThat(context.applicationId).isEqualTo(fakeApplicationId) } @Test diff --git a/dd-sdk-android/src/test/kotlin/com/datadog/android/rum/internal/domain/scope/RumContinuousActionScopeTest.kt b/dd-sdk-android/src/test/kotlin/com/datadog/android/rum/internal/domain/scope/RumContinuousActionScopeTest.kt index 381e90da9f..dc9e39d755 100644 --- a/dd-sdk-android/src/test/kotlin/com/datadog/android/rum/internal/domain/scope/RumContinuousActionScopeTest.kt +++ b/dd-sdk-android/src/test/kotlin/com/datadog/android/rum/internal/domain/scope/RumContinuousActionScopeTest.kt @@ -8,6 +8,7 @@ package com.datadog.android.rum.internal.domain.scope import android.content.Context import com.datadog.android.core.internal.persistence.DataWriter +import com.datadog.android.core.internal.system.AndroidInfoProvider import com.datadog.android.core.model.UserInfo import com.datadog.android.rum.GlobalRum import com.datadog.android.rum.RumActionType @@ -87,6 +88,9 @@ internal class RumContinuousActionScopeTest { @Forgery lateinit var fakeUserInfo: UserInfo + @Forgery + lateinit var fakeAndroidInfoProvider: AndroidInfoProvider + lateinit var fakeEventTime: Time lateinit var fakeEvent: RumRawEvent @@ -124,7 +128,8 @@ internal class RumContinuousActionScopeTest { fakeServerOffset, TEST_INACTIVITY_MS, TEST_MAX_DURATION_MS, - mockRumEventSourceProvider + mockRumEventSourceProvider, + fakeAndroidInfoProvider ) } @@ -207,6 +212,17 @@ internal class RumContinuousActionScopeTest { hasLiteSessionPlan() containsExactlyContextAttributes(fakeAttributes) hasSource(fakeSourceActionEvent) + hasDeviceInfo( + fakeAndroidInfoProvider.deviceName, + fakeAndroidInfoProvider.deviceModel, + fakeAndroidInfoProvider.deviceBrand, + fakeAndroidInfoProvider.deviceType.toActionSchemaType() + ) + hasOsInfo( + fakeAndroidInfoProvider.osName, + fakeAndroidInfoProvider.osVersion, + fakeAndroidInfoProvider.osMajorVersion + ) } } verify(mockParentScope, never()).handleEvent(any(), any()) @@ -254,6 +270,17 @@ internal class RumContinuousActionScopeTest { hasLiteSessionPlan() containsExactlyContextAttributes(expectedAttributes) hasSource(fakeSourceActionEvent) + hasDeviceInfo( + fakeAndroidInfoProvider.deviceName, + fakeAndroidInfoProvider.deviceModel, + fakeAndroidInfoProvider.deviceBrand, + fakeAndroidInfoProvider.deviceType.toActionSchemaType() + ) + hasOsInfo( + fakeAndroidInfoProvider.osName, + fakeAndroidInfoProvider.osVersion, + fakeAndroidInfoProvider.osMajorVersion + ) } } verify(mockParentScope, never()).handleEvent(any(), any()) @@ -300,6 +327,17 @@ internal class RumContinuousActionScopeTest { hasLiteSessionPlan() containsExactlyContextAttributes(expectedAttributes) hasSource(fakeSourceActionEvent) + hasDeviceInfo( + fakeAndroidInfoProvider.deviceName, + fakeAndroidInfoProvider.deviceModel, + fakeAndroidInfoProvider.deviceBrand, + fakeAndroidInfoProvider.deviceType.toActionSchemaType() + ) + hasOsInfo( + fakeAndroidInfoProvider.osName, + fakeAndroidInfoProvider.osVersion, + fakeAndroidInfoProvider.osMajorVersion + ) } } verify(mockParentScope, never()).handleEvent(any(), any()) @@ -349,6 +387,17 @@ internal class RumContinuousActionScopeTest { hasLiteSessionPlan() containsExactlyContextAttributes(fakeAttributes) hasSource(fakeSourceActionEvent) + hasDeviceInfo( + fakeAndroidInfoProvider.deviceName, + fakeAndroidInfoProvider.deviceModel, + fakeAndroidInfoProvider.deviceBrand, + fakeAndroidInfoProvider.deviceType.toActionSchemaType() + ) + hasOsInfo( + fakeAndroidInfoProvider.osName, + fakeAndroidInfoProvider.osVersion, + fakeAndroidInfoProvider.osMajorVersion + ) } } verify(mockParentScope, never()).handleEvent(any(), any()) @@ -408,6 +457,17 @@ internal class RumContinuousActionScopeTest { hasLiteSessionPlan() containsExactlyContextAttributes(fakeAttributes) hasSource(fakeSourceActionEvent) + hasDeviceInfo( + fakeAndroidInfoProvider.deviceName, + fakeAndroidInfoProvider.deviceModel, + fakeAndroidInfoProvider.deviceBrand, + fakeAndroidInfoProvider.deviceType.toActionSchemaType() + ) + hasOsInfo( + fakeAndroidInfoProvider.osName, + fakeAndroidInfoProvider.osVersion, + fakeAndroidInfoProvider.osMajorVersion + ) } } verify(mockParentScope, never()).handleEvent(any(), any()) @@ -471,6 +531,17 @@ internal class RumContinuousActionScopeTest { hasSessionId(fakeParentContext.sessionId) hasLiteSessionPlan() containsExactlyContextAttributes(fakeAttributes) + hasDeviceInfo( + fakeAndroidInfoProvider.deviceName, + fakeAndroidInfoProvider.deviceModel, + fakeAndroidInfoProvider.deviceBrand, + fakeAndroidInfoProvider.deviceType.toActionSchemaType() + ) + hasOsInfo( + fakeAndroidInfoProvider.osName, + fakeAndroidInfoProvider.osVersion, + fakeAndroidInfoProvider.osMajorVersion + ) } } verify(mockParentScope, never()).handleEvent(any(), any()) @@ -520,6 +591,17 @@ internal class RumContinuousActionScopeTest { hasLiteSessionPlan() containsExactlyContextAttributes(fakeAttributes) hasSource(fakeSourceActionEvent) + hasDeviceInfo( + fakeAndroidInfoProvider.deviceName, + fakeAndroidInfoProvider.deviceModel, + fakeAndroidInfoProvider.deviceBrand, + fakeAndroidInfoProvider.deviceType.toActionSchemaType() + ) + hasOsInfo( + fakeAndroidInfoProvider.osName, + fakeAndroidInfoProvider.osVersion, + fakeAndroidInfoProvider.osMajorVersion + ) } } verify(mockParentScope, never()).handleEvent(any(), any()) @@ -573,6 +655,17 @@ internal class RumContinuousActionScopeTest { hasLiteSessionPlan() containsExactlyContextAttributes(fakeAttributes) hasSource(fakeSourceActionEvent) + hasDeviceInfo( + fakeAndroidInfoProvider.deviceName, + fakeAndroidInfoProvider.deviceModel, + fakeAndroidInfoProvider.deviceBrand, + fakeAndroidInfoProvider.deviceType.toActionSchemaType() + ) + hasOsInfo( + fakeAndroidInfoProvider.osName, + fakeAndroidInfoProvider.osVersion, + fakeAndroidInfoProvider.osMajorVersion + ) } } verify(mockParentScope, never()).handleEvent(any(), any()) @@ -619,6 +712,17 @@ internal class RumContinuousActionScopeTest { hasLiteSessionPlan() containsExactlyContextAttributes(fakeAttributes) hasSource(fakeSourceActionEvent) + hasDeviceInfo( + fakeAndroidInfoProvider.deviceName, + fakeAndroidInfoProvider.deviceModel, + fakeAndroidInfoProvider.deviceBrand, + fakeAndroidInfoProvider.deviceType.toActionSchemaType() + ) + hasOsInfo( + fakeAndroidInfoProvider.osName, + fakeAndroidInfoProvider.osVersion, + fakeAndroidInfoProvider.osMajorVersion + ) } } verify(mockParentScope, never()).handleEvent(any(), any()) @@ -672,6 +776,17 @@ internal class RumContinuousActionScopeTest { hasLiteSessionPlan() containsExactlyContextAttributes(fakeAttributes) hasSource(fakeSourceActionEvent) + hasDeviceInfo( + fakeAndroidInfoProvider.deviceName, + fakeAndroidInfoProvider.deviceModel, + fakeAndroidInfoProvider.deviceBrand, + fakeAndroidInfoProvider.deviceType.toActionSchemaType() + ) + hasOsInfo( + fakeAndroidInfoProvider.osName, + fakeAndroidInfoProvider.osVersion, + fakeAndroidInfoProvider.osMajorVersion + ) } } verify(mockParentScope, never()).handleEvent(any(), any()) @@ -706,6 +821,17 @@ internal class RumContinuousActionScopeTest { hasLiteSessionPlan() containsExactlyContextAttributes(fakeAttributes) hasSource(fakeSourceActionEvent) + hasDeviceInfo( + fakeAndroidInfoProvider.deviceName, + fakeAndroidInfoProvider.deviceModel, + fakeAndroidInfoProvider.deviceBrand, + fakeAndroidInfoProvider.deviceType.toActionSchemaType() + ) + hasOsInfo( + fakeAndroidInfoProvider.osName, + fakeAndroidInfoProvider.osVersion, + fakeAndroidInfoProvider.osMajorVersion + ) } } verify(mockParentScope, never()).handleEvent(any(), any()) @@ -744,6 +870,17 @@ internal class RumContinuousActionScopeTest { hasLiteSessionPlan() containsExactlyContextAttributes(fakeAttributes) hasSource(fakeSourceActionEvent) + hasDeviceInfo( + fakeAndroidInfoProvider.deviceName, + fakeAndroidInfoProvider.deviceModel, + fakeAndroidInfoProvider.deviceBrand, + fakeAndroidInfoProvider.deviceType.toActionSchemaType() + ) + hasOsInfo( + fakeAndroidInfoProvider.osName, + fakeAndroidInfoProvider.osVersion, + fakeAndroidInfoProvider.osMajorVersion + ) } } verify(mockParentScope, never()).handleEvent(any(), any()) @@ -782,6 +919,17 @@ internal class RumContinuousActionScopeTest { hasLiteSessionPlan() containsExactlyContextAttributes(fakeAttributes) hasSource(fakeSourceActionEvent) + hasDeviceInfo( + fakeAndroidInfoProvider.deviceName, + fakeAndroidInfoProvider.deviceModel, + fakeAndroidInfoProvider.deviceBrand, + fakeAndroidInfoProvider.deviceType.toActionSchemaType() + ) + hasOsInfo( + fakeAndroidInfoProvider.osName, + fakeAndroidInfoProvider.osVersion, + fakeAndroidInfoProvider.osMajorVersion + ) } } verify(mockParentScope, never()).handleEvent(any(), any()) @@ -821,6 +969,17 @@ internal class RumContinuousActionScopeTest { hasLiteSessionPlan() containsExactlyContextAttributes(fakeAttributes) hasSource(fakeSourceActionEvent) + hasDeviceInfo( + fakeAndroidInfoProvider.deviceName, + fakeAndroidInfoProvider.deviceModel, + fakeAndroidInfoProvider.deviceBrand, + fakeAndroidInfoProvider.deviceType.toActionSchemaType() + ) + hasOsInfo( + fakeAndroidInfoProvider.osName, + fakeAndroidInfoProvider.osVersion, + fakeAndroidInfoProvider.osMajorVersion + ) } } verify(mockParentScope, never()).handleEvent(any(), any()) @@ -862,6 +1021,17 @@ internal class RumContinuousActionScopeTest { hasLiteSessionPlan() containsExactlyContextAttributes(fakeAttributes) hasSource(fakeSourceActionEvent) + hasDeviceInfo( + fakeAndroidInfoProvider.deviceName, + fakeAndroidInfoProvider.deviceModel, + fakeAndroidInfoProvider.deviceBrand, + fakeAndroidInfoProvider.deviceType.toActionSchemaType() + ) + hasOsInfo( + fakeAndroidInfoProvider.osName, + fakeAndroidInfoProvider.osVersion, + fakeAndroidInfoProvider.osMajorVersion + ) } } verify(mockParentScope, never()).handleEvent(any(), any()) @@ -898,6 +1068,17 @@ internal class RumContinuousActionScopeTest { hasLiteSessionPlan() containsExactlyContextAttributes(fakeAttributes) hasSource(fakeSourceActionEvent) + hasDeviceInfo( + fakeAndroidInfoProvider.deviceName, + fakeAndroidInfoProvider.deviceModel, + fakeAndroidInfoProvider.deviceBrand, + fakeAndroidInfoProvider.deviceType.toActionSchemaType() + ) + hasOsInfo( + fakeAndroidInfoProvider.osName, + fakeAndroidInfoProvider.osVersion, + fakeAndroidInfoProvider.osMajorVersion + ) } } verify(mockParentScope, never()).handleEvent(any(), any()) @@ -928,7 +1109,8 @@ internal class RumContinuousActionScopeTest { fakeServerOffset, TEST_INACTIVITY_MS, TEST_MAX_DURATION_MS, - mockRumEventSourceProvider + mockRumEventSourceProvider, + fakeAndroidInfoProvider ) fakeGlobalAttributes.keys.forEach { GlobalRum.globalAttributes.remove(it) } fakeEvent = RumRawEvent.StopAction(fakeType, fakeName, emptyMap()) @@ -959,6 +1141,17 @@ internal class RumContinuousActionScopeTest { hasLiteSessionPlan() containsExactlyContextAttributes(expectedAttributes) hasSource(fakeSourceActionEvent) + hasDeviceInfo( + fakeAndroidInfoProvider.deviceName, + fakeAndroidInfoProvider.deviceModel, + fakeAndroidInfoProvider.deviceBrand, + fakeAndroidInfoProvider.deviceType.toActionSchemaType() + ) + hasOsInfo( + fakeAndroidInfoProvider.osName, + fakeAndroidInfoProvider.osVersion, + fakeAndroidInfoProvider.osMajorVersion + ) } } verify(mockParentScope, never()).handleEvent(any(), any()) @@ -1007,6 +1200,17 @@ internal class RumContinuousActionScopeTest { hasLiteSessionPlan() containsExactlyContextAttributes(expectedAttributes) hasSource(fakeSourceActionEvent) + hasDeviceInfo( + fakeAndroidInfoProvider.deviceName, + fakeAndroidInfoProvider.deviceModel, + fakeAndroidInfoProvider.deviceBrand, + fakeAndroidInfoProvider.deviceType.toActionSchemaType() + ) + hasOsInfo( + fakeAndroidInfoProvider.osName, + fakeAndroidInfoProvider.osVersion, + fakeAndroidInfoProvider.osMajorVersion + ) } } verify(mockParentScope, never()).handleEvent(any(), any()) @@ -1049,6 +1253,17 @@ internal class RumContinuousActionScopeTest { hasLiteSessionPlan() containsExactlyContextAttributes(fakeAttributes) hasSource(fakeSourceActionEvent) + hasDeviceInfo( + fakeAndroidInfoProvider.deviceName, + fakeAndroidInfoProvider.deviceModel, + fakeAndroidInfoProvider.deviceBrand, + fakeAndroidInfoProvider.deviceType.toActionSchemaType() + ) + hasOsInfo( + fakeAndroidInfoProvider.osName, + fakeAndroidInfoProvider.osVersion, + fakeAndroidInfoProvider.osMajorVersion + ) } } verify(mockParentScope, never()).handleEvent(any(), any()) @@ -1091,6 +1306,17 @@ internal class RumContinuousActionScopeTest { hasLiteSessionPlan() containsExactlyContextAttributes(fakeAttributes) hasSource(fakeSourceActionEvent) + hasDeviceInfo( + fakeAndroidInfoProvider.deviceName, + fakeAndroidInfoProvider.deviceModel, + fakeAndroidInfoProvider.deviceBrand, + fakeAndroidInfoProvider.deviceType.toActionSchemaType() + ) + hasOsInfo( + fakeAndroidInfoProvider.osName, + fakeAndroidInfoProvider.osVersion, + fakeAndroidInfoProvider.osMajorVersion + ) } } verify(mockParentScope, never()).handleEvent(any(), any()) @@ -1134,6 +1360,17 @@ internal class RumContinuousActionScopeTest { hasLiteSessionPlan() containsExactlyContextAttributes(fakeAttributes) hasSource(fakeSourceActionEvent) + hasDeviceInfo( + fakeAndroidInfoProvider.deviceName, + fakeAndroidInfoProvider.deviceModel, + fakeAndroidInfoProvider.deviceBrand, + fakeAndroidInfoProvider.deviceType.toActionSchemaType() + ) + hasOsInfo( + fakeAndroidInfoProvider.osName, + fakeAndroidInfoProvider.osVersion, + fakeAndroidInfoProvider.osMajorVersion + ) } } verify(mockParentScope, never()).handleEvent(any(), any()) @@ -1174,6 +1411,17 @@ internal class RumContinuousActionScopeTest { hasLiteSessionPlan() containsExactlyContextAttributes(fakeAttributes) hasSource(fakeSourceActionEvent) + hasDeviceInfo( + fakeAndroidInfoProvider.deviceName, + fakeAndroidInfoProvider.deviceModel, + fakeAndroidInfoProvider.deviceBrand, + fakeAndroidInfoProvider.deviceType.toActionSchemaType() + ) + hasOsInfo( + fakeAndroidInfoProvider.osName, + fakeAndroidInfoProvider.osVersion, + fakeAndroidInfoProvider.osMajorVersion + ) } } verify(mockParentScope, never()).handleEvent(any(), any()) @@ -1218,6 +1466,17 @@ internal class RumContinuousActionScopeTest { hasLiteSessionPlan() containsExactlyContextAttributes(fakeAttributes) hasSource(fakeSourceActionEvent) + hasDeviceInfo( + fakeAndroidInfoProvider.deviceName, + fakeAndroidInfoProvider.deviceModel, + fakeAndroidInfoProvider.deviceBrand, + fakeAndroidInfoProvider.deviceType.toActionSchemaType() + ) + hasOsInfo( + fakeAndroidInfoProvider.osName, + fakeAndroidInfoProvider.osVersion, + fakeAndroidInfoProvider.osMajorVersion + ) } } verify(mockParentScope, never()).handleEvent(any(), any()) @@ -1258,6 +1517,17 @@ internal class RumContinuousActionScopeTest { hasLiteSessionPlan() containsExactlyContextAttributes(fakeAttributes) hasSource(fakeSourceActionEvent) + hasDeviceInfo( + fakeAndroidInfoProvider.deviceName, + fakeAndroidInfoProvider.deviceModel, + fakeAndroidInfoProvider.deviceBrand, + fakeAndroidInfoProvider.deviceType.toActionSchemaType() + ) + hasOsInfo( + fakeAndroidInfoProvider.osName, + fakeAndroidInfoProvider.osVersion, + fakeAndroidInfoProvider.osMajorVersion + ) } } verify(mockParentScope, never()).handleEvent(any(), any()) @@ -1365,6 +1635,17 @@ internal class RumContinuousActionScopeTest { hasLiteSessionPlan() containsExactlyContextAttributes(fakeAttributes) hasSource(fakeSourceActionEvent) + hasDeviceInfo( + fakeAndroidInfoProvider.deviceName, + fakeAndroidInfoProvider.deviceModel, + fakeAndroidInfoProvider.deviceBrand, + fakeAndroidInfoProvider.deviceType.toActionSchemaType() + ) + hasOsInfo( + fakeAndroidInfoProvider.osName, + fakeAndroidInfoProvider.osVersion, + fakeAndroidInfoProvider.osMajorVersion + ) } } verify(mockParentScope, never()).handleEvent(any(), any()) @@ -1409,6 +1690,17 @@ internal class RumContinuousActionScopeTest { hasLiteSessionPlan() containsExactlyContextAttributes(fakeAttributes) hasSource(fakeSourceActionEvent) + hasDeviceInfo( + fakeAndroidInfoProvider.deviceName, + fakeAndroidInfoProvider.deviceModel, + fakeAndroidInfoProvider.deviceBrand, + fakeAndroidInfoProvider.deviceType.toActionSchemaType() + ) + hasOsInfo( + fakeAndroidInfoProvider.osName, + fakeAndroidInfoProvider.osVersion, + fakeAndroidInfoProvider.osMajorVersion + ) } } verify(mockParentScope, never()).handleEvent(any(), any()) @@ -1447,6 +1739,17 @@ internal class RumContinuousActionScopeTest { hasLiteSessionPlan() containsExactlyContextAttributes(fakeAttributes) hasSource(fakeSourceActionEvent) + hasDeviceInfo( + fakeAndroidInfoProvider.deviceName, + fakeAndroidInfoProvider.deviceModel, + fakeAndroidInfoProvider.deviceBrand, + fakeAndroidInfoProvider.deviceType.toActionSchemaType() + ) + hasOsInfo( + fakeAndroidInfoProvider.osName, + fakeAndroidInfoProvider.osVersion, + fakeAndroidInfoProvider.osMajorVersion + ) } } verify(mockParentScope, never()).handleEvent(any(), any()) diff --git a/dd-sdk-android/src/test/kotlin/com/datadog/android/rum/internal/domain/scope/RumEventExtTest.kt b/dd-sdk-android/src/test/kotlin/com/datadog/android/rum/internal/domain/scope/RumEventExtTest.kt index 745e4a88f8..e8bc479393 100644 --- a/dd-sdk-android/src/test/kotlin/com/datadog/android/rum/internal/domain/scope/RumEventExtTest.kt +++ b/dd-sdk-android/src/test/kotlin/com/datadog/android/rum/internal/domain/scope/RumEventExtTest.kt @@ -6,6 +6,7 @@ package com.datadog.android.rum.internal.domain.scope +import com.datadog.android.core.internal.system.DeviceType import com.datadog.android.core.model.NetworkInfo import com.datadog.android.rum.RumActionType import com.datadog.android.rum.RumErrorSource @@ -597,4 +598,68 @@ internal class RumEventExtTest { ) ) } + + // region device type conversion + + @ParameterizedTest + @EnumSource(DeviceType::class) + fun `𝕄 return schema device type 𝕎 toViewSchemaType()`( + deviceType: DeviceType + ) { + // When + val schemaDeviceType = deviceType.toViewSchemaType() + + // Then + assertThat(schemaDeviceType.name).isEqualTo(deviceType.name) + } + + @ParameterizedTest + @EnumSource(DeviceType::class) + fun `𝕄 return schema device type 𝕎 toActionSchemaType()`( + deviceType: DeviceType + ) { + // When + val schemaDeviceType = deviceType.toActionSchemaType() + + // Then + assertThat(schemaDeviceType.name).isEqualTo(deviceType.name) + } + + @ParameterizedTest + @EnumSource(DeviceType::class) + fun `𝕄 return schema device type 𝕎 toLongTaskSchemaType()`( + deviceType: DeviceType + ) { + // When + val schemaDeviceType = deviceType.toLongTaskSchemaType() + + // Then + assertThat(schemaDeviceType.name).isEqualTo(deviceType.name) + } + + @ParameterizedTest + @EnumSource(DeviceType::class) + fun `𝕄 return schema device type 𝕎 toResourceSchemaType()`( + deviceType: DeviceType + ) { + // When + val schemaDeviceType = deviceType.toResourceSchemaType() + + // Then + assertThat(schemaDeviceType.name).isEqualTo(deviceType.name) + } + + @ParameterizedTest + @EnumSource(DeviceType::class) + fun `𝕄 return schema device type 𝕎 toErrorSchemaType()`( + deviceType: DeviceType + ) { + // When + val schemaDeviceType = deviceType.toErrorSchemaType() + + // Then + assertThat(schemaDeviceType.name).isEqualTo(deviceType.name) + } + + // endregion } diff --git a/dd-sdk-android/src/test/kotlin/com/datadog/android/rum/internal/domain/scope/RumResourceScopeTest.kt b/dd-sdk-android/src/test/kotlin/com/datadog/android/rum/internal/domain/scope/RumResourceScopeTest.kt index a8b2ec1a3e..e4e0ec73ab 100644 --- a/dd-sdk-android/src/test/kotlin/com/datadog/android/rum/internal/domain/scope/RumResourceScopeTest.kt +++ b/dd-sdk-android/src/test/kotlin/com/datadog/android/rum/internal/domain/scope/RumResourceScopeTest.kt @@ -10,6 +10,7 @@ import android.content.Context import android.util.Log import com.datadog.android.core.internal.net.FirstPartyHostDetector import com.datadog.android.core.internal.persistence.DataWriter +import com.datadog.android.core.internal.system.AndroidInfoProvider import com.datadog.android.core.internal.utils.loggableStackTrace import com.datadog.android.core.model.NetworkInfo import com.datadog.android.core.model.UserInfo @@ -104,6 +105,9 @@ internal class RumResourceScopeTest { @Forgery lateinit var fakeNetworkInfo: NetworkInfo + @Forgery + lateinit var fakeAndroidInfoProvider: AndroidInfoProvider + var fakeServerOffset: Long = 0L private lateinit var fakeEventTime: Time @@ -148,7 +152,8 @@ internal class RumResourceScopeTest { fakeAttributes, fakeServerOffset, mockDetector, - mockRumEventSourceProvider + mockRumEventSourceProvider, + fakeAndroidInfoProvider ) } @@ -218,6 +223,17 @@ internal class RumResourceScopeTest { hasLiteSessionPlan() containsExactlyContextAttributes(expectedAttributes) hasSource(fakeSourceResourceEvent) + hasDeviceInfo( + fakeAndroidInfoProvider.deviceName, + fakeAndroidInfoProvider.deviceModel, + fakeAndroidInfoProvider.deviceBrand, + fakeAndroidInfoProvider.deviceType.toResourceSchemaType() + ) + hasOsInfo( + fakeAndroidInfoProvider.osName, + fakeAndroidInfoProvider.osVersion, + fakeAndroidInfoProvider.osMajorVersion + ) } } verify(mockParentScope, never()).handleEvent(any(), any()) @@ -269,6 +285,17 @@ internal class RumResourceScopeTest { hasLiteSessionPlan() containsExactlyContextAttributes(expectedAttributes) hasSource(fakeSourceResourceEvent) + hasDeviceInfo( + fakeAndroidInfoProvider.deviceName, + fakeAndroidInfoProvider.deviceModel, + fakeAndroidInfoProvider.deviceBrand, + fakeAndroidInfoProvider.deviceType.toResourceSchemaType() + ) + hasOsInfo( + fakeAndroidInfoProvider.osName, + fakeAndroidInfoProvider.osVersion, + fakeAndroidInfoProvider.osMajorVersion + ) } } verify(mockParentScope, never()).handleEvent(any(), any()) @@ -294,7 +321,8 @@ internal class RumResourceScopeTest { fakeAttributes, fakeServerOffset, mockDetector, - mockRumEventSourceProvider + mockRumEventSourceProvider, + fakeAndroidInfoProvider ) doAnswer { true }.whenever(mockDetector).isFirstPartyUrl(brokenUrl) val attributes = forge.exhaustiveAttributes(excludedKeys = fakeAttributes.keys) @@ -332,6 +360,17 @@ internal class RumResourceScopeTest { hasLiteSessionPlan() containsExactlyContextAttributes(expectedAttributes) hasSource(fakeSourceResourceEvent) + hasDeviceInfo( + fakeAndroidInfoProvider.deviceName, + fakeAndroidInfoProvider.deviceModel, + fakeAndroidInfoProvider.deviceBrand, + fakeAndroidInfoProvider.deviceType.toResourceSchemaType() + ) + hasOsInfo( + fakeAndroidInfoProvider.osName, + fakeAndroidInfoProvider.osVersion, + fakeAndroidInfoProvider.osMajorVersion + ) } } verify(mockParentScope, never()).handleEvent(any(), any()) @@ -386,6 +425,17 @@ internal class RumResourceScopeTest { hasLiteSessionPlan() containsExactlyContextAttributes(expectedAttributes) hasSource(fakeSourceResourceEvent) + hasDeviceInfo( + fakeAndroidInfoProvider.deviceName, + fakeAndroidInfoProvider.deviceModel, + fakeAndroidInfoProvider.deviceBrand, + fakeAndroidInfoProvider.deviceType.toResourceSchemaType() + ) + hasOsInfo( + fakeAndroidInfoProvider.osName, + fakeAndroidInfoProvider.osVersion, + fakeAndroidInfoProvider.osMajorVersion + ) } } verify(mockParentScope, never()).handleEvent(any(), any()) @@ -437,6 +487,17 @@ internal class RumResourceScopeTest { hasLiteSessionPlan() containsExactlyContextAttributes(expectedAttributes) hasSource(fakeSourceResourceEvent) + hasDeviceInfo( + fakeAndroidInfoProvider.deviceName, + fakeAndroidInfoProvider.deviceModel, + fakeAndroidInfoProvider.deviceBrand, + fakeAndroidInfoProvider.deviceType.toResourceSchemaType() + ) + hasOsInfo( + fakeAndroidInfoProvider.osName, + fakeAndroidInfoProvider.osVersion, + fakeAndroidInfoProvider.osMajorVersion + ) } } verify(mockParentScope, never()).handleEvent(any(), any()) @@ -479,6 +540,17 @@ internal class RumResourceScopeTest { hasLiteSessionPlan() containsExactlyContextAttributes(fakeAttributes) hasSource(fakeSourceResourceEvent) + hasDeviceInfo( + fakeAndroidInfoProvider.deviceName, + fakeAndroidInfoProvider.deviceModel, + fakeAndroidInfoProvider.deviceBrand, + fakeAndroidInfoProvider.deviceType.toResourceSchemaType() + ) + hasOsInfo( + fakeAndroidInfoProvider.osName, + fakeAndroidInfoProvider.osVersion, + fakeAndroidInfoProvider.osMajorVersion + ) } } verify(mockParentScope, never()).handleEvent(any(), any()) @@ -513,6 +585,17 @@ internal class RumResourceScopeTest { hasLiteSessionPlan() containsExactlyContextAttributes(fakeAttributes) hasSource(fakeSourceResourceEvent) + hasDeviceInfo( + fakeAndroidInfoProvider.deviceName, + fakeAndroidInfoProvider.deviceModel, + fakeAndroidInfoProvider.deviceBrand, + fakeAndroidInfoProvider.deviceType.toResourceSchemaType() + ) + hasOsInfo( + fakeAndroidInfoProvider.osName, + fakeAndroidInfoProvider.osVersion, + fakeAndroidInfoProvider.osMajorVersion + ) } } verify(mockParentScope, never()).handleEvent(any(), any()) @@ -585,7 +668,8 @@ internal class RumResourceScopeTest { fakeAttributes, fakeServerOffset, mockDetector, - mockRumEventSourceProvider + mockRumEventSourceProvider, + fakeAndroidInfoProvider ) fakeGlobalAttributes.keys.forEach { GlobalRum.removeAttribute(it) } @@ -618,6 +702,17 @@ internal class RumResourceScopeTest { hasLiteSessionPlan() containsExactlyContextAttributes(expectedAttributes) hasSource(fakeSourceResourceEvent) + hasDeviceInfo( + fakeAndroidInfoProvider.deviceName, + fakeAndroidInfoProvider.deviceModel, + fakeAndroidInfoProvider.deviceBrand, + fakeAndroidInfoProvider.deviceType.toResourceSchemaType() + ) + hasOsInfo( + fakeAndroidInfoProvider.osName, + fakeAndroidInfoProvider.osVersion, + fakeAndroidInfoProvider.osMajorVersion + ) } } verify(mockParentScope, never()).handleEvent(any(), any()) @@ -670,6 +765,17 @@ internal class RumResourceScopeTest { hasLiteSessionPlan() containsExactlyContextAttributes(expectedAttributes) hasSource(fakeSourceResourceEvent) + hasDeviceInfo( + fakeAndroidInfoProvider.deviceName, + fakeAndroidInfoProvider.deviceModel, + fakeAndroidInfoProvider.deviceBrand, + fakeAndroidInfoProvider.deviceType.toResourceSchemaType() + ) + hasOsInfo( + fakeAndroidInfoProvider.osName, + fakeAndroidInfoProvider.osVersion, + fakeAndroidInfoProvider.osMajorVersion + ) } } verify(mockParentScope, never()).handleEvent(any(), any()) @@ -723,6 +829,17 @@ internal class RumResourceScopeTest { hasLiteSessionPlan() containsExactlyContextAttributes(expectedAttributes) hasSource(fakeSourceResourceEvent) + hasDeviceInfo( + fakeAndroidInfoProvider.deviceName, + fakeAndroidInfoProvider.deviceModel, + fakeAndroidInfoProvider.deviceBrand, + fakeAndroidInfoProvider.deviceType.toResourceSchemaType() + ) + hasOsInfo( + fakeAndroidInfoProvider.osName, + fakeAndroidInfoProvider.osVersion, + fakeAndroidInfoProvider.osMajorVersion + ) } } verify(mockParentScope, never()).handleEvent(any(), any()) @@ -777,6 +894,17 @@ internal class RumResourceScopeTest { hasLiteSessionPlan() containsExactlyContextAttributes(expectedAttributes) hasSource(fakeSourceResourceEvent) + hasDeviceInfo( + fakeAndroidInfoProvider.deviceName, + fakeAndroidInfoProvider.deviceModel, + fakeAndroidInfoProvider.deviceBrand, + fakeAndroidInfoProvider.deviceType.toResourceSchemaType() + ) + hasOsInfo( + fakeAndroidInfoProvider.osName, + fakeAndroidInfoProvider.osVersion, + fakeAndroidInfoProvider.osMajorVersion + ) } } verify(mockParentScope, never()).handleEvent(any(), any()) @@ -832,6 +960,17 @@ internal class RumResourceScopeTest { hasLiteSessionPlan() containsExactlyContextAttributes(expectedAttributes) hasSource(fakeSourceErrorEvent) + hasDeviceInfo( + fakeAndroidInfoProvider.deviceName, + fakeAndroidInfoProvider.deviceModel, + fakeAndroidInfoProvider.deviceBrand, + fakeAndroidInfoProvider.deviceType.toErrorSchemaType() + ) + hasOsInfo( + fakeAndroidInfoProvider.osName, + fakeAndroidInfoProvider.osVersion, + fakeAndroidInfoProvider.osMajorVersion + ) } } verify(mockParentScope, never()).handleEvent(any(), any()) @@ -887,6 +1026,17 @@ internal class RumResourceScopeTest { hasErrorSourceType(ErrorEvent.SourceType.ANDROID) hasLiteSessionPlan() containsExactlyContextAttributes(expectedAttributes) + hasDeviceInfo( + fakeAndroidInfoProvider.deviceName, + fakeAndroidInfoProvider.deviceModel, + fakeAndroidInfoProvider.deviceBrand, + fakeAndroidInfoProvider.deviceType.toErrorSchemaType() + ) + hasOsInfo( + fakeAndroidInfoProvider.osName, + fakeAndroidInfoProvider.osVersion, + fakeAndroidInfoProvider.osMajorVersion + ) } } verify(mockParentScope, never()).handleEvent(any(), any()) @@ -912,7 +1062,8 @@ internal class RumResourceScopeTest { fakeAttributes, fakeServerOffset, mockDetector, - mockRumEventSourceProvider + mockRumEventSourceProvider, + fakeAndroidInfoProvider ) doAnswer { true }.whenever(mockDetector).isFirstPartyUrl(brokenUrl) val attributes = forge.exhaustiveAttributes(excludedKeys = fakeAttributes.keys) @@ -956,6 +1107,17 @@ internal class RumResourceScopeTest { hasLiteSessionPlan() containsExactlyContextAttributes(expectedAttributes) hasSource(fakeSourceErrorEvent) + hasDeviceInfo( + fakeAndroidInfoProvider.deviceName, + fakeAndroidInfoProvider.deviceModel, + fakeAndroidInfoProvider.deviceBrand, + fakeAndroidInfoProvider.deviceType.toErrorSchemaType() + ) + hasOsInfo( + fakeAndroidInfoProvider.osName, + fakeAndroidInfoProvider.osVersion, + fakeAndroidInfoProvider.osMajorVersion + ) } } verify(mockParentScope, never()).handleEvent(any(), any()) @@ -982,7 +1144,8 @@ internal class RumResourceScopeTest { fakeAttributes, fakeServerOffset, mockDetector, - mockRumEventSourceProvider + mockRumEventSourceProvider, + fakeAndroidInfoProvider ) doAnswer { true }.whenever(mockDetector).isFirstPartyUrl(brokenUrl) val attributes = forge.exhaustiveAttributes(excludedKeys = fakeAttributes.keys) @@ -1026,6 +1189,17 @@ internal class RumResourceScopeTest { hasErrorSourceType(ErrorEvent.SourceType.ANDROID) hasLiteSessionPlan() containsExactlyContextAttributes(expectedAttributes) + hasDeviceInfo( + fakeAndroidInfoProvider.deviceName, + fakeAndroidInfoProvider.deviceModel, + fakeAndroidInfoProvider.deviceBrand, + fakeAndroidInfoProvider.deviceType.toErrorSchemaType() + ) + hasOsInfo( + fakeAndroidInfoProvider.osName, + fakeAndroidInfoProvider.osVersion, + fakeAndroidInfoProvider.osMajorVersion + ) } } verify(mockParentScope, never()).handleEvent(any(), any()) @@ -1084,6 +1258,17 @@ internal class RumResourceScopeTest { hasLiteSessionPlan() containsExactlyContextAttributes(expectedAttributes) hasSource(fakeSourceErrorEvent) + hasDeviceInfo( + fakeAndroidInfoProvider.deviceName, + fakeAndroidInfoProvider.deviceModel, + fakeAndroidInfoProvider.deviceBrand, + fakeAndroidInfoProvider.deviceType.toErrorSchemaType() + ) + hasOsInfo( + fakeAndroidInfoProvider.osName, + fakeAndroidInfoProvider.osVersion, + fakeAndroidInfoProvider.osMajorVersion + ) } } verify(mockParentScope, never()).handleEvent(any(), any()) @@ -1142,6 +1327,17 @@ internal class RumResourceScopeTest { hasErrorSourceType(ErrorEvent.SourceType.ANDROID) hasLiteSessionPlan() containsExactlyContextAttributes(expectedAttributes) + hasDeviceInfo( + fakeAndroidInfoProvider.deviceName, + fakeAndroidInfoProvider.deviceModel, + fakeAndroidInfoProvider.deviceBrand, + fakeAndroidInfoProvider.deviceType.toErrorSchemaType() + ) + hasOsInfo( + fakeAndroidInfoProvider.osName, + fakeAndroidInfoProvider.osVersion, + fakeAndroidInfoProvider.osMajorVersion + ) } } verify(mockParentScope, never()).handleEvent(any(), any()) @@ -1199,6 +1395,17 @@ internal class RumResourceScopeTest { hasLiteSessionPlan() containsExactlyContextAttributes(expectedAttributes) hasSource(fakeSourceErrorEvent) + hasDeviceInfo( + fakeAndroidInfoProvider.deviceName, + fakeAndroidInfoProvider.deviceModel, + fakeAndroidInfoProvider.deviceBrand, + fakeAndroidInfoProvider.deviceType.toErrorSchemaType() + ) + hasOsInfo( + fakeAndroidInfoProvider.osName, + fakeAndroidInfoProvider.osVersion, + fakeAndroidInfoProvider.osMajorVersion + ) } } verify(mockParentScope, never()).handleEvent(any(), any()) @@ -1257,6 +1464,17 @@ internal class RumResourceScopeTest { doesNotHaveAResourceProvider() hasLiteSessionPlan() containsExactlyContextAttributes(expectedAttributes) + hasDeviceInfo( + fakeAndroidInfoProvider.deviceName, + fakeAndroidInfoProvider.deviceModel, + fakeAndroidInfoProvider.deviceBrand, + fakeAndroidInfoProvider.deviceType.toErrorSchemaType() + ) + hasOsInfo( + fakeAndroidInfoProvider.osName, + fakeAndroidInfoProvider.osVersion, + fakeAndroidInfoProvider.osMajorVersion + ) } } verify(mockParentScope, never()).handleEvent(any(), any()) @@ -1320,6 +1538,17 @@ internal class RumResourceScopeTest { hasLiteSessionPlan() containsExactlyContextAttributes(expectedAttributes) hasSource(fakeSourceErrorEvent) + hasDeviceInfo( + fakeAndroidInfoProvider.deviceName, + fakeAndroidInfoProvider.deviceModel, + fakeAndroidInfoProvider.deviceBrand, + fakeAndroidInfoProvider.deviceType.toErrorSchemaType() + ) + hasOsInfo( + fakeAndroidInfoProvider.osName, + fakeAndroidInfoProvider.osVersion, + fakeAndroidInfoProvider.osMajorVersion + ) } } verify(mockParentScope, never()).handleEvent(any(), any()) @@ -1384,6 +1613,17 @@ internal class RumResourceScopeTest { doesNotHaveAResourceProvider() hasLiteSessionPlan() containsExactlyContextAttributes(expectedAttributes) + hasDeviceInfo( + fakeAndroidInfoProvider.deviceName, + fakeAndroidInfoProvider.deviceModel, + fakeAndroidInfoProvider.deviceBrand, + fakeAndroidInfoProvider.deviceType.toErrorSchemaType() + ) + hasOsInfo( + fakeAndroidInfoProvider.osName, + fakeAndroidInfoProvider.osVersion, + fakeAndroidInfoProvider.osMajorVersion + ) } } verify(mockParentScope, never()).handleEvent(any(), any()) @@ -1525,6 +1765,17 @@ internal class RumResourceScopeTest { hasLiteSessionPlan() containsExactlyContextAttributes(expectedAttributes) hasSource(fakeSourceResourceEvent) + hasDeviceInfo( + fakeAndroidInfoProvider.deviceName, + fakeAndroidInfoProvider.deviceModel, + fakeAndroidInfoProvider.deviceBrand, + fakeAndroidInfoProvider.deviceType.toResourceSchemaType() + ) + hasOsInfo( + fakeAndroidInfoProvider.osName, + fakeAndroidInfoProvider.osVersion, + fakeAndroidInfoProvider.osMajorVersion + ) } } verifyNoMoreInteractions(mockWriter) @@ -1574,6 +1825,17 @@ internal class RumResourceScopeTest { hasLiteSessionPlan() containsExactlyContextAttributes(expectedAttributes) hasSource(fakeSourceResourceEvent) + hasDeviceInfo( + fakeAndroidInfoProvider.deviceName, + fakeAndroidInfoProvider.deviceModel, + fakeAndroidInfoProvider.deviceBrand, + fakeAndroidInfoProvider.deviceType.toResourceSchemaType() + ) + hasOsInfo( + fakeAndroidInfoProvider.osName, + fakeAndroidInfoProvider.osVersion, + fakeAndroidInfoProvider.osMajorVersion + ) } } verifyNoMoreInteractions(mockWriter) @@ -1625,6 +1887,17 @@ internal class RumResourceScopeTest { hasLiteSessionPlan() containsExactlyContextAttributes(expectedAttributes) hasSource(fakeSourceResourceEvent) + hasDeviceInfo( + fakeAndroidInfoProvider.deviceName, + fakeAndroidInfoProvider.deviceModel, + fakeAndroidInfoProvider.deviceBrand, + fakeAndroidInfoProvider.deviceType.toResourceSchemaType() + ) + hasOsInfo( + fakeAndroidInfoProvider.osName, + fakeAndroidInfoProvider.osVersion, + fakeAndroidInfoProvider.osMajorVersion + ) } } verifyNoMoreInteractions(mockWriter) @@ -1724,6 +1997,17 @@ internal class RumResourceScopeTest { doesNotHaveAResourceProvider() hasLiteSessionPlan() hasSource(fakeSourceResourceEvent) + hasDeviceInfo( + fakeAndroidInfoProvider.deviceName, + fakeAndroidInfoProvider.deviceModel, + fakeAndroidInfoProvider.deviceBrand, + fakeAndroidInfoProvider.deviceType.toResourceSchemaType() + ) + hasOsInfo( + fakeAndroidInfoProvider.osName, + fakeAndroidInfoProvider.osVersion, + fakeAndroidInfoProvider.osMajorVersion + ) } } verify(mockParentScope, never()).handleEvent(any(), any()) @@ -1772,6 +2056,17 @@ internal class RumResourceScopeTest { doesNotHaveAResourceProvider() hasLiteSessionPlan() hasSource(fakeSourceResourceEvent) + hasDeviceInfo( + fakeAndroidInfoProvider.deviceName, + fakeAndroidInfoProvider.deviceModel, + fakeAndroidInfoProvider.deviceBrand, + fakeAndroidInfoProvider.deviceType.toResourceSchemaType() + ) + hasOsInfo( + fakeAndroidInfoProvider.osName, + fakeAndroidInfoProvider.osVersion, + fakeAndroidInfoProvider.osMajorVersion + ) } } verify(mockParentScope, never()).handleEvent(any(), any()) diff --git a/dd-sdk-android/src/test/kotlin/com/datadog/android/rum/internal/domain/scope/RumSessionScopeTest.kt b/dd-sdk-android/src/test/kotlin/com/datadog/android/rum/internal/domain/scope/RumSessionScopeTest.kt index 98dd882184..e23632040d 100644 --- a/dd-sdk-android/src/test/kotlin/com/datadog/android/rum/internal/domain/scope/RumSessionScopeTest.kt +++ b/dd-sdk-android/src/test/kotlin/com/datadog/android/rum/internal/domain/scope/RumSessionScopeTest.kt @@ -15,6 +15,7 @@ import com.datadog.android.core.internal.CoreFeature import com.datadog.android.core.internal.net.FirstPartyHostDetector import com.datadog.android.core.internal.persistence.DataWriter import com.datadog.android.core.internal.persistence.NoOpDataWriter +import com.datadog.android.core.internal.system.AndroidInfoProvider import com.datadog.android.core.internal.system.BuildSdkVersionProvider import com.datadog.android.core.internal.time.TimeProvider import com.datadog.android.core.model.NetworkInfo @@ -125,6 +126,9 @@ internal class RumSessionScopeTest { @Forgery lateinit var fakeNetworkInfo: NetworkInfo + @Forgery + lateinit var fakeAndroidInfoProvider: AndroidInfoProvider + @FloatForgery(min = 0f, max = 100f) var fakeSamplingRate: Float = 0f @@ -156,7 +160,8 @@ internal class RumSessionScopeTest { mockRumEventSourceProvider, mockBuildSdkVersionProvider, TEST_INACTIVITY_NS, - TEST_MAX_DURATION_NS + TEST_MAX_DURATION_NS, + fakeAndroidInfoProvider ) val originalRumContext = testedScope.getRumContext() assertThat(GlobalRum.getRumContext()).isEqualTo(originalRumContext) @@ -190,7 +195,8 @@ internal class RumSessionScopeTest { mockRumEventSourceProvider, mockBuildSdkVersionProvider, TEST_INACTIVITY_NS, - TEST_MAX_DURATION_NS + TEST_MAX_DURATION_NS, + fakeAndroidInfoProvider ) val context = testedScope.getRumContext() @@ -291,7 +297,8 @@ internal class RumSessionScopeTest { mockRumEventSourceProvider, mockBuildSdkVersionProvider, TEST_INACTIVITY_NS, - TEST_MAX_DURATION_NS + TEST_MAX_DURATION_NS, + fakeAndroidInfoProvider ) var sessions = 0 var sessionsKept = 0 @@ -387,7 +394,8 @@ internal class RumSessionScopeTest { mockRumEventSourceProvider, mockBuildSdkVersionProvider, TEST_INACTIVITY_NS, - TEST_MAX_DURATION_NS + TEST_MAX_DURATION_NS, + fakeAndroidInfoProvider ) testedScope.childrenScopes.add(mockChildScope) @@ -426,7 +434,8 @@ internal class RumSessionScopeTest { mockRumEventSourceProvider, mockBuildSdkVersionProvider, TEST_INACTIVITY_NS, - TEST_MAX_DURATION_NS + TEST_MAX_DURATION_NS, + fakeAndroidInfoProvider ) testedScope.applicationDisplayed = true @@ -649,7 +658,8 @@ internal class RumSessionScopeTest { mockRumEventSourceProvider, mockBuildSdkVersionProvider, TEST_INACTIVITY_NS, - TEST_MAX_DURATION_NS + TEST_MAX_DURATION_NS, + fakeAndroidInfoProvider ) val startViewEvent = RumRawEvent.StartView(key, name, emptyMap()) @@ -678,7 +688,8 @@ internal class RumSessionScopeTest { mockRumEventSourceProvider, mockBuildSdkVersionProvider, TEST_INACTIVITY_NS, - TEST_MAX_DURATION_NS + TEST_MAX_DURATION_NS, + fakeAndroidInfoProvider ) testedScope.applicationDisplayed = true val fakeEvent = forge.forgeValidBackgroundEvent() @@ -717,7 +728,8 @@ internal class RumSessionScopeTest { mockRumEventSourceProvider, mockBuildSdkVersionProvider, TEST_INACTIVITY_NS, - TEST_MAX_DURATION_NS + TEST_MAX_DURATION_NS, + fakeAndroidInfoProvider ) testedScope.applicationDisplayed = true testedScope.childrenScopes.add(mockChildScope) @@ -773,7 +785,8 @@ internal class RumSessionScopeTest { sessionListener = mockSessionListener, rumEventSourceProvider = mockRumEventSourceProvider, sessionInactivityNanos = TEST_INACTIVITY_NS, - sessionMaxDurationNanos = TEST_MAX_DURATION_NS + sessionMaxDurationNanos = TEST_MAX_DURATION_NS, + androidInfoProvider = fakeAndroidInfoProvider ) testedScope.applicationDisplayed = false val fakeEvent = forge.forgeValidBackgroundEvent() @@ -850,7 +863,8 @@ internal class RumSessionScopeTest { rumEventSourceProvider = mockRumEventSourceProvider, sessionListener = mockSessionListener, sessionInactivityNanos = TEST_INACTIVITY_NS, - sessionMaxDurationNanos = TEST_MAX_DURATION_NS + sessionMaxDurationNanos = TEST_MAX_DURATION_NS, + androidInfoProvider = fakeAndroidInfoProvider ) testedScope.applicationDisplayed = false val fakeEvent = forge.forgeValidAppLaunchEvent() @@ -880,7 +894,8 @@ internal class RumSessionScopeTest { mockRumEventSourceProvider, mockBuildSdkVersionProvider, TEST_INACTIVITY_NS, - TEST_MAX_DURATION_NS + TEST_MAX_DURATION_NS, + fakeAndroidInfoProvider ) val fakeEvent = forge.forgeInvalidAppLaunchEvent() @@ -909,7 +924,8 @@ internal class RumSessionScopeTest { mockRumEventSourceProvider, mockBuildSdkVersionProvider, TEST_INACTIVITY_NS, - TEST_MAX_DURATION_NS + TEST_MAX_DURATION_NS, + fakeAndroidInfoProvider ) testedScope.childrenScopes.add(mockChildScope) whenever(mockChildScope.isActive()) doReturn true @@ -942,7 +958,8 @@ internal class RumSessionScopeTest { mockRumEventSourceProvider, mockBuildSdkVersionProvider, TEST_INACTIVITY_NS, - TEST_MAX_DURATION_NS + TEST_MAX_DURATION_NS, + fakeAndroidInfoProvider ) testedScope.applicationDisplayed = true val fakeEvent = forge.forgeValidBackgroundEvent() diff --git a/dd-sdk-android/src/test/kotlin/com/datadog/android/rum/internal/domain/scope/RumViewScopeTest.kt b/dd-sdk-android/src/test/kotlin/com/datadog/android/rum/internal/domain/scope/RumViewScopeTest.kt index d9d9a168d7..e438ecf1ef 100644 --- a/dd-sdk-android/src/test/kotlin/com/datadog/android/rum/internal/domain/scope/RumViewScopeTest.kt +++ b/dd-sdk-android/src/test/kotlin/com/datadog/android/rum/internal/domain/scope/RumViewScopeTest.kt @@ -15,6 +15,7 @@ import androidx.fragment.app.Fragment import androidx.fragment.app.FragmentActivity import com.datadog.android.core.internal.net.FirstPartyHostDetector import com.datadog.android.core.internal.persistence.DataWriter +import com.datadog.android.core.internal.system.AndroidInfoProvider import com.datadog.android.core.internal.system.BuildSdkVersionProvider import com.datadog.android.core.internal.time.TimeProvider import com.datadog.android.core.internal.utils.loggableStackTrace @@ -145,6 +146,9 @@ internal class RumViewScopeTest { @Forgery lateinit var fakeNetworkInfo: NetworkInfo + @Forgery + lateinit var fakeAndroidInfoProvider: AndroidInfoProvider + lateinit var fakeEventTime: Time var fakeServerOffset: Long = 0L @@ -229,7 +233,8 @@ internal class RumViewScopeTest { mockTimeProvider, mockRumEventSourceProvider, mockBuildSdkVersionProvider, - mockViewUpdatePredicate + mockViewUpdatePredicate, + androidInfoProvider = fakeAndroidInfoProvider ) assertThat(GlobalRum.getRumContext()).isEqualTo(testedScope.getRumContext()) @@ -317,7 +322,8 @@ internal class RumViewScopeTest { mockRumEventSourceProvider, mockBuildSdkVersionProvider, mockViewUpdatePredicate, - type = fakeViewEventType + type = fakeViewEventType, + androidInfoProvider = fakeAndroidInfoProvider ) // Then @@ -386,7 +392,8 @@ internal class RumViewScopeTest { mockRumEventSourceProvider, mockBuildSdkVersionProvider, mockViewUpdatePredicate, - type = expectedViewType + type = expectedViewType, + androidInfoProvider = fakeAndroidInfoProvider ) // When @@ -551,7 +558,8 @@ internal class RumViewScopeTest { mockRumEventSourceProvider, mockBuildSdkVersionProvider, mockViewUpdatePredicate, - type = viewType + type = viewType, + androidInfoProvider = fakeAndroidInfoProvider ) // When @@ -595,7 +603,8 @@ internal class RumViewScopeTest { mockRumEventSourceProvider, mockBuildSdkVersionProvider, mockViewUpdatePredicate, - type = viewType + type = viewType, + androidInfoProvider = fakeAndroidInfoProvider ) // When @@ -667,6 +676,17 @@ internal class RumViewScopeTest { hasLiteSessionPlan() hasSource(fakeSourceViewEvent) containsExactlyContextAttributes(fakeAttributes) + hasDeviceInfo( + fakeAndroidInfoProvider.deviceName, + fakeAndroidInfoProvider.deviceModel, + fakeAndroidInfoProvider.deviceBrand, + fakeAndroidInfoProvider.deviceType.toViewSchemaType() + ) + hasOsInfo( + fakeAndroidInfoProvider.osName, + fakeAndroidInfoProvider.osVersion, + fakeAndroidInfoProvider.osMajorVersion + ) } } verifyNoMoreInteractions(mockWriter) @@ -719,6 +739,17 @@ internal class RumViewScopeTest { containsExactlyContextAttributes(fakeAttributes) hasLiteSessionPlan() hasSource(fakeSourceViewEvent) + hasDeviceInfo( + fakeAndroidInfoProvider.deviceName, + fakeAndroidInfoProvider.deviceModel, + fakeAndroidInfoProvider.deviceBrand, + fakeAndroidInfoProvider.deviceType.toViewSchemaType() + ) + hasOsInfo( + fakeAndroidInfoProvider.osName, + fakeAndroidInfoProvider.osVersion, + fakeAndroidInfoProvider.osMajorVersion + ) } } verifyNoMoreInteractions(mockWriter) @@ -771,6 +802,17 @@ internal class RumViewScopeTest { containsExactlyContextAttributes(expectedAttributes) hasLiteSessionPlan() hasSource(fakeSourceViewEvent) + hasDeviceInfo( + fakeAndroidInfoProvider.deviceName, + fakeAndroidInfoProvider.deviceModel, + fakeAndroidInfoProvider.deviceBrand, + fakeAndroidInfoProvider.deviceType.toViewSchemaType() + ) + hasOsInfo( + fakeAndroidInfoProvider.osName, + fakeAndroidInfoProvider.osVersion, + fakeAndroidInfoProvider.osMajorVersion + ) } } verifyNoMoreInteractions(mockWriter) @@ -829,6 +871,17 @@ internal class RumViewScopeTest { hasLiteSessionPlan() containsExactlyContextAttributes(expectedAttributes) hasSource(fakeSourceViewEvent) + hasDeviceInfo( + fakeAndroidInfoProvider.deviceName, + fakeAndroidInfoProvider.deviceModel, + fakeAndroidInfoProvider.deviceBrand, + fakeAndroidInfoProvider.deviceType.toViewSchemaType() + ) + hasOsInfo( + fakeAndroidInfoProvider.osName, + fakeAndroidInfoProvider.osVersion, + fakeAndroidInfoProvider.osMajorVersion + ) } } verifyNoMoreInteractions(mockWriter) @@ -884,6 +937,17 @@ internal class RumViewScopeTest { hasLiteSessionPlan() containsExactlyContextAttributes(expectedAttributes) hasSource(fakeSourceViewEvent) + hasDeviceInfo( + fakeAndroidInfoProvider.deviceName, + fakeAndroidInfoProvider.deviceModel, + fakeAndroidInfoProvider.deviceBrand, + fakeAndroidInfoProvider.deviceType.toViewSchemaType() + ) + hasOsInfo( + fakeAndroidInfoProvider.osName, + fakeAndroidInfoProvider.osVersion, + fakeAndroidInfoProvider.osMajorVersion + ) } } verifyNoMoreInteractions(mockWriter) @@ -939,6 +1003,17 @@ internal class RumViewScopeTest { hasLiteSessionPlan() containsExactlyContextAttributes(expectedAttributes) hasSource(fakeSourceViewEvent) + hasDeviceInfo( + fakeAndroidInfoProvider.deviceName, + fakeAndroidInfoProvider.deviceModel, + fakeAndroidInfoProvider.deviceBrand, + fakeAndroidInfoProvider.deviceType.toViewSchemaType() + ) + hasOsInfo( + fakeAndroidInfoProvider.osName, + fakeAndroidInfoProvider.osVersion, + fakeAndroidInfoProvider.osMajorVersion + ) } } verifyNoMoreInteractions(mockWriter) @@ -981,6 +1056,17 @@ internal class RumViewScopeTest { hasSessionId(fakeParentContext.sessionId) hasLiteSessionPlan() hasSource(fakeSourceViewEvent) + hasDeviceInfo( + fakeAndroidInfoProvider.deviceName, + fakeAndroidInfoProvider.deviceModel, + fakeAndroidInfoProvider.deviceBrand, + fakeAndroidInfoProvider.deviceType.toViewSchemaType() + ) + hasOsInfo( + fakeAndroidInfoProvider.osName, + fakeAndroidInfoProvider.osVersion, + fakeAndroidInfoProvider.osMajorVersion + ) } } verifyNoMoreInteractions(mockWriter) @@ -1014,7 +1100,8 @@ internal class RumViewScopeTest { mockFrameRateVitalMonitor, mockTimeProvider, rumEventSourceProvider = mockRumEventSourceProvider, - viewUpdatePredicate = mockViewUpdatePredicate + viewUpdatePredicate = mockViewUpdatePredicate, + androidInfoProvider = fakeAndroidInfoProvider ) fakeGlobalAttributes.keys.forEach { GlobalRum.removeAttribute(it) } @@ -1053,6 +1140,17 @@ internal class RumViewScopeTest { hasLiteSessionPlan() containsExactlyContextAttributes(expectedAttributes) hasSource(fakeSourceViewEvent) + hasDeviceInfo( + fakeAndroidInfoProvider.deviceName, + fakeAndroidInfoProvider.deviceModel, + fakeAndroidInfoProvider.deviceBrand, + fakeAndroidInfoProvider.deviceType.toViewSchemaType() + ) + hasOsInfo( + fakeAndroidInfoProvider.osName, + fakeAndroidInfoProvider.osVersion, + fakeAndroidInfoProvider.osMajorVersion + ) } } verifyNoMoreInteractions(mockWriter) @@ -1107,6 +1205,17 @@ internal class RumViewScopeTest { hasLiteSessionPlan() containsExactlyContextAttributes(expectedAttributes) hasSource(fakeSourceViewEvent) + hasDeviceInfo( + fakeAndroidInfoProvider.deviceName, + fakeAndroidInfoProvider.deviceModel, + fakeAndroidInfoProvider.deviceBrand, + fakeAndroidInfoProvider.deviceType.toViewSchemaType() + ) + hasOsInfo( + fakeAndroidInfoProvider.osName, + fakeAndroidInfoProvider.osVersion, + fakeAndroidInfoProvider.osMajorVersion + ) } } verifyNoMoreInteractions(mockWriter) @@ -1138,7 +1247,8 @@ internal class RumViewScopeTest { mockFrameRateVitalMonitor, mockTimeProvider, rumEventSourceProvider = mockRumEventSourceProvider, - viewUpdatePredicate = mockViewUpdatePredicate + viewUpdatePredicate = mockViewUpdatePredicate, + androidInfoProvider = fakeAndroidInfoProvider ) val expectedAttributes = mutableMapOf() expectedAttributes.putAll(fakeAttributes) @@ -1180,6 +1290,17 @@ internal class RumViewScopeTest { hasLiteSessionPlan() containsExactlyContextAttributes(expectedAttributes) hasSource(fakeSourceViewEvent) + hasDeviceInfo( + fakeAndroidInfoProvider.deviceName, + fakeAndroidInfoProvider.deviceModel, + fakeAndroidInfoProvider.deviceBrand, + fakeAndroidInfoProvider.deviceType.toViewSchemaType() + ) + hasOsInfo( + fakeAndroidInfoProvider.osName, + fakeAndroidInfoProvider.osVersion, + fakeAndroidInfoProvider.osMajorVersion + ) } } verifyNoMoreInteractions(mockWriter) @@ -1213,7 +1334,8 @@ internal class RumViewScopeTest { mockFrameRateVitalMonitor, mockTimeProvider, rumEventSourceProvider = mockRumEventSourceProvider, - viewUpdatePredicate = mockViewUpdatePredicate + viewUpdatePredicate = mockViewUpdatePredicate, + androidInfoProvider = fakeAndroidInfoProvider ) val expectedAttributes = mutableMapOf() expectedAttributes.putAll(fakeAttributes) @@ -1255,6 +1377,17 @@ internal class RumViewScopeTest { hasLiteSessionPlan() containsExactlyContextAttributes(expectedAttributes) hasSource(fakeSourceViewEvent) + hasDeviceInfo( + fakeAndroidInfoProvider.deviceName, + fakeAndroidInfoProvider.deviceModel, + fakeAndroidInfoProvider.deviceBrand, + fakeAndroidInfoProvider.deviceType.toViewSchemaType() + ) + hasOsInfo( + fakeAndroidInfoProvider.osName, + fakeAndroidInfoProvider.osVersion, + fakeAndroidInfoProvider.osMajorVersion + ) } } verifyNoMoreInteractions(mockWriter) @@ -1310,6 +1443,17 @@ internal class RumViewScopeTest { hasLiteSessionPlan() containsExactlyContextAttributes(expectedAttributes) hasSource(fakeSourceViewEvent) + hasDeviceInfo( + fakeAndroidInfoProvider.deviceName, + fakeAndroidInfoProvider.deviceModel, + fakeAndroidInfoProvider.deviceBrand, + fakeAndroidInfoProvider.deviceType.toViewSchemaType() + ) + hasOsInfo( + fakeAndroidInfoProvider.osName, + fakeAndroidInfoProvider.osVersion, + fakeAndroidInfoProvider.osMajorVersion + ) } } verifyNoMoreInteractions(mockWriter) @@ -1364,6 +1508,17 @@ internal class RumViewScopeTest { hasLiteSessionPlan() containsExactlyContextAttributes(expectedAttributes) hasSource(fakeSourceViewEvent) + hasDeviceInfo( + fakeAndroidInfoProvider.deviceName, + fakeAndroidInfoProvider.deviceModel, + fakeAndroidInfoProvider.deviceBrand, + fakeAndroidInfoProvider.deviceType.toViewSchemaType() + ) + hasOsInfo( + fakeAndroidInfoProvider.osName, + fakeAndroidInfoProvider.osVersion, + fakeAndroidInfoProvider.osMajorVersion + ) } } verifyNoMoreInteractions(mockWriter) @@ -1411,6 +1566,17 @@ internal class RumViewScopeTest { hasLiteSessionPlan() containsExactlyContextAttributes(fakeAttributes) hasSource(fakeSourceViewEvent) + hasDeviceInfo( + fakeAndroidInfoProvider.deviceName, + fakeAndroidInfoProvider.deviceModel, + fakeAndroidInfoProvider.deviceBrand, + fakeAndroidInfoProvider.deviceType.toViewSchemaType() + ) + hasOsInfo( + fakeAndroidInfoProvider.osName, + fakeAndroidInfoProvider.osVersion, + fakeAndroidInfoProvider.osMajorVersion + ) } } verifyNoMoreInteractions(mockWriter) @@ -1501,6 +1667,17 @@ internal class RumViewScopeTest { hasLiteSessionPlan() containsExactlyContextAttributes(fakeAttributes) hasSource(fakeSourceViewEvent) + hasDeviceInfo( + fakeAndroidInfoProvider.deviceName, + fakeAndroidInfoProvider.deviceModel, + fakeAndroidInfoProvider.deviceBrand, + fakeAndroidInfoProvider.deviceType.toViewSchemaType() + ) + hasOsInfo( + fakeAndroidInfoProvider.osName, + fakeAndroidInfoProvider.osVersion, + fakeAndroidInfoProvider.osMajorVersion + ) } } verifyNoMoreInteractions(mockWriter) @@ -1568,6 +1745,17 @@ internal class RumViewScopeTest { hasLiteSessionPlan() containsExactlyContextAttributes(fakeAttributes) hasSource(fakeSourceViewEvent) + hasDeviceInfo( + fakeAndroidInfoProvider.deviceName, + fakeAndroidInfoProvider.deviceModel, + fakeAndroidInfoProvider.deviceBrand, + fakeAndroidInfoProvider.deviceType.toViewSchemaType() + ) + hasOsInfo( + fakeAndroidInfoProvider.osName, + fakeAndroidInfoProvider.osVersion, + fakeAndroidInfoProvider.osMajorVersion + ) } } verifyNoMoreInteractions(mockWriter) @@ -1635,6 +1823,17 @@ internal class RumViewScopeTest { hasLiteSessionPlan() containsExactlyContextAttributes(fakeAttributes) hasSource(fakeSourceViewEvent) + hasDeviceInfo( + fakeAndroidInfoProvider.deviceName, + fakeAndroidInfoProvider.deviceModel, + fakeAndroidInfoProvider.deviceBrand, + fakeAndroidInfoProvider.deviceType.toViewSchemaType() + ) + hasOsInfo( + fakeAndroidInfoProvider.osName, + fakeAndroidInfoProvider.osVersion, + fakeAndroidInfoProvider.osMajorVersion + ) } } verifyNoMoreInteractions(mockWriter) @@ -1704,6 +1903,17 @@ internal class RumViewScopeTest { hasLiteSessionPlan() containsExactlyContextAttributes(fakeAttributes) hasSource(fakeSourceViewEvent) + hasDeviceInfo( + fakeAndroidInfoProvider.deviceName, + fakeAndroidInfoProvider.deviceModel, + fakeAndroidInfoProvider.deviceBrand, + fakeAndroidInfoProvider.deviceType.toViewSchemaType() + ) + hasOsInfo( + fakeAndroidInfoProvider.osName, + fakeAndroidInfoProvider.osVersion, + fakeAndroidInfoProvider.osMajorVersion + ) } } verifyNoMoreInteractions(mockWriter) @@ -1754,6 +1964,17 @@ internal class RumViewScopeTest { hasLiteSessionPlan() containsExactlyContextAttributes(fakeAttributes) hasSource(fakeSourceViewEvent) + hasDeviceInfo( + fakeAndroidInfoProvider.deviceName, + fakeAndroidInfoProvider.deviceModel, + fakeAndroidInfoProvider.deviceBrand, + fakeAndroidInfoProvider.deviceType.toViewSchemaType() + ) + hasOsInfo( + fakeAndroidInfoProvider.osName, + fakeAndroidInfoProvider.osVersion, + fakeAndroidInfoProvider.osMajorVersion + ) } } verifyNoMoreInteractions(mockWriter) @@ -1816,6 +2037,17 @@ internal class RumViewScopeTest { hasSessionId(fakeParentContext.sessionId) hasLiteSessionPlan() hasSource(fakeSourceActionEvent) + hasDeviceInfo( + fakeAndroidInfoProvider.deviceName, + fakeAndroidInfoProvider.deviceModel, + fakeAndroidInfoProvider.deviceBrand, + fakeAndroidInfoProvider.deviceType.toActionSchemaType() + ) + hasOsInfo( + fakeAndroidInfoProvider.osName, + fakeAndroidInfoProvider.osVersion, + fakeAndroidInfoProvider.osMajorVersion + ) } } verifyNoMoreInteractions(mockWriter) @@ -1861,6 +2093,17 @@ internal class RumViewScopeTest { hasLiteSessionPlan() containsExactlyContextAttributes(fakeAttributes) hasSource(fakeSourceViewEvent) + hasDeviceInfo( + fakeAndroidInfoProvider.deviceName, + fakeAndroidInfoProvider.deviceModel, + fakeAndroidInfoProvider.deviceBrand, + fakeAndroidInfoProvider.deviceType.toViewSchemaType() + ) + hasOsInfo( + fakeAndroidInfoProvider.osName, + fakeAndroidInfoProvider.osVersion, + fakeAndroidInfoProvider.osMajorVersion + ) } } verifyNoMoreInteractions(mockWriter) @@ -1928,6 +2171,17 @@ internal class RumViewScopeTest { hasLiteSessionPlan() containsExactlyContextAttributes(fakeAttributes) hasSource(fakeSourceViewEvent) + hasDeviceInfo( + fakeAndroidInfoProvider.deviceName, + fakeAndroidInfoProvider.deviceModel, + fakeAndroidInfoProvider.deviceBrand, + fakeAndroidInfoProvider.deviceType.toViewSchemaType() + ) + hasOsInfo( + fakeAndroidInfoProvider.osName, + fakeAndroidInfoProvider.osVersion, + fakeAndroidInfoProvider.osMajorVersion + ) } } verifyNoMoreInteractions(mockWriter) @@ -1995,6 +2249,17 @@ internal class RumViewScopeTest { hasLiteSessionPlan() containsExactlyContextAttributes(fakeAttributes) hasSource(fakeSourceViewEvent) + hasDeviceInfo( + fakeAndroidInfoProvider.deviceName, + fakeAndroidInfoProvider.deviceModel, + fakeAndroidInfoProvider.deviceBrand, + fakeAndroidInfoProvider.deviceType.toViewSchemaType() + ) + hasOsInfo( + fakeAndroidInfoProvider.osName, + fakeAndroidInfoProvider.osVersion, + fakeAndroidInfoProvider.osMajorVersion + ) } } verifyNoMoreInteractions(mockWriter) @@ -2062,6 +2327,17 @@ internal class RumViewScopeTest { hasLiteSessionPlan() containsExactlyContextAttributes(fakeAttributes) hasSource(fakeSourceViewEvent) + hasDeviceInfo( + fakeAndroidInfoProvider.deviceName, + fakeAndroidInfoProvider.deviceModel, + fakeAndroidInfoProvider.deviceBrand, + fakeAndroidInfoProvider.deviceType.toViewSchemaType() + ) + hasOsInfo( + fakeAndroidInfoProvider.osName, + fakeAndroidInfoProvider.osVersion, + fakeAndroidInfoProvider.osMajorVersion + ) } } verifyNoMoreInteractions(mockWriter) @@ -2124,6 +2400,17 @@ internal class RumViewScopeTest { hasSessionId(fakeParentContext.sessionId) hasLiteSessionPlan() hasSource(fakeSourceActionEvent) + hasDeviceInfo( + fakeAndroidInfoProvider.deviceName, + fakeAndroidInfoProvider.deviceModel, + fakeAndroidInfoProvider.deviceBrand, + fakeAndroidInfoProvider.deviceType.toActionSchemaType() + ) + hasOsInfo( + fakeAndroidInfoProvider.osName, + fakeAndroidInfoProvider.osVersion, + fakeAndroidInfoProvider.osMajorVersion + ) } } verifyNoMoreInteractions(mockWriter) @@ -2164,6 +2451,17 @@ internal class RumViewScopeTest { hasSessionId(fakeParentContext.sessionId) hasLiteSessionPlan() hasSource(fakeSourceActionEvent) + hasDeviceInfo( + fakeAndroidInfoProvider.deviceName, + fakeAndroidInfoProvider.deviceModel, + fakeAndroidInfoProvider.deviceBrand, + fakeAndroidInfoProvider.deviceType.toActionSchemaType() + ) + hasOsInfo( + fakeAndroidInfoProvider.osName, + fakeAndroidInfoProvider.osVersion, + fakeAndroidInfoProvider.osMajorVersion + ) } } verifyNoMoreInteractions(mockWriter) @@ -2223,6 +2521,17 @@ internal class RumViewScopeTest { hasLiteSessionPlan() containsExactlyContextAttributes(fakeAttributes) hasSource(fakeSourceViewEvent) + hasDeviceInfo( + fakeAndroidInfoProvider.deviceName, + fakeAndroidInfoProvider.deviceModel, + fakeAndroidInfoProvider.deviceBrand, + fakeAndroidInfoProvider.deviceType.toViewSchemaType() + ) + hasOsInfo( + fakeAndroidInfoProvider.osName, + fakeAndroidInfoProvider.osVersion, + fakeAndroidInfoProvider.osMajorVersion + ) } } verifyNoMoreInteractions(mockWriter) @@ -2471,6 +2780,17 @@ internal class RumViewScopeTest { hasLiteSessionPlan() containsExactlyContextAttributes(attributes) hasSource(fakeSourceActionEvent) + hasDeviceInfo( + fakeAndroidInfoProvider.deviceName, + fakeAndroidInfoProvider.deviceModel, + fakeAndroidInfoProvider.deviceBrand, + fakeAndroidInfoProvider.deviceType.toActionSchemaType() + ) + hasOsInfo( + fakeAndroidInfoProvider.osName, + fakeAndroidInfoProvider.osVersion, + fakeAndroidInfoProvider.osMajorVersion + ) } } verifyNoMoreInteractions(mockWriter) @@ -2906,6 +3226,17 @@ internal class RumViewScopeTest { hasActionId(fakeActionId) hasLiteSessionPlan() containsExactlyContextAttributes(attributes) + hasDeviceInfo( + fakeAndroidInfoProvider.deviceName, + fakeAndroidInfoProvider.deviceModel, + fakeAndroidInfoProvider.deviceBrand, + fakeAndroidInfoProvider.deviceType.toErrorSchemaType() + ) + hasOsInfo( + fakeAndroidInfoProvider.osName, + fakeAndroidInfoProvider.osVersion, + fakeAndroidInfoProvider.osMajorVersion + ) } } verifyNoMoreInteractions(mockWriter) @@ -2955,6 +3286,17 @@ internal class RumViewScopeTest { hasLiteSessionPlan() containsExactlyContextAttributes(attributes) hasSource(fakeSourceErrorEvent) + hasDeviceInfo( + fakeAndroidInfoProvider.deviceName, + fakeAndroidInfoProvider.deviceModel, + fakeAndroidInfoProvider.deviceBrand, + fakeAndroidInfoProvider.deviceType.toErrorSchemaType() + ) + hasOsInfo( + fakeAndroidInfoProvider.osName, + fakeAndroidInfoProvider.osVersion, + fakeAndroidInfoProvider.osMajorVersion + ) } } verifyNoMoreInteractions(mockWriter) @@ -3005,6 +3347,17 @@ internal class RumViewScopeTest { hasLiteSessionPlan() containsExactlyContextAttributes(attributes) hasSource(fakeSourceErrorEvent) + hasDeviceInfo( + fakeAndroidInfoProvider.deviceName, + fakeAndroidInfoProvider.deviceModel, + fakeAndroidInfoProvider.deviceBrand, + fakeAndroidInfoProvider.deviceType.toErrorSchemaType() + ) + hasOsInfo( + fakeAndroidInfoProvider.osName, + fakeAndroidInfoProvider.osVersion, + fakeAndroidInfoProvider.osMajorVersion + ) } } verifyNoMoreInteractions(mockWriter) @@ -3057,6 +3410,17 @@ internal class RumViewScopeTest { hasLiteSessionPlan() containsExactlyContextAttributes(attributes) hasSource(fakeSourceErrorEvent) + hasDeviceInfo( + fakeAndroidInfoProvider.deviceName, + fakeAndroidInfoProvider.deviceModel, + fakeAndroidInfoProvider.deviceBrand, + fakeAndroidInfoProvider.deviceType.toErrorSchemaType() + ) + hasOsInfo( + fakeAndroidInfoProvider.osName, + fakeAndroidInfoProvider.osVersion, + fakeAndroidInfoProvider.osMajorVersion + ) } } verifyNoMoreInteractions(mockWriter) @@ -3154,6 +3518,17 @@ internal class RumViewScopeTest { hasLiteSessionPlan() containsExactlyContextAttributes(attributes) hasSource(fakeSourceErrorEvent) + hasDeviceInfo( + fakeAndroidInfoProvider.deviceName, + fakeAndroidInfoProvider.deviceModel, + fakeAndroidInfoProvider.deviceBrand, + fakeAndroidInfoProvider.deviceType.toErrorSchemaType() + ) + hasOsInfo( + fakeAndroidInfoProvider.osName, + fakeAndroidInfoProvider.osVersion, + fakeAndroidInfoProvider.osMajorVersion + ) } } verifyNoMoreInteractions(mockWriter) @@ -3205,6 +3580,17 @@ internal class RumViewScopeTest { hasLiteSessionPlan() containsExactlyContextAttributes(attributes) hasSource(fakeSourceErrorEvent) + hasDeviceInfo( + fakeAndroidInfoProvider.deviceName, + fakeAndroidInfoProvider.deviceModel, + fakeAndroidInfoProvider.deviceBrand, + fakeAndroidInfoProvider.deviceType.toErrorSchemaType() + ) + hasOsInfo( + fakeAndroidInfoProvider.osName, + fakeAndroidInfoProvider.osVersion, + fakeAndroidInfoProvider.osMajorVersion + ) } } verifyNoMoreInteractions(mockWriter) @@ -3255,6 +3641,17 @@ internal class RumViewScopeTest { hasLiteSessionPlan() containsExactlyContextAttributes(attributes) hasSource(fakeSourceErrorEvent) + hasDeviceInfo( + fakeAndroidInfoProvider.deviceName, + fakeAndroidInfoProvider.deviceModel, + fakeAndroidInfoProvider.deviceBrand, + fakeAndroidInfoProvider.deviceType.toErrorSchemaType() + ) + hasOsInfo( + fakeAndroidInfoProvider.osName, + fakeAndroidInfoProvider.osVersion, + fakeAndroidInfoProvider.osMajorVersion + ) } assertThat(lastValue as ViewEvent) .apply { @@ -3284,6 +3681,17 @@ internal class RumViewScopeTest { hasLiteSessionPlan() containsExactlyContextAttributes(fakeAttributes) hasSource(fakeSourceViewEvent) + hasDeviceInfo( + fakeAndroidInfoProvider.deviceName, + fakeAndroidInfoProvider.deviceModel, + fakeAndroidInfoProvider.deviceBrand, + fakeAndroidInfoProvider.deviceType.toViewSchemaType() + ) + hasOsInfo( + fakeAndroidInfoProvider.osName, + fakeAndroidInfoProvider.osVersion, + fakeAndroidInfoProvider.osMajorVersion + ) } } verifyNoMoreInteractions(mockWriter) @@ -3338,6 +3746,17 @@ internal class RumViewScopeTest { hasLiteSessionPlan() containsExactlyContextAttributes(attributes) hasSource(fakeSourceErrorEvent) + hasDeviceInfo( + fakeAndroidInfoProvider.deviceName, + fakeAndroidInfoProvider.deviceModel, + fakeAndroidInfoProvider.deviceBrand, + fakeAndroidInfoProvider.deviceType.toErrorSchemaType() + ) + hasOsInfo( + fakeAndroidInfoProvider.osName, + fakeAndroidInfoProvider.osVersion, + fakeAndroidInfoProvider.osMajorVersion + ) } } verifyNoMoreInteractions(mockWriter) @@ -3390,6 +3809,17 @@ internal class RumViewScopeTest { hasLiteSessionPlan() containsExactlyContextAttributes(attributes) hasSource(fakeSourceErrorEvent) + hasDeviceInfo( + fakeAndroidInfoProvider.deviceName, + fakeAndroidInfoProvider.deviceModel, + fakeAndroidInfoProvider.deviceBrand, + fakeAndroidInfoProvider.deviceType.toErrorSchemaType() + ) + hasOsInfo( + fakeAndroidInfoProvider.osName, + fakeAndroidInfoProvider.osVersion, + fakeAndroidInfoProvider.osMajorVersion + ) } assertThat(lastValue as ViewEvent) .apply { @@ -3419,6 +3849,17 @@ internal class RumViewScopeTest { hasLiteSessionPlan() containsExactlyContextAttributes(fakeAttributes) hasSource(fakeSourceViewEvent) + hasDeviceInfo( + fakeAndroidInfoProvider.deviceName, + fakeAndroidInfoProvider.deviceModel, + fakeAndroidInfoProvider.deviceBrand, + fakeAndroidInfoProvider.deviceType.toViewSchemaType() + ) + hasOsInfo( + fakeAndroidInfoProvider.osName, + fakeAndroidInfoProvider.osVersion, + fakeAndroidInfoProvider.osMajorVersion + ) } } verifyNoMoreInteractions(mockWriter) @@ -3472,6 +3913,17 @@ internal class RumViewScopeTest { hasErrorSourceType(sourceType.toSchemaSourceType()) hasLiteSessionPlan() containsExactlyContextAttributes(attributes) + hasDeviceInfo( + fakeAndroidInfoProvider.deviceName, + fakeAndroidInfoProvider.deviceModel, + fakeAndroidInfoProvider.deviceBrand, + fakeAndroidInfoProvider.deviceType.toErrorSchemaType() + ) + hasOsInfo( + fakeAndroidInfoProvider.osName, + fakeAndroidInfoProvider.osVersion, + fakeAndroidInfoProvider.osMajorVersion + ) } } verifyNoMoreInteractions(mockWriter) @@ -3526,6 +3978,17 @@ internal class RumViewScopeTest { hasLiteSessionPlan() containsExactlyContextAttributes(attributes) hasSource(fakeSourceErrorEvent) + hasDeviceInfo( + fakeAndroidInfoProvider.deviceName, + fakeAndroidInfoProvider.deviceModel, + fakeAndroidInfoProvider.deviceBrand, + fakeAndroidInfoProvider.deviceType.toErrorSchemaType() + ) + hasOsInfo( + fakeAndroidInfoProvider.osName, + fakeAndroidInfoProvider.osVersion, + fakeAndroidInfoProvider.osMajorVersion + ) } } verifyNoMoreInteractions(mockWriter) @@ -3581,6 +4044,17 @@ internal class RumViewScopeTest { hasLiteSessionPlan() containsExactlyContextAttributes(attributes) hasSource(fakeSourceErrorEvent) + hasDeviceInfo( + fakeAndroidInfoProvider.deviceName, + fakeAndroidInfoProvider.deviceModel, + fakeAndroidInfoProvider.deviceBrand, + fakeAndroidInfoProvider.deviceType.toErrorSchemaType() + ) + hasOsInfo( + fakeAndroidInfoProvider.osName, + fakeAndroidInfoProvider.osVersion, + fakeAndroidInfoProvider.osMajorVersion + ) } } verifyNoMoreInteractions(mockWriter) @@ -3634,6 +4108,17 @@ internal class RumViewScopeTest { hasLiteSessionPlan() containsExactlyContextAttributes(attributes) hasSource(fakeSourceErrorEvent) + hasDeviceInfo( + fakeAndroidInfoProvider.deviceName, + fakeAndroidInfoProvider.deviceModel, + fakeAndroidInfoProvider.deviceBrand, + fakeAndroidInfoProvider.deviceType.toErrorSchemaType() + ) + hasOsInfo( + fakeAndroidInfoProvider.osName, + fakeAndroidInfoProvider.osVersion, + fakeAndroidInfoProvider.osMajorVersion + ) } assertThat(lastValue as ViewEvent) .apply { @@ -3663,6 +4148,17 @@ internal class RumViewScopeTest { hasLiteSessionPlan() containsExactlyContextAttributes(fakeAttributes + attributes) hasSource(fakeSourceViewEvent) + hasDeviceInfo( + fakeAndroidInfoProvider.deviceName, + fakeAndroidInfoProvider.deviceModel, + fakeAndroidInfoProvider.deviceBrand, + fakeAndroidInfoProvider.deviceType.toViewSchemaType() + ) + hasOsInfo( + fakeAndroidInfoProvider.osName, + fakeAndroidInfoProvider.osVersion, + fakeAndroidInfoProvider.osMajorVersion + ) } } verifyNoMoreInteractions(mockWriter) @@ -3840,6 +4336,17 @@ internal class RumViewScopeTest { hasSessionId(fakeParentContext.sessionId) hasLiteSessionPlan() hasSource(fakeSourceLongTaskEvent) + hasDeviceInfo( + fakeAndroidInfoProvider.deviceName, + fakeAndroidInfoProvider.deviceModel, + fakeAndroidInfoProvider.deviceBrand, + fakeAndroidInfoProvider.deviceType.toLongTaskSchemaType() + ) + hasOsInfo( + fakeAndroidInfoProvider.osName, + fakeAndroidInfoProvider.osVersion, + fakeAndroidInfoProvider.osMajorVersion + ) } } verifyNoMoreInteractions(mockWriter) @@ -3875,6 +4382,17 @@ internal class RumViewScopeTest { hasSessionId(fakeParentContext.sessionId) hasLiteSessionPlan() hasSource(fakeSourceLongTaskEvent) + hasDeviceInfo( + fakeAndroidInfoProvider.deviceName, + fakeAndroidInfoProvider.deviceModel, + fakeAndroidInfoProvider.deviceBrand, + fakeAndroidInfoProvider.deviceType.toLongTaskSchemaType() + ) + hasOsInfo( + fakeAndroidInfoProvider.osName, + fakeAndroidInfoProvider.osVersion, + fakeAndroidInfoProvider.osMajorVersion + ) } } verifyNoMoreInteractions(mockWriter) @@ -3920,6 +4438,17 @@ internal class RumViewScopeTest { hasLiteSessionPlan() containsExactlyContextAttributes(expectedAttributes) hasSource(fakeSourceLongTaskEvent) + hasDeviceInfo( + fakeAndroidInfoProvider.deviceName, + fakeAndroidInfoProvider.deviceModel, + fakeAndroidInfoProvider.deviceBrand, + fakeAndroidInfoProvider.deviceType.toLongTaskSchemaType() + ) + hasOsInfo( + fakeAndroidInfoProvider.osName, + fakeAndroidInfoProvider.osVersion, + fakeAndroidInfoProvider.osMajorVersion + ) } } verifyNoMoreInteractions(mockWriter) @@ -3965,6 +4494,17 @@ internal class RumViewScopeTest { hasLiteSessionPlan() containsExactlyContextAttributes(expectedAttributes) hasSource(fakeSourceLongTaskEvent) + hasDeviceInfo( + fakeAndroidInfoProvider.deviceName, + fakeAndroidInfoProvider.deviceModel, + fakeAndroidInfoProvider.deviceBrand, + fakeAndroidInfoProvider.deviceType.toLongTaskSchemaType() + ) + hasOsInfo( + fakeAndroidInfoProvider.osName, + fakeAndroidInfoProvider.osVersion, + fakeAndroidInfoProvider.osMajorVersion + ) } } verifyNoMoreInteractions(mockWriter) @@ -4182,6 +4722,17 @@ internal class RumViewScopeTest { hasLiteSessionPlan() containsExactlyContextAttributes(fakeAttributes) hasSource(fakeSourceViewEvent) + hasDeviceInfo( + fakeAndroidInfoProvider.deviceName, + fakeAndroidInfoProvider.deviceModel, + fakeAndroidInfoProvider.deviceBrand, + fakeAndroidInfoProvider.deviceType.toViewSchemaType() + ) + hasOsInfo( + fakeAndroidInfoProvider.osName, + fakeAndroidInfoProvider.osVersion, + fakeAndroidInfoProvider.osMajorVersion + ) } } verifyNoMoreInteractions(mockWriter) @@ -4234,6 +4785,17 @@ internal class RumViewScopeTest { hasLiteSessionPlan() containsExactlyContextAttributes(fakeAttributes) hasSource(fakeSourceViewEvent) + hasDeviceInfo( + fakeAndroidInfoProvider.deviceName, + fakeAndroidInfoProvider.deviceModel, + fakeAndroidInfoProvider.deviceBrand, + fakeAndroidInfoProvider.deviceType.toViewSchemaType() + ) + hasOsInfo( + fakeAndroidInfoProvider.osName, + fakeAndroidInfoProvider.osVersion, + fakeAndroidInfoProvider.osMajorVersion + ) } } verifyNoMoreInteractions(mockWriter) @@ -4304,6 +4866,17 @@ internal class RumViewScopeTest { hasSessionId(fakeParentContext.sessionId) hasLiteSessionPlan() hasSource(fakeSourceViewEvent) + hasDeviceInfo( + fakeAndroidInfoProvider.deviceName, + fakeAndroidInfoProvider.deviceModel, + fakeAndroidInfoProvider.deviceBrand, + fakeAndroidInfoProvider.deviceType.toViewSchemaType() + ) + hasOsInfo( + fakeAndroidInfoProvider.osName, + fakeAndroidInfoProvider.osVersion, + fakeAndroidInfoProvider.osMajorVersion + ) } } verifyNoMoreInteractions(mockWriter) @@ -4359,6 +4932,17 @@ internal class RumViewScopeTest { hasLiteSessionPlan() containsExactlyContextAttributes(fakeAttributes) hasSource(fakeSourceViewEvent) + hasDeviceInfo( + fakeAndroidInfoProvider.deviceName, + fakeAndroidInfoProvider.deviceModel, + fakeAndroidInfoProvider.deviceBrand, + fakeAndroidInfoProvider.deviceType.toViewSchemaType() + ) + hasOsInfo( + fakeAndroidInfoProvider.osName, + fakeAndroidInfoProvider.osVersion, + fakeAndroidInfoProvider.osMajorVersion + ) } assertThat(lastValue) .apply { @@ -4392,6 +4976,17 @@ internal class RumViewScopeTest { hasLiteSessionPlan() containsExactlyContextAttributes(fakeAttributes) hasSource(fakeSourceViewEvent) + hasDeviceInfo( + fakeAndroidInfoProvider.deviceName, + fakeAndroidInfoProvider.deviceModel, + fakeAndroidInfoProvider.deviceBrand, + fakeAndroidInfoProvider.deviceType.toViewSchemaType() + ) + hasOsInfo( + fakeAndroidInfoProvider.osName, + fakeAndroidInfoProvider.osVersion, + fakeAndroidInfoProvider.osMajorVersion + ) } } verifyNoMoreInteractions(mockWriter) @@ -4457,6 +5052,17 @@ internal class RumViewScopeTest { hasLiteSessionPlan() containsExactlyContextAttributes(fakeAttributes) hasSource(fakeSourceViewEvent) + hasDeviceInfo( + fakeAndroidInfoProvider.deviceName, + fakeAndroidInfoProvider.deviceModel, + fakeAndroidInfoProvider.deviceBrand, + fakeAndroidInfoProvider.deviceType.toViewSchemaType() + ) + hasOsInfo( + fakeAndroidInfoProvider.osName, + fakeAndroidInfoProvider.osVersion, + fakeAndroidInfoProvider.osMajorVersion + ) } } verifyNoMoreInteractions(mockWriter) @@ -4510,6 +5116,17 @@ internal class RumViewScopeTest { hasLiteSessionPlan() containsExactlyContextAttributes(fakeAttributes) hasSource(fakeSourceViewEvent) + hasDeviceInfo( + fakeAndroidInfoProvider.deviceName, + fakeAndroidInfoProvider.deviceModel, + fakeAndroidInfoProvider.deviceBrand, + fakeAndroidInfoProvider.deviceType.toViewSchemaType() + ) + hasOsInfo( + fakeAndroidInfoProvider.osName, + fakeAndroidInfoProvider.osVersion, + fakeAndroidInfoProvider.osMajorVersion + ) } } verifyNoMoreInteractions(mockWriter) @@ -4573,6 +5190,17 @@ internal class RumViewScopeTest { hasLiteSessionPlan() containsExactlyContextAttributes(fakeAttributes) hasSource(fakeSourceViewEvent) + hasDeviceInfo( + fakeAndroidInfoProvider.deviceName, + fakeAndroidInfoProvider.deviceModel, + fakeAndroidInfoProvider.deviceBrand, + fakeAndroidInfoProvider.deviceType.toViewSchemaType() + ) + hasOsInfo( + fakeAndroidInfoProvider.osName, + fakeAndroidInfoProvider.osVersion, + fakeAndroidInfoProvider.osMajorVersion + ) } } verifyNoMoreInteractions(mockWriter) @@ -4636,6 +5264,17 @@ internal class RumViewScopeTest { hasLiteSessionPlan() containsExactlyContextAttributes(fakeAttributes) hasSource(fakeSourceViewEvent) + hasDeviceInfo( + fakeAndroidInfoProvider.deviceName, + fakeAndroidInfoProvider.deviceModel, + fakeAndroidInfoProvider.deviceBrand, + fakeAndroidInfoProvider.deviceType.toViewSchemaType() + ) + hasOsInfo( + fakeAndroidInfoProvider.osName, + fakeAndroidInfoProvider.osVersion, + fakeAndroidInfoProvider.osMajorVersion + ) } } verifyNoMoreInteractions(mockWriter) @@ -4672,7 +5311,8 @@ internal class RumViewScopeTest { mockTimeProvider, mockRumEventSourceProvider, mockBuildSdkVersionProvider, - viewUpdatePredicate = mockViewUpdatePredicate + viewUpdatePredicate = mockViewUpdatePredicate, + androidInfoProvider = fakeAndroidInfoProvider ) val listenerCaptor = argumentCaptor { verify(mockFrameRateVitalMonitor).register(capture()) @@ -4713,6 +5353,17 @@ internal class RumViewScopeTest { hasLiteSessionPlan() containsExactlyContextAttributes(fakeAttributes) hasSource(fakeSourceViewEvent) + hasDeviceInfo( + fakeAndroidInfoProvider.deviceName, + fakeAndroidInfoProvider.deviceModel, + fakeAndroidInfoProvider.deviceBrand, + fakeAndroidInfoProvider.deviceType.toViewSchemaType() + ) + hasOsInfo( + fakeAndroidInfoProvider.osName, + fakeAndroidInfoProvider.osVersion, + fakeAndroidInfoProvider.osMajorVersion + ) } } verifyNoMoreInteractions(mockWriter) @@ -4749,7 +5400,8 @@ internal class RumViewScopeTest { mockTimeProvider, mockRumEventSourceProvider, mockBuildSdkVersionProvider, - viewUpdatePredicate = mockViewUpdatePredicate + viewUpdatePredicate = mockViewUpdatePredicate, + androidInfoProvider = fakeAndroidInfoProvider ) val listenerCaptor = argumentCaptor { verify(mockFrameRateVitalMonitor).register(capture()) @@ -4790,6 +5442,17 @@ internal class RumViewScopeTest { hasLiteSessionPlan() containsExactlyContextAttributes(fakeAttributes) hasSource(fakeSourceViewEvent) + hasDeviceInfo( + fakeAndroidInfoProvider.deviceName, + fakeAndroidInfoProvider.deviceModel, + fakeAndroidInfoProvider.deviceBrand, + fakeAndroidInfoProvider.deviceType.toViewSchemaType() + ) + hasOsInfo( + fakeAndroidInfoProvider.osName, + fakeAndroidInfoProvider.osVersion, + fakeAndroidInfoProvider.osMajorVersion + ) } } verifyNoMoreInteractions(mockWriter) @@ -4828,7 +5491,8 @@ internal class RumViewScopeTest { mockTimeProvider, mockRumEventSourceProvider, mockBuildSdkVersionProvider, - viewUpdatePredicate = mockViewUpdatePredicate + viewUpdatePredicate = mockViewUpdatePredicate, + androidInfoProvider = fakeAndroidInfoProvider ) val listenerCaptor = argumentCaptor { verify(mockFrameRateVitalMonitor).register(capture()) @@ -4869,6 +5533,17 @@ internal class RumViewScopeTest { hasLiteSessionPlan() containsExactlyContextAttributes(fakeAttributes) hasSource(fakeSourceViewEvent) + hasDeviceInfo( + fakeAndroidInfoProvider.deviceName, + fakeAndroidInfoProvider.deviceModel, + fakeAndroidInfoProvider.deviceBrand, + fakeAndroidInfoProvider.deviceType.toViewSchemaType() + ) + hasOsInfo( + fakeAndroidInfoProvider.osName, + fakeAndroidInfoProvider.osVersion, + fakeAndroidInfoProvider.osMajorVersion + ) } } verifyNoMoreInteractions(mockWriter) @@ -4907,7 +5582,8 @@ internal class RumViewScopeTest { mockTimeProvider, mockRumEventSourceProvider, mockBuildSdkVersionProvider, - viewUpdatePredicate = mockViewUpdatePredicate + viewUpdatePredicate = mockViewUpdatePredicate, + androidInfoProvider = fakeAndroidInfoProvider ) val listenerCaptor = argumentCaptor { verify(mockFrameRateVitalMonitor).register(capture()) @@ -4948,6 +5624,17 @@ internal class RumViewScopeTest { hasLiteSessionPlan() containsExactlyContextAttributes(fakeAttributes) hasSource(fakeSourceViewEvent) + hasDeviceInfo( + fakeAndroidInfoProvider.deviceName, + fakeAndroidInfoProvider.deviceModel, + fakeAndroidInfoProvider.deviceBrand, + fakeAndroidInfoProvider.deviceType.toViewSchemaType() + ) + hasOsInfo( + fakeAndroidInfoProvider.osName, + fakeAndroidInfoProvider.osVersion, + fakeAndroidInfoProvider.osMajorVersion + ) } } verifyNoMoreInteractions(mockWriter) @@ -4987,7 +5674,8 @@ internal class RumViewScopeTest { mockTimeProvider, mockRumEventSourceProvider, mockBuildSdkVersionProvider, - viewUpdatePredicate = mockViewUpdatePredicate + viewUpdatePredicate = mockViewUpdatePredicate, + androidInfoProvider = fakeAndroidInfoProvider ) val listenerCaptor = argumentCaptor { verify(mockFrameRateVitalMonitor).register(capture()) @@ -5028,6 +5716,17 @@ internal class RumViewScopeTest { hasLiteSessionPlan() containsExactlyContextAttributes(fakeAttributes) hasSource(fakeSourceViewEvent) + hasDeviceInfo( + fakeAndroidInfoProvider.deviceName, + fakeAndroidInfoProvider.deviceModel, + fakeAndroidInfoProvider.deviceBrand, + fakeAndroidInfoProvider.deviceType.toViewSchemaType() + ) + hasOsInfo( + fakeAndroidInfoProvider.osName, + fakeAndroidInfoProvider.osVersion, + fakeAndroidInfoProvider.osMajorVersion + ) } } verifyNoMoreInteractions(mockWriter) @@ -5067,7 +5766,8 @@ internal class RumViewScopeTest { mockTimeProvider, mockRumEventSourceProvider, mockBuildSdkVersionProvider, - viewUpdatePredicate = mockViewUpdatePredicate + viewUpdatePredicate = mockViewUpdatePredicate, + androidInfoProvider = fakeAndroidInfoProvider ) val listenerCaptor = argumentCaptor { verify(mockFrameRateVitalMonitor).register(capture()) @@ -5108,6 +5808,17 @@ internal class RumViewScopeTest { hasLiteSessionPlan() containsExactlyContextAttributes(fakeAttributes) hasSource(fakeSourceViewEvent) + hasDeviceInfo( + fakeAndroidInfoProvider.deviceName, + fakeAndroidInfoProvider.deviceModel, + fakeAndroidInfoProvider.deviceBrand, + fakeAndroidInfoProvider.deviceType.toViewSchemaType() + ) + hasOsInfo( + fakeAndroidInfoProvider.osName, + fakeAndroidInfoProvider.osVersion, + fakeAndroidInfoProvider.osMajorVersion + ) } } verifyNoMoreInteractions(mockWriter) @@ -5216,6 +5927,17 @@ internal class RumViewScopeTest { hasSessionId(fakeParentContext.sessionId) hasLiteSessionPlan() hasSource(fakeSourceActionEvent) + hasDeviceInfo( + fakeAndroidInfoProvider.deviceName, + fakeAndroidInfoProvider.deviceModel, + fakeAndroidInfoProvider.deviceBrand, + fakeAndroidInfoProvider.deviceType.toActionSchemaType() + ) + hasOsInfo( + fakeAndroidInfoProvider.osName, + fakeAndroidInfoProvider.osVersion, + fakeAndroidInfoProvider.osMajorVersion + ) } } verifyNoMoreInteractions(mockWriter) @@ -5252,6 +5974,17 @@ internal class RumViewScopeTest { hasSessionId(fakeParentContext.sessionId) hasLiteSessionPlan() hasSource(fakeSourceLongTaskEvent) + hasDeviceInfo( + fakeAndroidInfoProvider.deviceName, + fakeAndroidInfoProvider.deviceModel, + fakeAndroidInfoProvider.deviceBrand, + fakeAndroidInfoProvider.deviceType.toLongTaskSchemaType() + ) + hasOsInfo( + fakeAndroidInfoProvider.osName, + fakeAndroidInfoProvider.osVersion, + fakeAndroidInfoProvider.osMajorVersion + ) } } @@ -5303,6 +6036,17 @@ internal class RumViewScopeTest { hasLiteSessionPlan() containsExactlyContextAttributes(attributes) hasSource(fakeSourceErrorEvent) + hasDeviceInfo( + fakeAndroidInfoProvider.deviceName, + fakeAndroidInfoProvider.deviceModel, + fakeAndroidInfoProvider.deviceBrand, + fakeAndroidInfoProvider.deviceType.toErrorSchemaType() + ) + hasOsInfo( + fakeAndroidInfoProvider.osName, + fakeAndroidInfoProvider.osVersion, + fakeAndroidInfoProvider.osMajorVersion + ) } } verifyNoMoreInteractions(mockWriter) @@ -5332,7 +6076,8 @@ internal class RumViewScopeTest { mockTimeProvider, mockRumEventSourceProvider, mockBuildSdkVersionProvider, - viewUpdatePredicate = mockViewUpdatePredicate + viewUpdatePredicate = mockViewUpdatePredicate, + androidInfoProvider = fakeAndroidInfoProvider ) // When diff --git a/dd-sdk-android/src/test/kotlin/com/datadog/android/rum/internal/monitor/DatadogRumMonitorTest.kt b/dd-sdk-android/src/test/kotlin/com/datadog/android/rum/internal/monitor/DatadogRumMonitorTest.kt index 5b415614b3..0c9ae440cd 100644 --- a/dd-sdk-android/src/test/kotlin/com/datadog/android/rum/internal/monitor/DatadogRumMonitorTest.kt +++ b/dd-sdk-android/src/test/kotlin/com/datadog/android/rum/internal/monitor/DatadogRumMonitorTest.kt @@ -9,6 +9,7 @@ package com.datadog.android.rum.internal.monitor import android.os.Handler import com.datadog.android.core.internal.net.FirstPartyHostDetector import com.datadog.android.core.internal.persistence.DataWriter +import com.datadog.android.core.internal.system.AndroidInfoProvider import com.datadog.android.core.internal.time.TimeProvider import com.datadog.android.rum.RumActionType import com.datadog.android.rum.RumAttributes @@ -113,6 +114,9 @@ internal class DatadogRumMonitorTest { @Mock lateinit var mockTelemetryEventHandler: TelemetryEventHandler + @Mock + lateinit var mockAndroidInfoProvider: AndroidInfoProvider + @StringForgery(regex = "[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}") lateinit var fakeApplicationId: String @@ -142,7 +146,8 @@ internal class DatadogRumMonitorTest { mockMemoryVitalMonitor, mockFrameRateVitalMonitor, mockTimeProvider, - mockSessionListener + mockSessionListener, + androidInfoProvider = mockAndroidInfoProvider ) testedMonitor.rootScope = mockScope } @@ -161,7 +166,8 @@ internal class DatadogRumMonitorTest { mockMemoryVitalMonitor, mockFrameRateVitalMonitor, mockTimeProvider, - mockSessionListener + mockSessionListener, + androidInfoProvider = mockAndroidInfoProvider ) val rootScope = testedMonitor.rootScope @@ -1174,7 +1180,8 @@ internal class DatadogRumMonitorTest { mockFrameRateVitalMonitor, mockTimeProvider, mockSessionListener, - mockExecutor + mockExecutor, + mockAndroidInfoProvider ) // When @@ -1217,7 +1224,8 @@ internal class DatadogRumMonitorTest { mockFrameRateVitalMonitor, mockTimeProvider, mockSessionListener, - mockExecutorService + mockExecutorService, + mockAndroidInfoProvider ) // When @@ -1247,7 +1255,8 @@ internal class DatadogRumMonitorTest { mockFrameRateVitalMonitor, mockTimeProvider, mockSessionListener, - mockExecutorService + mockExecutorService, + mockAndroidInfoProvider ) whenever(mockExecutorService.isShutdown).thenReturn(true) diff --git a/dd-sdk-android/src/test/kotlin/com/datadog/android/rum/internal/ndk/DatadogNdkCrashHandlerTest.kt b/dd-sdk-android/src/test/kotlin/com/datadog/android/rum/internal/ndk/DatadogNdkCrashHandlerTest.kt index a2f7899db3..947c40991b 100644 --- a/dd-sdk-android/src/test/kotlin/com/datadog/android/rum/internal/ndk/DatadogNdkCrashHandlerTest.kt +++ b/dd-sdk-android/src/test/kotlin/com/datadog/android/rum/internal/ndk/DatadogNdkCrashHandlerTest.kt @@ -10,6 +10,7 @@ import android.content.Context import com.datadog.android.core.internal.persistence.DataWriter import com.datadog.android.core.internal.persistence.Deserializer import com.datadog.android.core.internal.persistence.file.FileHandler +import com.datadog.android.core.internal.system.AndroidInfoProvider import com.datadog.android.core.internal.time.TimeProvider import com.datadog.android.core.model.NetworkInfo import com.datadog.android.core.model.UserInfo @@ -22,6 +23,7 @@ import com.datadog.android.rum.RumErrorSource import com.datadog.android.rum.assertj.ErrorEventAssert import com.datadog.android.rum.assertj.ViewEventAssert import com.datadog.android.rum.internal.domain.event.RumEventSourceProvider +import com.datadog.android.rum.internal.domain.scope.toErrorSchemaType import com.datadog.android.rum.model.ErrorEvent import com.datadog.android.rum.model.ViewEvent import com.datadog.android.utils.forge.Configurator @@ -106,6 +108,9 @@ internal class DatadogNdkCrashHandlerTest { @Forgery lateinit var fakeLog: LogEvent + @Forgery + lateinit var fakeAndroidInfoProvider: AndroidInfoProvider + @Captor lateinit var captureRunnable: ArgumentCaptor @@ -143,7 +148,8 @@ internal class DatadogNdkCrashHandlerTest { Logger(mockLogHandler), mockTimeProvider, mockFileHandler, - mockRumEventSourceProvider + mockRumEventSourceProvider, + fakeAndroidInfoProvider ) } @@ -423,6 +429,17 @@ internal class DatadogNdkCrashHandlerTest { ) .hasErrorType(ndkCrashLog.signalName) .hasLiteSessionPlan() + .hasDeviceInfo( + fakeAndroidInfoProvider.deviceName, + fakeAndroidInfoProvider.deviceModel, + fakeAndroidInfoProvider.deviceBrand, + fakeAndroidInfoProvider.deviceType.toErrorSchemaType() + ) + .hasOsInfo( + fakeAndroidInfoProvider.osName, + fakeAndroidInfoProvider.osVersion, + fakeAndroidInfoProvider.osMajorVersion + ) ViewEventAssert.assertThat(secondValue as ViewEvent) .hasVersion(fakeViewEvent.dd.documentVersion + 1) @@ -496,6 +513,17 @@ internal class DatadogNdkCrashHandlerTest { .hasErrorType(ndkCrashLog.signalName) .hasLiteSessionPlan() .hasSource(fakeSourceErrorEvent) + .hasDeviceInfo( + fakeAndroidInfoProvider.deviceName, + fakeAndroidInfoProvider.deviceModel, + fakeAndroidInfoProvider.deviceBrand, + fakeAndroidInfoProvider.deviceType.toErrorSchemaType() + ) + .hasOsInfo( + fakeAndroidInfoProvider.osName, + fakeAndroidInfoProvider.osVersion, + fakeAndroidInfoProvider.osMajorVersion + ) } verify(mockLogWriter).write(fakeLog) } diff --git a/dd-sdk-android/src/test/kotlin/com/datadog/android/utils/config/CoreFeatureTestConfiguration.kt b/dd-sdk-android/src/test/kotlin/com/datadog/android/utils/config/CoreFeatureTestConfiguration.kt index c728865e66..e9c466eb22 100644 --- a/dd-sdk-android/src/test/kotlin/com/datadog/android/utils/config/CoreFeatureTestConfiguration.kt +++ b/dd-sdk-android/src/test/kotlin/com/datadog/android/utils/config/CoreFeatureTestConfiguration.kt @@ -10,6 +10,7 @@ import android.content.Context import com.datadog.android.core.internal.CoreFeature import com.datadog.android.core.internal.net.info.NetworkInfoProvider import com.datadog.android.core.internal.privacy.ConsentProvider +import com.datadog.android.core.internal.system.AndroidInfoProvider import com.datadog.android.core.internal.system.SystemInfoProvider import com.datadog.android.core.internal.time.TimeProvider import com.datadog.android.log.internal.user.MutableUserInfoProvider @@ -43,6 +44,7 @@ internal class CoreFeatureTestConfiguration( lateinit var mockSystemInfoProvider: SystemInfoProvider lateinit var mockUserInfoProvider: MutableUserInfoProvider lateinit var mockTrackingConsentProvider: ConsentProvider + lateinit var mockAndroidInfoProvider: AndroidInfoProvider // region CoreFeatureTestConfiguration @@ -81,6 +83,7 @@ internal class CoreFeatureTestConfiguration( mockNetworkInfoProvider = mock() mockSystemInfoProvider = mock() mockUserInfoProvider = mock() + mockAndroidInfoProvider = mock() mockTrackingConsentProvider = mock { on { getConsent() } doReturn TrackingConsent.PENDING } } @@ -105,6 +108,7 @@ internal class CoreFeatureTestConfiguration( CoreFeature.systemInfoProvider = mockSystemInfoProvider CoreFeature.userInfoProvider = mockUserInfoProvider CoreFeature.trackingConsentProvider = mockTrackingConsentProvider + CoreFeature.androidInfoProvider = mockAndroidInfoProvider } // endregion diff --git a/dd-sdk-android/src/test/kotlin/com/datadog/android/utils/forge/ActionEventForgeryFactory.kt b/dd-sdk-android/src/test/kotlin/com/datadog/android/utils/forge/ActionEventForgeryFactory.kt index c5e4bb3a75..1b221761dc 100644 --- a/dd-sdk-android/src/test/kotlin/com/datadog/android/utils/forge/ActionEventForgeryFactory.kt +++ b/dd-sdk-android/src/test/kotlin/com/datadog/android/utils/forge/ActionEventForgeryFactory.kt @@ -6,6 +6,8 @@ package com.datadog.android.utils.forge +import com.datadog.android.core.internal.system.AndroidInfoProvider +import com.datadog.android.rum.internal.domain.scope.toActionSchemaType import com.datadog.android.rum.model.ActionEvent import fr.xgouchet.elmyr.Forge import fr.xgouchet.elmyr.ForgeryFactory @@ -72,6 +74,23 @@ internal class ActionEventForgeryFactory : ciTest = forge.aNullable { ActionEvent.CiTest(anHexadecimalString()) }, + os = forge.aNullable { + val androidInfoProvider = getForgery(AndroidInfoProvider::class.java) + ActionEvent.Os( + name = androidInfoProvider.osName, + version = androidInfoProvider.osVersion, + versionMajor = androidInfoProvider.osMajorVersion + ) + }, + device = forge.aNullable { + val androidInfoProvider = getForgery(AndroidInfoProvider::class.java) + ActionEvent.Device( + name = androidInfoProvider.deviceName, + model = androidInfoProvider.deviceModel, + brand = androidInfoProvider.deviceBrand, + type = androidInfoProvider.deviceType.toActionSchemaType() + ) + }, context = forge.aNullable { ActionEvent.Context(additionalProperties = forge.exhaustiveAttributes()) }, diff --git a/dd-sdk-android/src/test/kotlin/com/datadog/android/utils/forge/AndroidInfoProviderForgeryFactory.kt b/dd-sdk-android/src/test/kotlin/com/datadog/android/utils/forge/AndroidInfoProviderForgeryFactory.kt new file mode 100644 index 0000000000..4c6628f1ac --- /dev/null +++ b/dd-sdk-android/src/test/kotlin/com/datadog/android/utils/forge/AndroidInfoProviderForgeryFactory.kt @@ -0,0 +1,37 @@ +/* + * 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 2016-Present Datadog, Inc. + */ + +package com.datadog.android.utils.forge + +import com.datadog.android.core.internal.system.AndroidInfoProvider +import com.datadog.android.core.internal.system.DeviceType +import fr.xgouchet.elmyr.Forge +import fr.xgouchet.elmyr.ForgeryFactory + +internal class AndroidInfoProviderForgeryFactory : ForgeryFactory { + + override fun getForgery(forge: Forge): AndroidInfoProvider { + val deviceName = forge.aString() + val deviceBrand = forge.aString() + val deviceModel = forge.aString() + val deviceType = forge.aValueFrom(DeviceType::class.java) + val deviceBuildId = forge.aString() + val osName = forge.aString() + val osMajorVersion = forge.aSmallInt().toString() + val osVersion = "${forge.aSmallInt()}.${forge.aSmallInt()}.${forge.aSmallInt()}" + + return object : AndroidInfoProvider { + override val deviceName = deviceName + override val deviceBrand = deviceBrand + override val deviceModel = deviceModel + override val deviceType = deviceType + override val deviceBuildId = deviceBuildId + override val osName = osName + override val osMajorVersion = osMajorVersion + override val osVersion = osVersion + } + } +} diff --git a/dd-sdk-android/src/test/kotlin/com/datadog/android/utils/forge/Configurator.kt b/dd-sdk-android/src/test/kotlin/com/datadog/android/utils/forge/Configurator.kt index 7c73f58464..a58603ee51 100644 --- a/dd-sdk-android/src/test/kotlin/com/datadog/android/utils/forge/Configurator.kt +++ b/dd-sdk-android/src/test/kotlin/com/datadog/android/utils/forge/Configurator.kt @@ -27,6 +27,7 @@ internal class Configurator : forge.addFactory(NetworkInfoForgeryFactory()) forge.addFactory(UserInfoForgeryFactory()) forge.addFactory(FilePersistenceConfigForgeryFactory()) + forge.addFactory(AndroidInfoProviderForgeryFactory()) // IO forge.addFactory(BatchForgeryFactory()) diff --git a/dd-sdk-android/src/test/kotlin/com/datadog/android/utils/forge/ErrorEventForgeryFactory.kt b/dd-sdk-android/src/test/kotlin/com/datadog/android/utils/forge/ErrorEventForgeryFactory.kt index 779eefff60..d5d419c021 100644 --- a/dd-sdk-android/src/test/kotlin/com/datadog/android/utils/forge/ErrorEventForgeryFactory.kt +++ b/dd-sdk-android/src/test/kotlin/com/datadog/android/utils/forge/ErrorEventForgeryFactory.kt @@ -6,7 +6,9 @@ package com.datadog.android.utils.forge +import com.datadog.android.core.internal.system.AndroidInfoProvider import com.datadog.android.core.internal.utils.loggableStackTrace +import com.datadog.android.rum.internal.domain.scope.toErrorSchemaType import com.datadog.android.rum.model.ErrorEvent import com.datadog.tools.unit.forge.aThrowable import fr.xgouchet.elmyr.Forge @@ -90,6 +92,23 @@ internal class ErrorEventForgeryFactory : ForgeryFactory { ciTest = forge.aNullable { ErrorEvent.CiTest(anHexadecimalString()) }, + os = forge.aNullable { + val androidInfoProvider = getForgery(AndroidInfoProvider::class.java) + ErrorEvent.Os( + name = androidInfoProvider.osName, + version = androidInfoProvider.osVersion, + versionMajor = androidInfoProvider.osMajorVersion + ) + }, + device = forge.aNullable { + val androidInfoProvider = getForgery(AndroidInfoProvider::class.java) + ErrorEvent.Device( + name = androidInfoProvider.deviceName, + model = androidInfoProvider.deviceModel, + brand = androidInfoProvider.deviceBrand, + type = androidInfoProvider.deviceType.toErrorSchemaType() + ) + }, context = forge.aNullable { ErrorEvent.Context(additionalProperties = forge.exhaustiveAttributes()) }, diff --git a/dd-sdk-android/src/test/kotlin/com/datadog/android/utils/forge/ListenableFutureFactory.kt b/dd-sdk-android/src/test/kotlin/com/datadog/android/utils/forge/ListenableFutureFactory.kt deleted file mode 100644 index df3d2b3311..0000000000 --- a/dd-sdk-android/src/test/kotlin/com/datadog/android/utils/forge/ListenableFutureFactory.kt +++ /dev/null @@ -1,42 +0,0 @@ -/* - * 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 2016-Present Datadog, Inc. - */ - -package com.datadog.android.utils.forge - -import com.google.common.util.concurrent.ListenableFuture -import fr.xgouchet.elmyr.Forge -import fr.xgouchet.elmyr.ForgeryFactory -import java.util.concurrent.Executor -import java.util.concurrent.TimeUnit - -internal class ListenableFutureFactory : ForgeryFactory> { - override fun getForgery(forge: Forge): ListenableFuture { - return object : ListenableFuture { - override fun addListener(listener: Runnable, executor: Executor) { - } - - override fun isDone(): Boolean { - return false - } - - override fun get(): Void? { - return null - } - - override fun get(timeout: Long, unit: TimeUnit): Void? { - return null - } - - override fun cancel(mayInterruptIfRunning: Boolean): Boolean { - return false - } - - override fun isCancelled(): Boolean { - return false - } - } - } -} diff --git a/dd-sdk-android/src/test/kotlin/com/datadog/android/utils/forge/LongTaskEventForgeryFactory.kt b/dd-sdk-android/src/test/kotlin/com/datadog/android/utils/forge/LongTaskEventForgeryFactory.kt index 46e1c327d5..9853934908 100644 --- a/dd-sdk-android/src/test/kotlin/com/datadog/android/utils/forge/LongTaskEventForgeryFactory.kt +++ b/dd-sdk-android/src/test/kotlin/com/datadog/android/utils/forge/LongTaskEventForgeryFactory.kt @@ -6,6 +6,8 @@ package com.datadog.android.utils.forge +import com.datadog.android.core.internal.system.AndroidInfoProvider +import com.datadog.android.rum.internal.domain.scope.toLongTaskSchemaType import com.datadog.android.rum.model.LongTaskEvent import fr.xgouchet.elmyr.Forge import fr.xgouchet.elmyr.ForgeryFactory @@ -60,13 +62,30 @@ internal class LongTaskEventForgeryFactory : service = forge.aNullable { anAlphabeticalString() }, session = LongTaskEvent.LongTaskEventSession( id = forge.getForgery().toString(), - type = LongTaskEvent.Type.USER, + type = LongTaskEvent.LongTaskEventSessionType.USER, hasReplay = forge.aNullable { aBool() } ), source = forge.aNullable { aValueFrom(LongTaskEvent.Source::class.java) }, ciTest = forge.aNullable { LongTaskEvent.CiTest(anHexadecimalString()) }, + os = forge.aNullable { + val androidInfoProvider = getForgery(AndroidInfoProvider::class.java) + LongTaskEvent.Os( + name = androidInfoProvider.osName, + version = androidInfoProvider.osVersion, + versionMajor = androidInfoProvider.osMajorVersion + ) + }, + device = forge.aNullable { + val androidInfoProvider = getForgery(AndroidInfoProvider::class.java) + LongTaskEvent.Device( + name = androidInfoProvider.deviceName, + model = androidInfoProvider.deviceModel, + brand = androidInfoProvider.deviceBrand, + type = androidInfoProvider.deviceType.toLongTaskSchemaType() + ) + }, context = forge.aNullable { LongTaskEvent.Context( additionalProperties = forge.exhaustiveAttributes() diff --git a/dd-sdk-android/src/test/kotlin/com/datadog/android/utils/forge/ResourceEventForgeryFactory.kt b/dd-sdk-android/src/test/kotlin/com/datadog/android/utils/forge/ResourceEventForgeryFactory.kt index 76a1b0be3c..1f8fbed64f 100644 --- a/dd-sdk-android/src/test/kotlin/com/datadog/android/utils/forge/ResourceEventForgeryFactory.kt +++ b/dd-sdk-android/src/test/kotlin/com/datadog/android/utils/forge/ResourceEventForgeryFactory.kt @@ -6,12 +6,14 @@ package com.datadog.android.utils.forge +import com.datadog.android.core.internal.system.AndroidInfoProvider import com.datadog.android.rum.internal.domain.event.ResourceTiming import com.datadog.android.rum.internal.domain.scope.connect import com.datadog.android.rum.internal.domain.scope.dns import com.datadog.android.rum.internal.domain.scope.download import com.datadog.android.rum.internal.domain.scope.firstByte import com.datadog.android.rum.internal.domain.scope.ssl +import com.datadog.android.rum.internal.domain.scope.toResourceSchemaType import com.datadog.android.rum.model.ResourceEvent import fr.xgouchet.elmyr.Forge import fr.xgouchet.elmyr.ForgeryFactory @@ -96,6 +98,23 @@ internal class ResourceEventForgeryFactory : ciTest = forge.aNullable { ResourceEvent.CiTest(anHexadecimalString()) }, + os = forge.aNullable { + val androidInfoProvider = getForgery(AndroidInfoProvider::class.java) + ResourceEvent.Os( + name = androidInfoProvider.osName, + version = androidInfoProvider.osVersion, + versionMajor = androidInfoProvider.osMajorVersion + ) + }, + device = forge.aNullable { + val androidInfoProvider = getForgery(AndroidInfoProvider::class.java) + ResourceEvent.Device( + name = androidInfoProvider.deviceName, + model = androidInfoProvider.deviceModel, + brand = androidInfoProvider.deviceBrand, + type = androidInfoProvider.deviceType.toResourceSchemaType() + ) + }, context = forge.aNullable { ResourceEvent.Context( additionalProperties = forge.exhaustiveAttributes() diff --git a/dd-sdk-android/src/test/kotlin/com/datadog/android/utils/forge/ViewEventForgeryFactory.kt b/dd-sdk-android/src/test/kotlin/com/datadog/android/utils/forge/ViewEventForgeryFactory.kt index 9b4b3abbeb..0b954b54cc 100644 --- a/dd-sdk-android/src/test/kotlin/com/datadog/android/utils/forge/ViewEventForgeryFactory.kt +++ b/dd-sdk-android/src/test/kotlin/com/datadog/android/utils/forge/ViewEventForgeryFactory.kt @@ -6,6 +6,8 @@ package com.datadog.android.utils.forge +import com.datadog.android.core.internal.system.AndroidInfoProvider +import com.datadog.android.rum.internal.domain.scope.toViewSchemaType import com.datadog.android.rum.model.ViewEvent import fr.xgouchet.elmyr.Forge import fr.xgouchet.elmyr.ForgeryFactory @@ -93,13 +95,30 @@ internal class ViewEventForgeryFactory : ForgeryFactory { service = forge.aNullable { anAlphabeticalString() }, session = ViewEvent.ViewEventSession( id = forge.getForgery().toString(), - type = ViewEvent.Type.USER, + type = ViewEvent.ViewEventSessionType.USER, hasReplay = forge.aNullable { aBool() } ), source = forge.aNullable { aValueFrom(ViewEvent.Source::class.java) }, ciTest = forge.aNullable { ViewEvent.CiTest(anHexadecimalString()) }, + os = forge.aNullable { + val androidInfoProvider = getForgery(AndroidInfoProvider::class.java) + ViewEvent.Os( + name = androidInfoProvider.osName, + version = androidInfoProvider.osVersion, + versionMajor = androidInfoProvider.osMajorVersion + ) + }, + device = forge.aNullable { + val androidInfoProvider = getForgery(AndroidInfoProvider::class.java) + ViewEvent.Device( + name = androidInfoProvider.deviceName, + model = androidInfoProvider.deviceModel, + brand = androidInfoProvider.deviceBrand, + type = androidInfoProvider.deviceType.toViewSchemaType() + ) + }, context = forge.aNullable { ViewEvent.Context( additionalProperties = exhaustiveAttributes() diff --git a/detekt.yml b/detekt.yml index 11f572cc13..19c5f671ea 100644 --- a/detekt.yml +++ b/detekt.yml @@ -665,6 +665,7 @@ datadog: # endregion # region Kotlin Collections - "kotlin.collections.List.last():java.util.NoSuchElementException" + - "kotlin.collections.List.first():java.util.NoSuchElementException" - "kotlin.collections.List.get(kotlin.Int):java.util.NoSuchElementException" - "kotlin.collections.MutableIterator.next():java.util.NoSuchElementException" - "kotlin.collections.MutableIterator.remove():java.lang.UnsupportedOperationException,java.lang.IllegalStateException" @@ -716,6 +717,7 @@ datadog: - "android.content.IntentFilter.addAction(kotlin.String)" - "android.content.IntentFilter.constructor()" - "android.content.IntentFilter.constructor(kotlin.String)" + - "android.content.pm.PackageManager.hasSystemFeature(kotlin.String)" - "android.content.res.AssetManager.open(kotlin.String, kotlin.Int)" - "android.database.DatabaseErrorHandler.onCorruption(android.database.sqlite.SQLiteDatabase)" - "android.database.DefaultDatabaseErrorHandler.constructor()" @@ -1031,6 +1033,8 @@ datadog: - "kotlin.Boolean.hashCode()" - "kotlin.Byte.toInt()" - "kotlin.ByteArray.constructor(kotlin.Int)" + - "kotlin.Char.isLowerCase()" + - "kotlin.Char.titlecase(java.util.Locale)" - "kotlin.Double.isNaN()" - "kotlin.Double.pow(kotlin.Int)" - "kotlin.Double.rangeTo(kotlin.Double)" @@ -1049,6 +1053,7 @@ datadog: # endregion # region Kotlin String - "kotlin.String.contains(kotlin.Char, kotlin.Boolean)" + - "kotlin.String.contains(kotlin.CharSequence, kotlin.Boolean)" - "kotlin.String.count(kotlin.Function1)" - "kotlin.String.endsWith(kotlin.Char, kotlin.Boolean)" - "kotlin.String.endsWith(kotlin.String, kotlin.Boolean)" @@ -1067,6 +1072,7 @@ datadog: - "kotlin.String.plus(kotlin.Any?)" - "kotlin.String.replace(kotlin.Char, kotlin.Char, kotlin.Boolean)" - "kotlin.String.replace(kotlin.text.Regex, kotlin.String)" + - "kotlin.String.replaceFirstChar(kotlin.Function1)" - "kotlin.String.split(kotlin.Array, kotlin.Boolean, kotlin.Int)" - "kotlin.String.split(kotlin.CharArray, kotlin.Boolean, kotlin.Int)" - "kotlin.String.startsWith(kotlin.String, kotlin.Boolean)"