From d705e7b70ebc32c06d601aa30d8869a4f7999263 Mon Sep 17 00:00:00 2001 From: Maciek Grzybowski Date: Thu, 9 Jun 2022 19:25:18 +0200 Subject: [PATCH 1/8] RUMM-2197 Read device model from `sysctl` --- Datadog/Datadog.xcodeproj/project.pbxproj | 6 ++ .../Datadog/Core/System/MobileDevice.swift | 80 +++++++++++++++---- Sources/Datadog/Core/System/Sysctl.swift | 73 +++++++++++++++++ .../Core/System/MobileDeviceTests.swift | 46 +++++++++-- .../Datadog/Mocks/CoreMocks.swift | 2 + .../Mocks/SystemFrameworks/UIKitMocks.swift | 2 +- 6 files changed, 186 insertions(+), 23 deletions(-) create mode 100644 Sources/Datadog/Core/System/Sysctl.swift diff --git a/Datadog/Datadog.xcodeproj/project.pbxproj b/Datadog/Datadog.xcodeproj/project.pbxproj index 3427899398..6ca3c697d8 100644 --- a/Datadog/Datadog.xcodeproj/project.pbxproj +++ b/Datadog/Datadog.xcodeproj/project.pbxproj @@ -482,6 +482,8 @@ 61FC5F3525CC1898006BB4DE /* CrashContextProviderTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 61FC5F3425CC1898006BB4DE /* CrashContextProviderTests.swift */; }; 61FC5F4525CC23C9006BB4DE /* RUMWithCrashContextIntegration.swift in Sources */ = {isa = PBXBuildFile; fileRef = 61FC5F4425CC23C9006BB4DE /* RUMWithCrashContextIntegration.swift */; }; 61FC5F4E25CC2920006BB4DE /* RUMWithCrashContextIntegrationTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 61FC5F4D25CC2920006BB4DE /* RUMWithCrashContextIntegrationTests.swift */; }; + 61FD9FC92851E67100214BD9 /* Sysctl.swift in Sources */ = {isa = PBXBuildFile; fileRef = 61FD9FC82851E67100214BD9 /* Sysctl.swift */; }; + 61FD9FCA2851E67100214BD9 /* Sysctl.swift in Sources */ = {isa = PBXBuildFile; fileRef = 61FD9FC82851E67100214BD9 /* Sysctl.swift */; }; 61FDBA1326971953001D9D43 /* CrashReportMinifier.swift in Sources */ = {isa = PBXBuildFile; fileRef = 61FDBA1226971953001D9D43 /* CrashReportMinifier.swift */; }; 61FDBA15269722B4001D9D43 /* CrashReportMinifierTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 61FDBA14269722B4001D9D43 /* CrashReportMinifierTests.swift */; }; 61FDBA1726974CA9001D9D43 /* DDCrashReportBuilderTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 61FDBA1626974CA9001D9D43 /* DDCrashReportBuilderTests.swift */; }; @@ -1670,6 +1672,7 @@ 61FC5F3425CC1898006BB4DE /* CrashContextProviderTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CrashContextProviderTests.swift; sourceTree = ""; }; 61FC5F4425CC23C9006BB4DE /* RUMWithCrashContextIntegration.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = RUMWithCrashContextIntegration.swift; sourceTree = ""; }; 61FC5F4D25CC2920006BB4DE /* RUMWithCrashContextIntegrationTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = RUMWithCrashContextIntegrationTests.swift; sourceTree = ""; }; + 61FD9FC82851E67100214BD9 /* Sysctl.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Sysctl.swift; sourceTree = ""; }; 61FDBA1226971953001D9D43 /* CrashReportMinifier.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CrashReportMinifier.swift; sourceTree = ""; }; 61FDBA14269722B4001D9D43 /* CrashReportMinifierTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CrashReportMinifierTests.swift; sourceTree = ""; }; 61FDBA1626974CA9001D9D43 /* DDCrashReportBuilderTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = DDCrashReportBuilderTests.swift; sourceTree = ""; }; @@ -2107,6 +2110,7 @@ 61E36A10254B2280001AD6F2 /* LaunchTimeProvider.swift */, 61133BA22423979B00786299 /* CarrierInfoProvider.swift */, 61133BA32423979B00786299 /* MobileDevice.swift */, + 61FD9FC82851E67100214BD9 /* Sysctl.swift */, 61133BA42423979B00786299 /* NetworkConnectionInfoProvider.swift */, 61133BA52423979B00786299 /* BatteryStatusProvider.swift */, 9ED6A6B325F2901800CB2E29 /* AppStateListener.swift */, @@ -5046,6 +5050,7 @@ 61D3E0D6277B23F1008BE766 /* KronosClock.swift in Sources */, D248ED452807193B00B315B4 /* RUMTelemetry.swift in Sources */, 613E793B2577B6EE00DFCC17 /* DataReader.swift in Sources */, + 61FD9FC92851E67100214BD9 /* Sysctl.swift in Sources */, 614B0A5324EBFE5500A2A780 /* DDRUMMonitor.swift in Sources */, 61133BE32423979B00786299 /* UserInfoProvider.swift in Sources */, 9EB4B868275103E40041CD03 /* WebEventBridge.swift in Sources */, @@ -5606,6 +5611,7 @@ D2CB6E4027C50EAE00A62B57 /* UIViewControllerSwizzler.swift in Sources */, D2CB6E4127C50EAE00A62B57 /* RUMCurrentContext.swift in Sources */, D2CB6E4227C50EAE00A62B57 /* RUMConnectivityInfoProvider.swift in Sources */, + 61FD9FCA2851E67100214BD9 /* Sysctl.swift in Sources */, D248ED462807193B00B315B4 /* RUMTelemetry.swift in Sources */, D2CB6E4327C50EAE00A62B57 /* ObjcExceptionHandler.m in Sources */, D2CB6E4427C50EAE00A62B57 /* UIApplicationSwizzler.swift in Sources */, diff --git a/Sources/Datadog/Core/System/MobileDevice.swift b/Sources/Datadog/Core/System/MobileDevice.swift index bcfd18c5bd..abc4d416fd 100644 --- a/Sources/Datadog/Core/System/MobileDevice.swift +++ b/Sources/Datadog/Core/System/MobileDevice.swift @@ -10,8 +10,19 @@ import UIKit internal class MobileDevice { // MARK: - Info + /// Device manufacturer name. + let brand = "Apple" + + /// Device marketing name, e.g. "iPhone", "iPad", "iPod touch". + let name: String + + /// Device model name, e.g. "iPhone10,1", "iPhone13,2". let model: String + + /// The name of operating system, e.g. "iOS", "iPadOS", "tvOS". let osName: String + + /// The version of the operating system, e.g. "15.4.1". let osVersion: String // MARK: - Battery status monitoring @@ -37,6 +48,7 @@ internal class MobileDevice { let currentBatteryStatus: () -> BatteryStatus init( + name: String, model: String, osName: String, osVersion: String, @@ -44,6 +56,7 @@ internal class MobileDevice { resetBatteryStatusMonitoring: @escaping () -> Void, currentBatteryStatus: @escaping () -> BatteryStatus ) { + self.name = name self.model = model self.osName = osName self.osVersion = osVersion @@ -53,7 +66,13 @@ internal class MobileDevice { } #if os(iOS) - convenience init(uiDevice: UIDevice, processInfo: ProcessInfo, notificationCenter: NotificationCenter) { + + convenience init( + model: String, + uiDevice: UIDevice, + processInfo: ProcessInfo, + notificationCenter: NotificationCenter + ) { let wasBatteryMonitoringEnabled = uiDevice.isBatteryMonitoringEnabled // We capture this `lowPowerModeMonitor` in `currentBatteryStatus` closure so its lifecycle @@ -61,7 +80,8 @@ internal class MobileDevice { let lowPowerModeMonitor = LowPowerModeMonitor(initialProcessInfo: processInfo, notificationCenter: notificationCenter) self.init( - model: uiDevice.model, + name: uiDevice.model, + model: model, osName: uiDevice.systemName, osVersion: uiDevice.systemVersion, enableBatteryStatusMonitoring: { uiDevice.isBatteryMonitoringEnabled = true }, @@ -77,19 +97,25 @@ internal class MobileDevice { } convenience init() { + let processInfo = ProcessInfo.processInfo + let device = UIDevice.current + #if !targetEnvironment(simulator) - // Real device + // Real iOS device self.init( - uiDevice: UIDevice.current, - processInfo: ProcessInfo.processInfo, + model: (try? Sysctl.getModel()) ?? device.model, + uiDevice: device, + processInfo: processInfo, notificationCenter: .default ) #else + let model = processInfo.environment["SIMULATOR_MODEL_IDENTIFIER"] ?? device.model // iOS Simulator - battery monitoring doesn't work on Simulator, so return "always OK" value self.init( - model: UIDevice.current.model, - osName: UIDevice.current.systemName, - osVersion: UIDevice.current.systemVersion, + name: device.model, + model: "\(model) Simulator", + osName: device.systemName, + osVersion: device.systemVersion, enableBatteryStatusMonitoring: {}, resetBatteryStatusMonitoring: {}, currentBatteryStatus: { BatteryStatus(state: .full, level: 1, isLowPowerModeEnabled: false) } @@ -107,22 +133,48 @@ internal class MobileDevice { } } - #else + #elseif os(tvOS) + convenience init( - uiDevice: UIDevice = .current, - processInfo: ProcessInfo = .processInfo, - notificationCenter: NotificationCenter = .default + model: String, + uiDevice: UIDevice, + processInfo: ProcessInfo, + notificationCenter: NotificationCenter ) { - // iOS Simulator - battery monitoring doesn't work on tvOS nor Simulator, so return "always OK" value self.init( - model: uiDevice.model, + name: uiDevice.model, + model: model, osName: uiDevice.systemName, osVersion: uiDevice.systemVersion, + // Battery monitoring doesn't work on tvOS, so return "always OK" value: enableBatteryStatusMonitoring: {}, resetBatteryStatusMonitoring: {}, currentBatteryStatus: { BatteryStatus(state: .full, level: 1, isLowPowerModeEnabled: false) } ) } + + convenience init() { + let processInfo = ProcessInfo.processInfo + let device = UIDevice.current + let model: String + + #if !targetEnvironment(simulator) + // Real tvOS device + model = (try? Sysctl.getModel()) ?? device.model + #else + // tvOS Simulator + let simulatorModel = processInfo.environment["SIMULATOR_MODEL_IDENTIFIER"] ?? device.model + model = "\(simulatorModel) Simulator" + #endif + + self.init( + model: model, + uiDevice: device, + processInfo: processInfo, + notificationCenter: .default + ) + } + #endif } diff --git a/Sources/Datadog/Core/System/Sysctl.swift b/Sources/Datadog/Core/System/Sysctl.swift new file mode 100644 index 0000000000..f5a20dd134 --- /dev/null +++ b/Sources/Datadog/Core/System/Sysctl.swift @@ -0,0 +1,73 @@ +/* + * Unless explicitly stated otherwise all files in this repository are licensed under the Apache License Version 2.0. + * This product includes software developed at Datadog (https://www.datadoghq.com/). + * Copyright 2019-2020 Datadog, Inc. + * + * This file includes software created by Matt Gallagher on 2016/02/03 and modified by Datadog. + * Copyright © 2016 Matt Gallagher ( https://www.cocoawithlove.com ). + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * Use of this source code is governed by ISC license: https://github.com/mattgallagher/CwlUtils/blob/master/LICENSE.txt + */ + +import Foundation + +/// A "static"-only namespace around a series of functions that operate on buffers returned from the `Darwin.sysctl` function +internal struct Sysctl { + /// Possible errors. + enum Error: Swift.Error { + case unknown + case malformedUTF8 + case posixError(POSIXErrorCode) + } + + /// Access the raw data for an array of sysctl identifiers. + private static func data(for keys: [Int32]) throws -> [Int8] { + return try keys.withUnsafeBufferPointer { keysPointer throws -> [Int8] in + // Preflight the request to get the required data size + var requiredSize = 0 + let preFlightResult = Darwin.sysctl(UnsafeMutablePointer(mutating: keysPointer.baseAddress), UInt32(keys.count), nil, &requiredSize, nil, 0) + if preFlightResult != 0 { + throw POSIXErrorCode(rawValue: errno).map { + print($0.rawValue) + return Error.posixError($0) + } ?? Error.unknown + } + + // Run the actual request with an appropriately sized array buffer + let data: [Int8] = Array(repeating: 0, count: requiredSize) + let result = data.withUnsafeBufferPointer { dataBuffer -> Int32 in + return Darwin.sysctl(UnsafeMutablePointer(mutating: keysPointer.baseAddress), UInt32(keys.count), UnsafeMutableRawPointer(mutating: dataBuffer.baseAddress), &requiredSize, nil, 0) + } + if result != 0 { + throw POSIXErrorCode(rawValue: errno).map { Error.posixError($0) } ?? Error.unknown + } + + return data + } + } + + /// Invoke `sysctl` with an array of identifers, interpreting the returned buffer as a `String`. This function will throw `Error.malformedUTF8` if the buffer returned from `sysctl` cannot be interpreted as a UTF8 buffer. + private static func string(for keys: [Int32]) throws -> String { + let optionalString = try data(for: keys).withUnsafeBufferPointer { dataPointer -> String? in + dataPointer.baseAddress.flatMap { String(validatingUTF8: $0) } + } + guard let s = optionalString else { + throw Error.malformedUTF8 + } + return s + } + + /// e.g. "MacPro4,1" or "iPhone8,1" + /// NOTE: this is *corrected* on iOS devices to fetch hw.machine + static func getModel() throws -> String { + #if os(iOS) && !arch(x86_64) && !arch(i386) // iOS device && not Simulator + return try Sysctl.string(for: [CTL_HW, HW_MACHINE]) + #else + return try Sysctl.string(for: [CTL_HW, HW_MODEL]) + #endif + } +} diff --git a/Tests/DatadogTests/Datadog/Core/System/MobileDeviceTests.swift b/Tests/DatadogTests/Datadog/Core/System/MobileDeviceTests.swift index 1c96fa5001..dd116bb020 100644 --- a/Tests/DatadogTests/Datadog/Core/System/MobileDeviceTests.swift +++ b/Tests/DatadogTests/Datadog/Core/System/MobileDeviceTests.swift @@ -12,22 +12,35 @@ class MobileDeviceTests: XCTestCase { private let notificationCenter = NotificationCenter() func testWhenRunningOnMobile_itUsesUIDeviceInfo() { + let randomUIDeviceModel: String = .mockRandom() + let randomModel: String = .mockRandom() + let randomOSName: String = .mockRandom() + let randomOSVersion: String = .mockRandom() + let uiDevice = UIDeviceMock( - model: "model mock", - systemName: "system name mock", - systemVersion: "system version mock" + model: randomUIDeviceModel, + systemName: randomOSName, + systemVersion: randomOSVersion + ) + let mobileDevice = MobileDevice( + model: randomModel, + uiDevice: uiDevice, + processInfo: ProcessInfoMock(), + notificationCenter: notificationCenter ) - let mobileDevice = MobileDevice(uiDevice: uiDevice, processInfo: ProcessInfoMock(), notificationCenter: notificationCenter) - XCTAssertEqual(mobileDevice.model, uiDevice.model) - XCTAssertEqual(mobileDevice.osName, uiDevice.systemName) - XCTAssertEqual(mobileDevice.osVersion, uiDevice.systemVersion) + XCTAssertEqual(mobileDevice.name, randomUIDeviceModel) + XCTAssertEqual(mobileDevice.model, randomModel) + XCTAssertEqual(mobileDevice.osName, randomOSName) + XCTAssertEqual(mobileDevice.osVersion, randomOSVersion) } #if os(iOS) + func testWhenRunningOnMobile_itUsesUIDeviceBatteryState() { func mobileDevice(withBatteryState bateryState: UIDevice.BatteryState) -> MobileDevice { return MobileDevice( + model: .mockAny(), uiDevice: UIDeviceMock(batteryState: bateryState), processInfo: ProcessInfoMock(), notificationCenter: notificationCenter @@ -42,6 +55,7 @@ class MobileDeviceTests: XCTestCase { func testWhenRunningOnMobile_itUsesUIDeviceBatteryLevel() { let randomBatteryLevel: Float = .random(in: 0...1) let mobileDevice = MobileDevice( + model: .mockAny(), uiDevice: UIDeviceMock(batteryLevel: randomBatteryLevel), processInfo: ProcessInfoMock(), notificationCenter: notificationCenter @@ -54,6 +68,7 @@ class MobileDeviceTests: XCTestCase { let isLowPowerModeEnabled: Bool = .random() let mobileDevice = MobileDevice( + model: .mockAny(), uiDevice: UIDeviceMock(), processInfo: ProcessInfoMock(isLowPowerModeEnabled: isLowPowerModeEnabled), notificationCenter: notificationCenter @@ -78,7 +93,12 @@ class MobileDeviceTests: XCTestCase { func testWhenRunningOnMobile_itTogglesBatteryMonitoring() { let uiDevice = UIDeviceMock(isBatteryMonitoringEnabled: false) - let mobileDevice = MobileDevice(uiDevice: uiDevice, processInfo: ProcessInfoMock(), notificationCenter: notificationCenter) + let mobileDevice = MobileDevice( + model: .mockAny(), + uiDevice: uiDevice, + processInfo: ProcessInfoMock(), + notificationCenter: notificationCenter + ) XCTAssertFalse(uiDevice.isBatteryMonitoringEnabled) mobileDevice.enableBatteryStatusMonitoring() @@ -86,5 +106,15 @@ class MobileDeviceTests: XCTestCase { mobileDevice.resetBatteryStatusMonitoring() XCTAssertFalse(uiDevice.isBatteryMonitoringEnabled) } + + #elseif os(tvOS) + + func testWhenRunningOnAppleTV_itReportsFullBatteryState() { + let device = MobileDevice() + XCTAssertEqual(device.currentBatteryStatus().level, 1) + XCTAssertEqual(device.currentBatteryStatus().state, .full) + XCTAssertFalse(device.currentBatteryStatus().isLowPowerModeEnabled) + } + #endif } diff --git a/Tests/DatadogTests/Datadog/Mocks/CoreMocks.swift b/Tests/DatadogTests/Datadog/Mocks/CoreMocks.swift index 27890c14ba..4e0d6e2838 100644 --- a/Tests/DatadogTests/Datadog/Mocks/CoreMocks.swift +++ b/Tests/DatadogTests/Datadog/Mocks/CoreMocks.swift @@ -884,6 +884,7 @@ extension MobileDevice { } static func mockWith( + name: String = .mockAny(), model: String = .mockAny(), osName: String = .mockAny(), osVersion: String = .mockAny(), @@ -892,6 +893,7 @@ extension MobileDevice { currentBatteryStatus: @escaping () -> BatteryStatus = { .mockAny() } ) -> MobileDevice { return MobileDevice( + name: name, model: model, osName: osName, osVersion: osVersion, diff --git a/Tests/DatadogTests/Datadog/Mocks/SystemFrameworks/UIKitMocks.swift b/Tests/DatadogTests/Datadog/Mocks/SystemFrameworks/UIKitMocks.swift index 4675a1f446..2a30a4acc2 100644 --- a/Tests/DatadogTests/Datadog/Mocks/SystemFrameworks/UIKitMocks.swift +++ b/Tests/DatadogTests/Datadog/Mocks/SystemFrameworks/UIKitMocks.swift @@ -22,7 +22,7 @@ extension UIDevice.BatteryState { class UIDeviceMock: UIDevice { override var model: String { _model } override var systemName: String { _systemName } - override var systemVersion: String { "mock system version" } + override var systemVersion: String { _systemVersion } private var _model: String private var _systemName: String From 5949bd3c43e8f205787747d8c90dbd02f02bc967 Mon Sep 17 00:00:00 2001 From: Maciek Grzybowski Date: Fri, 10 Jun 2022 12:46:56 +0200 Subject: [PATCH 2/8] RUMM-2197 Infer device and OS info from `MobileDevice` --- Datadog/Datadog.xcodeproj/project.pbxproj | 24 +++++++++ .../Datadog/Core/Upload/RequestBuilder.swift | 2 +- .../Datadog/RUM/RUMEvent/RUMDeviceInfo.swift | 41 ++++++++++++++ .../RUM/RUMEvent/RUMOperatingSystemInfo.swift | 15 ++++++ .../Core/System/MobileDeviceTests.swift | 1 + .../Core/Upload/RequestBuilderTests.swift | 4 +- .../Datadog/Logging/LoggingFeatureTests.swift | 10 ++-- .../RUM/RUMEvent/RUMDeviceInfoTests.swift | 53 +++++++++++++++++++ .../RUMOperatingSystemInfoTests.swift | 39 ++++++++++++++ .../Datadog/RUM/RUMFeatureTests.swift | 10 ++-- .../Datadog/Tracing/TracingFeatureTests.swift | 10 ++-- 11 files changed, 197 insertions(+), 12 deletions(-) create mode 100644 Sources/Datadog/RUM/RUMEvent/RUMDeviceInfo.swift create mode 100644 Sources/Datadog/RUM/RUMEvent/RUMOperatingSystemInfo.swift create mode 100644 Tests/DatadogTests/Datadog/RUM/RUMEvent/RUMDeviceInfoTests.swift create mode 100644 Tests/DatadogTests/Datadog/RUM/RUMEvent/RUMOperatingSystemInfoTests.swift diff --git a/Datadog/Datadog.xcodeproj/project.pbxproj b/Datadog/Datadog.xcodeproj/project.pbxproj index 6ca3c697d8..7b975a5b79 100644 --- a/Datadog/Datadog.xcodeproj/project.pbxproj +++ b/Datadog/Datadog.xcodeproj/project.pbxproj @@ -262,6 +262,10 @@ 6167C7952666622800D4CF07 /* LoggingE2EHelpers.swift in Sources */ = {isa = PBXBuildFile; fileRef = 6167C7942666622800D4CF07 /* LoggingE2EHelpers.swift */; }; 616B6684259CAE3300968EE8 /* DDGlobalTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 616B6683259CAE3300968EE8 /* DDGlobalTests.swift */; }; 616B668E259CC28E00968EE8 /* DDRUMMonitorTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 616B668D259CC28E00968EE8 /* DDRUMMonitorTests.swift */; }; + 616C0A9E28573DFF00C13264 /* RUMOperatingSystemInfo.swift in Sources */ = {isa = PBXBuildFile; fileRef = 616C0A9D28573DFF00C13264 /* RUMOperatingSystemInfo.swift */; }; + 616C0A9F28573DFF00C13264 /* RUMOperatingSystemInfo.swift in Sources */ = {isa = PBXBuildFile; fileRef = 616C0A9D28573DFF00C13264 /* RUMOperatingSystemInfo.swift */; }; + 616C0AA128573F6300C13264 /* RUMOperatingSystemInfoTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 616C0AA028573F6300C13264 /* RUMOperatingSystemInfoTests.swift */; }; + 616C0AA228573F6300C13264 /* RUMOperatingSystemInfoTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 616C0AA028573F6300C13264 /* RUMOperatingSystemInfoTests.swift */; }; 616CCE13250A1868009FED46 /* RUMCommandSubscriber.swift in Sources */ = {isa = PBXBuildFile; fileRef = 616CCE12250A1868009FED46 /* RUMCommandSubscriber.swift */; }; 616CCE16250A467E009FED46 /* RUMInstrumentation.swift in Sources */ = {isa = PBXBuildFile; fileRef = 616CCE15250A467E009FED46 /* RUMInstrumentation.swift */; }; 6170DC1C25C18729003AED5C /* DDCrashReportingPlugin.swift in Sources */ = {isa = PBXBuildFile; fileRef = 6170DC1B25C18729003AED5C /* DDCrashReportingPlugin.swift */; }; @@ -484,6 +488,10 @@ 61FC5F4E25CC2920006BB4DE /* RUMWithCrashContextIntegrationTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 61FC5F4D25CC2920006BB4DE /* RUMWithCrashContextIntegrationTests.swift */; }; 61FD9FC92851E67100214BD9 /* Sysctl.swift in Sources */ = {isa = PBXBuildFile; fileRef = 61FD9FC82851E67100214BD9 /* Sysctl.swift */; }; 61FD9FCA2851E67100214BD9 /* Sysctl.swift in Sources */ = {isa = PBXBuildFile; fileRef = 61FD9FC82851E67100214BD9 /* Sysctl.swift */; }; + 61FD9FCC28533EDF00214BD9 /* RUMDeviceInfo.swift in Sources */ = {isa = PBXBuildFile; fileRef = 61FD9FCB28533EDF00214BD9 /* RUMDeviceInfo.swift */; }; + 61FD9FCD28533EDF00214BD9 /* RUMDeviceInfo.swift in Sources */ = {isa = PBXBuildFile; fileRef = 61FD9FCB28533EDF00214BD9 /* RUMDeviceInfo.swift */; }; + 61FD9FD12853562A00214BD9 /* RUMDeviceInfoTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 61FD9FCE28534EBD00214BD9 /* RUMDeviceInfoTests.swift */; }; + 61FD9FD22853562B00214BD9 /* RUMDeviceInfoTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 61FD9FCE28534EBD00214BD9 /* RUMDeviceInfoTests.swift */; }; 61FDBA1326971953001D9D43 /* CrashReportMinifier.swift in Sources */ = {isa = PBXBuildFile; fileRef = 61FDBA1226971953001D9D43 /* CrashReportMinifier.swift */; }; 61FDBA15269722B4001D9D43 /* CrashReportMinifierTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 61FDBA14269722B4001D9D43 /* CrashReportMinifierTests.swift */; }; 61FDBA1726974CA9001D9D43 /* DDCrashReportBuilderTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 61FDBA1626974CA9001D9D43 /* DDCrashReportBuilderTests.swift */; }; @@ -1444,6 +1452,8 @@ 6167C7942666622800D4CF07 /* LoggingE2EHelpers.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = LoggingE2EHelpers.swift; sourceTree = ""; }; 616B6683259CAE3300968EE8 /* DDGlobalTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = DDGlobalTests.swift; sourceTree = ""; }; 616B668D259CC28E00968EE8 /* DDRUMMonitorTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = DDRUMMonitorTests.swift; sourceTree = ""; }; + 616C0A9D28573DFF00C13264 /* RUMOperatingSystemInfo.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = RUMOperatingSystemInfo.swift; sourceTree = ""; }; + 616C0AA028573F6300C13264 /* RUMOperatingSystemInfoTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = RUMOperatingSystemInfoTests.swift; sourceTree = ""; }; 616CCE12250A1868009FED46 /* RUMCommandSubscriber.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = RUMCommandSubscriber.swift; sourceTree = ""; }; 616CCE15250A467E009FED46 /* RUMInstrumentation.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = RUMInstrumentation.swift; sourceTree = ""; }; 6170DC1B25C18729003AED5C /* DDCrashReportingPlugin.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = DDCrashReportingPlugin.swift; sourceTree = ""; }; @@ -1673,6 +1683,8 @@ 61FC5F4425CC23C9006BB4DE /* RUMWithCrashContextIntegration.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = RUMWithCrashContextIntegration.swift; sourceTree = ""; }; 61FC5F4D25CC2920006BB4DE /* RUMWithCrashContextIntegrationTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = RUMWithCrashContextIntegrationTests.swift; sourceTree = ""; }; 61FD9FC82851E67100214BD9 /* Sysctl.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Sysctl.swift; sourceTree = ""; }; + 61FD9FCB28533EDF00214BD9 /* RUMDeviceInfo.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = RUMDeviceInfo.swift; sourceTree = ""; }; + 61FD9FCE28534EBD00214BD9 /* RUMDeviceInfoTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = RUMDeviceInfoTests.swift; sourceTree = ""; }; 61FDBA1226971953001D9D43 /* CrashReportMinifier.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CrashReportMinifier.swift; sourceTree = ""; }; 61FDBA14269722B4001D9D43 /* CrashReportMinifierTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CrashReportMinifierTests.swift; sourceTree = ""; }; 61FDBA1626974CA9001D9D43 /* DDCrashReportBuilderTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = DDCrashReportBuilderTests.swift; sourceTree = ""; }; @@ -3696,6 +3708,8 @@ 61FF281D24B8968D000B3D9B /* RUMEventBuilder.swift */, 61122ED325B1B84D00F9C7F5 /* RUMEventSanitizer.swift */, 614B0A4E24EBDC6B00A2A780 /* RUMConnectivityInfoProvider.swift */, + 61FD9FCB28533EDF00214BD9 /* RUMDeviceInfo.swift */, + 616C0A9D28573DFF00C13264 /* RUMOperatingSystemInfo.swift */, ); path = RUMEvent; sourceTree = ""; @@ -3881,6 +3895,8 @@ 61FF282024B8981D000B3D9B /* RUMEventBuilderTests.swift */, 61122EED25B1D75B00F9C7F5 /* RUMEventSanitizerTests.swift */, 614B0A5024EBDC8000A2A780 /* RUMConnectivityInfoProviderTests.swift */, + 61FD9FCE28534EBD00214BD9 /* RUMDeviceInfoTests.swift */, + 616C0AA028573F6300C13264 /* RUMOperatingSystemInfoTests.swift */, ); path = RUMEvent; sourceTree = ""; @@ -4985,6 +5001,7 @@ 61C5A8A724509FAA00DA608C /* SpanEventBuilder.swift in Sources */, 6179FFD3254ADB1700556A0B /* ObjcAppLaunchHandler.m in Sources */, F637AED22697404200516F32 /* UIKitRUMUserActionsPredicate.swift in Sources */, + 616C0A9E28573DFF00C13264 /* RUMOperatingSystemInfo.swift in Sources */, 61AD4E3824531500006E34EA /* DataFormat.swift in Sources */, 9E58E8E124615C75008E5063 /* JSONEncoder.swift in Sources */, 61133BCA2423979B00786299 /* CodableValue.swift in Sources */, @@ -5088,6 +5105,7 @@ 61D3E0D4277B23F1008BE766 /* KronosTimeStorage.swift in Sources */, 61133BD12423979B00786299 /* FilesOrchestrator.swift in Sources */, 61133BCD2423979B00786299 /* NetworkConnectionInfoProvider.swift in Sources */, + 61FD9FCC28533EDF00214BD9 /* RUMDeviceInfo.swift in Sources */, 61FF282424B8A1C3000B3D9B /* RUMEventFileOutput.swift in Sources */, 61B22E5A24F3E6B700DC26D2 /* RUMDebugging.swift in Sources */, D24C27EA270C8BEE005DE596 /* DataCompression.swift in Sources */, @@ -5146,6 +5164,7 @@ D29889C9273413ED00A4D1A9 /* RUMViewsHandlerTests.swift in Sources */, 61C5A8A024509C1100DA608C /* Casting+Tracing.swift in Sources */, 61133C662423990D00786299 /* LogSanitizerTests.swift in Sources */, + 616C0AA128573F6300C13264 /* RUMOperatingSystemInfoTests.swift in Sources */, 6114FE23257671F00084E372 /* ConsentAwareDataWriterTests.swift in Sources */, 61410167251A661D00E3C2D9 /* UIApplicationSwizzlerTests.swift in Sources */, 61FF282824B8A31E000B3D9B /* RUMEventMatcher.swift in Sources */, @@ -5313,6 +5332,7 @@ 6121627C247D220500AC5D67 /* LoggingForTracingAdapterTests.swift in Sources */, 61133C532423990D00786299 /* MobileDeviceTests.swift in Sources */, 61FF282124B8981D000B3D9B /* RUMEventBuilderTests.swift in Sources */, + 61FD9FD22853562B00214BD9 /* RUMDeviceInfoTests.swift in Sources */, 61B5E42926DFB60A000B0A5F /* DDConfiguration+apiTests.m in Sources */, 6184751826EFD03400C7C9C5 /* DatadogTestsObserverLoader.m in Sources */, 61345613244756E300E7DA6B /* PerformancePresetTests.swift in Sources */, @@ -5716,12 +5736,14 @@ D2CB6EA727C50EAE00A62B57 /* Versioning.swift in Sources */, D2CB6EA827C50EAE00A62B57 /* HTTPClient.swift in Sources */, D2CB6EA927C50EAE00A62B57 /* LogEventMapper.swift in Sources */, + 61FD9FCD28533EDF00214BD9 /* RUMDeviceInfo.swift in Sources */, D2CB6EAA27C50EAE00A62B57 /* URLSessionSwizzler.swift in Sources */, D2CB6EAB27C50EAE00A62B57 /* VitalMemoryReader.swift in Sources */, D2CB6EAC27C50EAE00A62B57 /* DatadogConfiguration.swift in Sources */, D2CB6EAD27C50EAE00A62B57 /* DataProcessor.swift in Sources */, D2CB6EAE27C50EAE00A62B57 /* DataOrchestrator.swift in Sources */, D2CB6EAF27C50EAE00A62B57 /* BundleType.swift in Sources */, + 616C0A9F28573DFF00C13264 /* RUMOperatingSystemInfo.swift in Sources */, D2CB6EB027C50EAE00A62B57 /* UIKitRUMViewsPredicate.swift in Sources */, D2CB6EB127C50EAE00A62B57 /* BatteryStatusProvider.swift in Sources */, D2CB6EB227C50EAE00A62B57 /* Sampler.swift in Sources */, @@ -5762,6 +5784,7 @@ D2CB6ED927C520D400A62B57 /* RUMViewsHandlerTests.swift in Sources */, D2CB6EDA27C520D400A62B57 /* Casting+Tracing.swift in Sources */, D2CB6EDB27C520D400A62B57 /* LogSanitizerTests.swift in Sources */, + 616C0AA228573F6300C13264 /* RUMOperatingSystemInfoTests.swift in Sources */, D2CB6EDC27C520D400A62B57 /* ConsentAwareDataWriterTests.swift in Sources */, D2CB6EDD27C520D400A62B57 /* UIApplicationSwizzlerTests.swift in Sources */, D2CB6EDE27C520D400A62B57 /* RUMEventMatcher.swift in Sources */, @@ -5929,6 +5952,7 @@ D2CB6F8027C520D400A62B57 /* LoggingForTracingAdapterTests.swift in Sources */, D2CB6F8127C520D400A62B57 /* MobileDeviceTests.swift in Sources */, D2CB6F8227C520D400A62B57 /* RUMEventBuilderTests.swift in Sources */, + 61FD9FD12853562A00214BD9 /* RUMDeviceInfoTests.swift in Sources */, D2CB6F8327C520D400A62B57 /* DDConfiguration+apiTests.m in Sources */, D2CB6F8427C520D400A62B57 /* DatadogTestsObserverLoader.m in Sources */, D2CB6F8527C520D400A62B57 /* PerformancePresetTests.swift in Sources */, diff --git a/Sources/Datadog/Core/Upload/RequestBuilder.swift b/Sources/Datadog/Core/Upload/RequestBuilder.swift index b256e897aa..1473bb9309 100644 --- a/Sources/Datadog/Core/Upload/RequestBuilder.swift +++ b/Sources/Datadog/Core/Upload/RequestBuilder.swift @@ -67,7 +67,7 @@ internal struct RequestBuilder { return HTTPHeader( field: userAgentHeaderField, - value: .constant("\(sanitizedAppName)/\(appVersion) CFNetwork (\(device.model); \(device.osName)/\(device.osVersion))") + value: .constant("\(sanitizedAppName)/\(appVersion) CFNetwork (\(device.name); \(device.osName)/\(device.osVersion))") ) } diff --git a/Sources/Datadog/RUM/RUMEvent/RUMDeviceInfo.swift b/Sources/Datadog/RUM/RUMEvent/RUMDeviceInfo.swift new file mode 100644 index 0000000000..f2dd230f15 --- /dev/null +++ b/Sources/Datadog/RUM/RUMEvent/RUMDeviceInfo.swift @@ -0,0 +1,41 @@ +/* + * Unless explicitly stated otherwise all files in this repository are licensed under the Apache License Version 2.0. + * This product includes software developed at Datadog (https://www.datadoghq.com/). + * Copyright 2019-2020 Datadog, Inc. + */ + +import Foundation + +extension RUMDevice { + init(from device: MobileDevice, telemetry: Telemetry?) { + self.init( + brand: device.brand, + model: device.model, + name: device.name, + type: { + if let type = RUMDeviceType(from: device.model) { + return type + } else { + telemetry?.debug("Couldn't read `RUMDeviceType` from `device.model`: \(device.model)") + return .other + } + }() + ) + } +} + +private extension RUMDevice.RUMDeviceType { + init?(from deviceModel: String) { + let lowercasedModel = deviceModel.lowercased() + + if lowercasedModel.hasPrefix("iphone") || lowercasedModel.hasPrefix("ipod") { + self = .mobile + } else if lowercasedModel.hasPrefix("ipad") { + self = .tablet + } else if lowercasedModel.hasPrefix("appletv") { + self = .tv + } else { + return nil + } + } +} diff --git a/Sources/Datadog/RUM/RUMEvent/RUMOperatingSystemInfo.swift b/Sources/Datadog/RUM/RUMEvent/RUMOperatingSystemInfo.swift new file mode 100644 index 0000000000..37b2615e9a --- /dev/null +++ b/Sources/Datadog/RUM/RUMEvent/RUMOperatingSystemInfo.swift @@ -0,0 +1,15 @@ +/* + * Unless explicitly stated otherwise all files in this repository are licensed under the Apache License Version 2.0. + * This product includes software developed at Datadog (https://www.datadoghq.com/). + * Copyright 2019-2020 Datadog, Inc. + */ + +import Foundation + +extension RUMOperatingSystem { + init(from device: MobileDevice) { + self.name = device.osName + self.version = device.osVersion + self.versionMajor = device.osVersion.split(separator: ".").first.map { String($0) } ?? device.osVersion + } +} diff --git a/Tests/DatadogTests/Datadog/Core/System/MobileDeviceTests.swift b/Tests/DatadogTests/Datadog/Core/System/MobileDeviceTests.swift index dd116bb020..29c80e7d55 100644 --- a/Tests/DatadogTests/Datadog/Core/System/MobileDeviceTests.swift +++ b/Tests/DatadogTests/Datadog/Core/System/MobileDeviceTests.swift @@ -29,6 +29,7 @@ class MobileDeviceTests: XCTestCase { notificationCenter: notificationCenter ) + XCTAssertEqual(mobileDevice.brand, "Apple") XCTAssertEqual(mobileDevice.name, randomUIDeviceModel) XCTAssertEqual(mobileDevice.model, randomModel) XCTAssertEqual(mobileDevice.osName, randomOSName) diff --git a/Tests/DatadogTests/Datadog/Core/Upload/RequestBuilderTests.swift b/Tests/DatadogTests/Datadog/Core/Upload/RequestBuilderTests.swift index 59d5929f76..feeba8a7c6 100644 --- a/Tests/DatadogTests/Datadog/Core/Upload/RequestBuilderTests.swift +++ b/Tests/DatadogTests/Datadog/Core/Upload/RequestBuilderTests.swift @@ -53,7 +53,7 @@ class RequestBuilderTests: XCTestCase { appName: "FoobarApp", appVersion: "1.2.3", device: .mockWith( - model: "iPhone", + name: "iPhone", osName: "iOS", osVersion: "13.3.1" ) @@ -73,7 +73,7 @@ class RequestBuilderTests: XCTestCase { appName: "Foobar 電話 𝛼β", appVersion: "1.2.3", device: .mockWith( - model: "iPhone", + name: "iPhone", osName: "iOS", osVersion: "13.3.1" ) diff --git a/Tests/DatadogTests/Datadog/Logging/LoggingFeatureTests.swift b/Tests/DatadogTests/Datadog/Logging/LoggingFeatureTests.swift index d209ecba7b..3e22a452e6 100644 --- a/Tests/DatadogTests/Datadog/Logging/LoggingFeatureTests.swift +++ b/Tests/DatadogTests/Datadog/Logging/LoggingFeatureTests.swift @@ -32,7 +32,7 @@ class LoggingFeatureTests: XCTestCase { let randomSDKVersion: String = .mockRandom(among: .alphanumerics) let randomUploadURL: URL = .mockRandom() let randomClientToken: String = .mockRandom() - let randomDeviceModel: String = .mockRandom() + let randomDeviceName: String = .mockRandom() let randomDeviceOSName: String = .mockRandom() let randomDeviceOSVersion: String = .mockRandom() let randomEncryption: DataEncryption? = Bool.random() ? DataEncryptionMock() : nil @@ -55,7 +55,11 @@ class LoggingFeatureTests: XCTestCase { clientToken: randomClientToken ), dependencies: .mockWith( - mobileDevice: .mockWith(model: randomDeviceModel, osName: randomDeviceOSName, osVersion: randomDeviceOSVersion) + mobileDevice: .mockWith( + name: randomDeviceName, + osName: randomDeviceOSName, + osVersion: randomDeviceOSVersion + ) ) ) defer { LoggingFeature.instance?.deinitialize() } @@ -73,7 +77,7 @@ class LoggingFeatureTests: XCTestCase { XCTAssertEqual( request.allHTTPHeaderFields?["User-Agent"], """ - \(randomApplicationName)/\(randomApplicationVersion) CFNetwork (\(randomDeviceModel); \(randomDeviceOSName)/\(randomDeviceOSVersion)) + \(randomApplicationName)/\(randomApplicationVersion) CFNetwork (\(randomDeviceName); \(randomDeviceOSName)/\(randomDeviceOSVersion)) """ ) XCTAssertEqual(request.allHTTPHeaderFields?["Content-Type"], "application/json") diff --git a/Tests/DatadogTests/Datadog/RUM/RUMEvent/RUMDeviceInfoTests.swift b/Tests/DatadogTests/Datadog/RUM/RUMEvent/RUMDeviceInfoTests.swift new file mode 100644 index 0000000000..1a317b8e8e --- /dev/null +++ b/Tests/DatadogTests/Datadog/RUM/RUMEvent/RUMDeviceInfoTests.swift @@ -0,0 +1,53 @@ +/* + * Unless explicitly stated otherwise all files in this repository are licensed under the Apache License Version 2.0. + * This product includes software developed at Datadog (https://www.datadoghq.com/). + * Copyright 2019-2020 Datadog, Inc. + */ + +import XCTest +@testable import Datadog + +class RUMDeviceInfoTests: XCTestCase { + func testItSetsBrandAndModelAndName() { + let randomModel: String = .mockRandom() + let randomName: String = .mockRandom() + + let info = RUMDevice( + from: .mockWith(name: randomName, model: randomModel), + telemetry: nil + ) + + XCTAssertEqual(info.brand, "Apple") + XCTAssertEqual(info.name, randomName) + XCTAssertEqual(info.model, randomModel) + } + + func testItInfersDeviceTypeFromDeviceModel() { + let iPhone = RUMDevice( + from: .mockWith(model: "iPhone" + String.mockRandom(among: .alphanumerics, length: 2)), + telemetry: nil + ) + let iPod = RUMDevice( + from: .mockWith(model: "iPod" + String.mockRandom(among: .alphanumerics, length: 2)), + telemetry: nil + ) + let iPad = RUMDevice( + from: .mockWith(model: "iPad" + String.mockRandom(among: .alphanumerics, length: 2)), + telemetry: nil + ) + let appleTV = RUMDevice( + from: .mockWith(model: "AppleTV" + String.mockRandom(among: .alphanumerics, length: 2)), + telemetry: nil + ) + let unknownDevice = RUMDevice( + from: .mockWith(model: .mockRandom()), + telemetry: nil + ) + + XCTAssertEqual(iPhone.type, .mobile) + XCTAssertEqual(iPod.type, .mobile) + XCTAssertEqual(iPad.type, .tablet) + XCTAssertEqual(appleTV.type, .tv) + XCTAssertEqual(unknownDevice.type, .other) + } +} diff --git a/Tests/DatadogTests/Datadog/RUM/RUMEvent/RUMOperatingSystemInfoTests.swift b/Tests/DatadogTests/Datadog/RUM/RUMEvent/RUMOperatingSystemInfoTests.swift new file mode 100644 index 0000000000..e702f07d5e --- /dev/null +++ b/Tests/DatadogTests/Datadog/RUM/RUMEvent/RUMOperatingSystemInfoTests.swift @@ -0,0 +1,39 @@ +/* + * Unless explicitly stated otherwise all files in this repository are licensed under the Apache License Version 2.0. + * This product includes software developed at Datadog (https://www.datadoghq.com/). + * Copyright 2019-2020 Datadog, Inc. + */ + +import XCTest +@testable import Datadog + +class RUMOperatingSystemInfoTests: XCTestCase { + func testItSetsOSNameAndVersion() { + let randomOSName: String = .mockRandom() + let randomOSVersion: String = .mockRandom() + + let info = RUMOperatingSystem( + from: .mockWith(osName: randomOSName, osVersion: randomOSVersion) + ) + + XCTAssertEqual(info.name, randomOSName) + XCTAssertEqual(info.version, randomOSVersion) + } + + func testItInfersOSMajorVersion() { + var info = RUMOperatingSystem(from: .mockWith(osVersion: "15.4.1")) + XCTAssertEqual(info.versionMajor, "15") + + info = RUMOperatingSystem(from: .mockWith(osVersion: "1.4")) + XCTAssertEqual(info.versionMajor, "1") + + info = RUMOperatingSystem(from: .mockWith(osVersion: "1")) + XCTAssertEqual(info.versionMajor, "1") + + info = RUMOperatingSystem(from: .mockWith(osVersion: "0.1.2-beta1")) + XCTAssertEqual(info.versionMajor, "0") + + info = RUMOperatingSystem(from: .mockWith(osVersion: "invalid_version")) + XCTAssertEqual(info.versionMajor, "invalid_version") + } +} diff --git a/Tests/DatadogTests/Datadog/RUM/RUMFeatureTests.swift b/Tests/DatadogTests/Datadog/RUM/RUMFeatureTests.swift index 2afe37bb99..6ac25c55da 100644 --- a/Tests/DatadogTests/Datadog/RUM/RUMFeatureTests.swift +++ b/Tests/DatadogTests/Datadog/RUM/RUMFeatureTests.swift @@ -34,7 +34,7 @@ class RUMFeatureTests: XCTestCase { let randomSDKVersion: String = .mockRandom(among: .alphanumerics) let randomUploadURL: URL = .mockRandom() let randomClientToken: String = .mockRandom() - let randomDeviceModel: String = .mockRandom() + let randomDeviceName: String = .mockRandom() let randomDeviceOSName: String = .mockRandom() let randomDeviceOSVersion: String = .mockRandom() let randomEncryption: DataEncryption? = Bool.random() ? DataEncryptionMock() : nil @@ -59,7 +59,11 @@ class RUMFeatureTests: XCTestCase { clientToken: randomClientToken ), dependencies: .mockWith( - mobileDevice: .mockWith(model: randomDeviceModel, osName: randomDeviceOSName, osVersion: randomDeviceOSVersion) + mobileDevice: .mockWith( + name: randomDeviceName, + osName: randomDeviceOSName, + osVersion: randomDeviceOSVersion + ) ) ) defer { RUMFeature.instance?.deinitialize() } @@ -82,7 +86,7 @@ class RUMFeatureTests: XCTestCase { XCTAssertEqual( request.allHTTPHeaderFields?["User-Agent"], """ - \(randomApplicationName)/\(randomApplicationVersion) CFNetwork (\(randomDeviceModel); \(randomDeviceOSName)/\(randomDeviceOSVersion)) + \(randomApplicationName)/\(randomApplicationVersion) CFNetwork (\(randomDeviceName); \(randomDeviceOSName)/\(randomDeviceOSVersion)) """ ) XCTAssertEqual(request.allHTTPHeaderFields?["Content-Type"], "text/plain;charset=UTF-8") diff --git a/Tests/DatadogTests/Datadog/Tracing/TracingFeatureTests.swift b/Tests/DatadogTests/Datadog/Tracing/TracingFeatureTests.swift index e7a870a995..19dcf81284 100644 --- a/Tests/DatadogTests/Datadog/Tracing/TracingFeatureTests.swift +++ b/Tests/DatadogTests/Datadog/Tracing/TracingFeatureTests.swift @@ -32,7 +32,7 @@ class TracingFeatureTests: XCTestCase { let randomSDKVersion: String = .mockRandom(among: .alphanumerics) let randomUploadURL: URL = .mockRandom() let randomClientToken: String = .mockRandom() - let randomDeviceModel: String = .mockRandom() + let randomDeviceName: String = .mockRandom() let randomDeviceOSName: String = .mockRandom() let randomDeviceOSVersion: String = .mockRandom() let randomEncryption: DataEncryption? = Bool.random() ? DataEncryptionMock() : nil @@ -55,7 +55,11 @@ class TracingFeatureTests: XCTestCase { clientToken: randomClientToken ), dependencies: .mockWith( - mobileDevice: .mockWith(model: randomDeviceModel, osName: randomDeviceOSName, osVersion: randomDeviceOSVersion) + mobileDevice: .mockWith( + name: randomDeviceName, + osName: randomDeviceOSName, + osVersion: randomDeviceOSVersion + ) ) ) defer { TracingFeature.instance?.deinitialize() } @@ -74,7 +78,7 @@ class TracingFeatureTests: XCTestCase { XCTAssertEqual( request.allHTTPHeaderFields?["User-Agent"], """ - \(randomApplicationName)/\(randomApplicationVersion) CFNetwork (\(randomDeviceModel); \(randomDeviceOSName)/\(randomDeviceOSVersion)) + \(randomApplicationName)/\(randomApplicationVersion) CFNetwork (\(randomDeviceName); \(randomDeviceOSName)/\(randomDeviceOSVersion)) """ ) XCTAssertEqual(request.allHTTPHeaderFields?["Content-Type"], "text/plain;charset=UTF-8") From 70acb679bee38da4e1a56342f105838147d2e987 Mon Sep 17 00:00:00 2001 From: Maciek Grzybowski Date: Mon, 13 Jun 2022 12:39:46 +0200 Subject: [PATCH 3/8] RUMM-2197 Validate `os` and `device` info in tests --- .../CrashReportingWithRUMIntegration.swift | 20 ++-- Sources/Datadog/RUM/RUMFeature.swift | 2 + .../RUMMonitor/Scopes/RUMResourceScope.swift | 8 +- .../Scopes/RUMScopeDependencies.swift | 7 ++ .../Scopes/RUMUserActionScope.swift | 4 +- .../RUM/RUMMonitor/Scopes/RUMViewScope.swift | 16 ++-- ...rashReportingWithRUMIntegrationTests.swift | 14 +++ .../Datadog/Mocks/RUMFeatureMocks.swift | 8 ++ .../Matchers/RUMSessionMatcher.swift | 94 +++++++++++++++++++ 9 files changed, 153 insertions(+), 20 deletions(-) diff --git a/Sources/Datadog/FeaturesIntegration/CrashReporting/CrashReportingWithRUMIntegration.swift b/Sources/Datadog/FeaturesIntegration/CrashReporting/CrashReportingWithRUMIntegration.swift index 059f67af76..1db89de36a 100644 --- a/Sources/Datadog/FeaturesIntegration/CrashReporting/CrashReportingWithRUMIntegration.swift +++ b/Sources/Datadog/FeaturesIntegration/CrashReporting/CrashReportingWithRUMIntegration.swift @@ -32,6 +32,7 @@ internal struct CrashReportingWithRUMIntegration: CrashReportingIntegration { private let rumEventOutput: RUMEventOutput private let dateProvider: DateProvider private let dateCorrector: DateCorrectorType + private let deviceInfoProvider: MobileDevice private let rumConfiguration: FeaturesConfiguration.RUM // MARK: - Initialization @@ -43,6 +44,7 @@ internal struct CrashReportingWithRUMIntegration: CrashReportingIntegration { ), dateProvider: rumFeature.dateProvider, dateCorrector: rumFeature.dateCorrector, + deviceInfoProvider: rumFeature.deviceInfoProvider, rumConfiguration: rumFeature.configuration ) } @@ -51,11 +53,13 @@ internal struct CrashReportingWithRUMIntegration: CrashReportingIntegration { rumEventOutput: RUMEventOutput, dateProvider: DateProvider, dateCorrector: DateCorrectorType, + deviceInfoProvider: MobileDevice, rumConfiguration: FeaturesConfiguration.RUM ) { self.rumEventOutput = rumEventOutput self.dateProvider = dateProvider self.dateCorrector = dateCorrector + self.deviceInfoProvider = deviceInfoProvider self.rumConfiguration = rumConfiguration } @@ -235,7 +239,7 @@ internal struct CrashReportingWithRUMIntegration: CrashReportingIntegration { connectivity: lastRUMView.connectivity, context: nil, date: crashDate.timeIntervalSince1970.toInt64Milliseconds, - device: nil, // TODO: RUMM-2197 add device and OS info + device: lastRUMView.device, error: .init( handling: nil, handlingStack: nil, @@ -248,7 +252,7 @@ internal struct CrashReportingWithRUMIntegration: CrashReportingIntegration { stack: errorStackTrace, type: errorType ), - os: nil, // TODO: RUMM-2197 add device and OS info + os: lastRUMView.os, service: lastRUMView.service, session: .init( hasReplay: lastRUMView.session.hasReplay, @@ -286,8 +290,8 @@ internal struct CrashReportingWithRUMIntegration: CrashReportingIntegration { connectivity: original.connectivity, context: original.context, date: crashDate.timeIntervalSince1970.toInt64Milliseconds - 1, // -1ms to put the crash after view in RUM session - device: nil, // TODO: RUMM-2197 add device and OS info - os: nil, // TODO: RUMM-2197 add device and OS info + device: original.device, + os: original.os, service: original.service, session: original.session, source: original.source ?? .ios, @@ -358,8 +362,12 @@ internal struct CrashReportingWithRUMIntegration: CrashReportingIntegration { ), context: nil, date: startDate.timeIntervalSince1970.toInt64Milliseconds, - device: nil, // TODO: RUMM-2197 add device and OS info - os: nil, // TODO: RUMM-2197 add device and OS info + device: .init(from: deviceInfoProvider, telemetry: nil), + // RUMM-2197: In very rare cases, the OS info computed below might not be exactly the one + // that the app crashed on. This would correspond to a scenario when the device OS was upgraded + // before restarting the app after crash. To solve this, the OS information would have to be + // persisted in `crashContext` the same way as we do for other dynamic information. + os: .init(from: deviceInfoProvider), service: rumConfiguration.common.serviceName, session: .init( hasReplay: nil, diff --git a/Sources/Datadog/RUM/RUMFeature.swift b/Sources/Datadog/RUM/RUMFeature.swift index b283d61bc9..5ac8c1284e 100644 --- a/Sources/Datadog/RUM/RUMFeature.swift +++ b/Sources/Datadog/RUM/RUMFeature.swift @@ -34,6 +34,7 @@ internal final class RUMFeature { let dateProvider: DateProvider let dateCorrector: DateCorrectorType let appStateListener: AppStateListening + let deviceInfoProvider: MobileDevice let userInfoProvider: UserInfoProvider let networkConnectionInfoProvider: NetworkConnectionInfoProviderType let carrierInfoProvider: CarrierInfoProviderType @@ -165,6 +166,7 @@ internal final class RUMFeature { self.dateProvider = commonDependencies.dateProvider self.dateCorrector = commonDependencies.dateCorrector self.appStateListener = commonDependencies.appStateListener + self.deviceInfoProvider = commonDependencies.mobileDevice self.userInfoProvider = commonDependencies.userInfoProvider self.networkConnectionInfoProvider = commonDependencies.networkConnectionInfoProvider self.carrierInfoProvider = commonDependencies.carrierInfoProvider diff --git a/Sources/Datadog/RUM/RUMMonitor/Scopes/RUMResourceScope.swift b/Sources/Datadog/RUM/RUMMonitor/Scopes/RUMResourceScope.swift index f498e10f70..0b1097ff5f 100644 --- a/Sources/Datadog/RUM/RUMMonitor/Scopes/RUMResourceScope.swift +++ b/Sources/Datadog/RUM/RUMMonitor/Scopes/RUMResourceScope.swift @@ -142,8 +142,8 @@ internal class RUMResourceScope: RUMScope { connectivity: dependencies.connectivityInfoProvider.current, context: .init(contextInfo: attributes), date: dateCorrection.applying(to: resourceStartTime).timeIntervalSince1970.toInt64Milliseconds, - device: nil, // TODO: RUMM-2197 add device and OS info - os: nil, // TODO: RUMM-2197 add device and OS info + device: dependencies.deviceInfo, + os: dependencies.osInfo, resource: .init( connect: resourceMetrics?.connect.flatMap { metric in .init( @@ -231,7 +231,7 @@ internal class RUMResourceScope: RUMScope { connectivity: dependencies.connectivityInfoProvider.current, context: .init(contextInfo: attributes), date: dateCorrection.applying(to: command.time).timeIntervalSince1970.toInt64Milliseconds, - device: nil, + device: dependencies.deviceInfo, error: .init( handling: nil, handlingStack: nil, @@ -249,7 +249,7 @@ internal class RUMResourceScope: RUMScope { stack: command.stack, type: command.errorType ), - os: nil, // TODO: RUMM-2197 add device and OS info + os: dependencies.osInfo, service: dependencies.serviceName, session: .init( hasReplay: nil, diff --git a/Sources/Datadog/RUM/RUMMonitor/Scopes/RUMScopeDependencies.swift b/Sources/Datadog/RUM/RUMMonitor/Scopes/RUMScopeDependencies.swift index e9608d8e2b..37ac9e8bb5 100644 --- a/Sources/Datadog/RUM/RUMMonitor/Scopes/RUMScopeDependencies.swift +++ b/Sources/Datadog/RUM/RUMMonitor/Scopes/RUMScopeDependencies.swift @@ -23,6 +23,8 @@ internal struct RUMScopeDependencies { let sdkInitDate: Date let backgroundEventTrackingEnabled: Bool let appStateListener: AppStateListening + let deviceInfo: RUMDevice + let osInfo: RUMOperatingSystem let userInfoProvider: RUMUserInfoProvider let launchTimeProvider: LaunchTimeProviderType let connectivityInfoProvider: RUMConnectivityInfoProvider @@ -56,6 +58,11 @@ internal extension RUMScopeDependencies { sdkInitDate: rumFeature.sdkInitDate, backgroundEventTrackingEnabled: rumFeature.configuration.backgroundEventTrackingEnabled, appStateListener: rumFeature.appStateListener, + deviceInfo: RUMDevice( + from: rumFeature.deviceInfoProvider, + telemetry: rumFeature.telemetry + ), + osInfo: RUMOperatingSystem(from: rumFeature.deviceInfoProvider), userInfoProvider: RUMUserInfoProvider(userInfoProvider: rumFeature.userInfoProvider), launchTimeProvider: rumFeature.launchTimeProvider, connectivityInfoProvider: RUMConnectivityInfoProvider( diff --git a/Sources/Datadog/RUM/RUMMonitor/Scopes/RUMUserActionScope.swift b/Sources/Datadog/RUM/RUMMonitor/Scopes/RUMUserActionScope.swift index fdc5f45c87..d6b0e4887a 100644 --- a/Sources/Datadog/RUM/RUMMonitor/Scopes/RUMUserActionScope.swift +++ b/Sources/Datadog/RUM/RUMMonitor/Scopes/RUMUserActionScope.swift @@ -159,8 +159,8 @@ internal class RUMUserActionScope: RUMScope, RUMContextProvider { connectivity: dependencies.connectivityInfoProvider.current, context: .init(contextInfo: attributes), date: dateCorrection.applying(to: actionStartTime).timeIntervalSince1970.toInt64Milliseconds, - device: nil, // TODO: RUMM-2197 add device and OS info - os: nil, // TODO: RUMM-2197 add device and OS info + device: dependencies.deviceInfo, + os: dependencies.osInfo, service: dependencies.serviceName, session: .init( hasReplay: nil, diff --git a/Sources/Datadog/RUM/RUMMonitor/Scopes/RUMViewScope.swift b/Sources/Datadog/RUM/RUMMonitor/Scopes/RUMViewScope.swift index f1a07c3d72..455cbff5bb 100644 --- a/Sources/Datadog/RUM/RUMMonitor/Scopes/RUMViewScope.swift +++ b/Sources/Datadog/RUM/RUMMonitor/Scopes/RUMViewScope.swift @@ -344,8 +344,8 @@ internal class RUMViewScope: RUMScope, RUMContextProvider { connectivity: dependencies.connectivityInfoProvider.current, context: .init(contextInfo: attributes), date: dateCorrection.applying(to: viewStartTime).timeIntervalSince1970.toInt64Milliseconds, - device: nil, // TODO: RUMM-2197 add device and OS info - os: nil, // TODO: RUMM-2197 add device and OS info + device: dependencies.deviceInfo, + os: dependencies.osInfo, service: dependencies.serviceName, session: .init( hasReplay: nil, @@ -396,8 +396,8 @@ internal class RUMViewScope: RUMScope, RUMContextProvider { connectivity: dependencies.connectivityInfoProvider.current, context: .init(contextInfo: attributes), date: dateCorrection.applying(to: viewStartTime).timeIntervalSince1970.toInt64Milliseconds, - device: nil, // TODO: RUMM-2197 add device and OS info - os: nil, // TODO: RUMM-2197 add device and OS info + device: dependencies.deviceInfo, + os: dependencies.osInfo, service: dependencies.serviceName, session: .init( hasReplay: nil, @@ -478,7 +478,7 @@ internal class RUMViewScope: RUMScope, RUMContextProvider { connectivity: dependencies.connectivityInfoProvider.current, context: .init(contextInfo: attributes), date: dateCorrection.applying(to: command.time).timeIntervalSince1970.toInt64Milliseconds, - device: nil, // TODO: RUMM-2197 add device and OS info + device: dependencies.deviceInfo, error: .init( handling: nil, handlingStack: nil, @@ -491,7 +491,7 @@ internal class RUMViewScope: RUMScope, RUMContextProvider { stack: command.stack, type: command.type ), - os: nil, // TODO: RUMM-2197 add device and OS info + os: dependencies.osInfo, service: dependencies.serviceName, session: .init( hasReplay: nil, @@ -534,9 +534,9 @@ internal class RUMViewScope: RUMScope, RUMContextProvider { connectivity: dependencies.connectivityInfoProvider.current, context: .init(contextInfo: attributes), date: dateCorrection.applying(to: command.time - command.duration).timeIntervalSince1970.toInt64Milliseconds, - device: nil, // TODO: RUMM-2197 add device and OS info + device: dependencies.deviceInfo, longTask: .init(duration: taskDurationInNs, id: nil, isFrozenFrame: isFrozenFrame), - os: nil, // TODO: RUMM-2197 add device and OS info + os: dependencies.osInfo, service: dependencies.serviceName, session: .init( hasReplay: nil, diff --git a/Tests/DatadogTests/Datadog/FeaturesIntegration/CrashReporting/CrashReportingWithRUMIntegrationTests.swift b/Tests/DatadogTests/Datadog/FeaturesIntegration/CrashReporting/CrashReportingWithRUMIntegrationTests.swift index a6d67978da..8ce9902c23 100644 --- a/Tests/DatadogTests/Datadog/FeaturesIntegration/CrashReporting/CrashReportingWithRUMIntegrationTests.swift +++ b/Tests/DatadogTests/Datadog/FeaturesIntegration/CrashReporting/CrashReportingWithRUMIntegrationTests.swift @@ -30,6 +30,7 @@ class CrashReportingWithRUMIntegrationTests: XCTestCase { rumEventOutput: rumEventOutput, dateProvider: RelativeDateProvider(using: currentDate), dateCorrector: DateCorrectorMock(correctionOffset: 0), + deviceInfoProvider: .mockAny(), rumConfiguration: .mockWith( sessionSampler: Bool.random() ? .mockKeepAll() : .mockRejectAll(), // no matter sampling (as previous session was sampled) backgroundEventTrackingEnabled: .mockRandom() // no matter BET @@ -63,6 +64,7 @@ class CrashReportingWithRUMIntegrationTests: XCTestCase { rumEventOutput: rumEventOutput, dateProvider: RelativeDateProvider(using: currentDate), dateCorrector: DateCorrectorMock(correctionOffset: 0), + deviceInfoProvider: .mockAny(), rumConfiguration: .mockWith( sessionSampler: Bool.random() ? .mockKeepAll() : .mockRejectAll(), // no matter sampling (as previous session was sampled) backgroundEventTrackingEnabled: .mockRandom() // no matter BET @@ -94,6 +96,7 @@ class CrashReportingWithRUMIntegrationTests: XCTestCase { rumEventOutput: rumEventOutput, dateProvider: RelativeDateProvider(using: currentDate), dateCorrector: DateCorrectorMock(correctionOffset: 0), + deviceInfoProvider: .mockAny(), rumConfiguration: .mockWith( sessionSampler: Bool.random() ? .mockKeepAll() : .mockRejectAll(), // no matter sampling (as previous session was sampled) backgroundEventTrackingEnabled: true // BET enabled @@ -126,6 +129,7 @@ class CrashReportingWithRUMIntegrationTests: XCTestCase { rumEventOutput: rumEventOutput, dateProvider: RelativeDateProvider(using: currentDate), dateCorrector: DateCorrectorMock(correctionOffset: 0), + deviceInfoProvider: .mockAny(), rumConfiguration: .mockWith( sessionSampler: .mockKeepAll(), backgroundEventTrackingEnabled: true @@ -153,6 +157,7 @@ class CrashReportingWithRUMIntegrationTests: XCTestCase { rumEventOutput: rumEventOutput, dateProvider: RelativeDateProvider(using: .mockDecember15th2019At10AMUTC()), dateCorrector: DateCorrectorMock(), + deviceInfoProvider: .mockAny(), rumConfiguration: .mockWith( sessionSampler: Bool.random() ? .mockKeepAll() : .mockRejectAll(), // no matter sampling backgroundEventTrackingEnabled: .mockRandom() // no matter BET @@ -183,6 +188,7 @@ class CrashReportingWithRUMIntegrationTests: XCTestCase { rumEventOutput: rumEventOutput, dateProvider: RelativeDateProvider(using: currentDate), dateCorrector: DateCorrectorMock(correctionOffset: 0), + deviceInfoProvider: .mockAny(), rumConfiguration: .mockWith( sessionSampler: .mockRejectAll(), // no sampling (no session should be sent) backgroundEventTrackingEnabled: true @@ -212,6 +218,7 @@ class CrashReportingWithRUMIntegrationTests: XCTestCase { rumEventOutput: rumEventOutput, dateProvider: RelativeDateProvider(using: crashDate), dateCorrector: DateCorrectorMock(correctionOffset: dateCorrectionOffset), + deviceInfoProvider: .mockAny(), rumConfiguration: .mockWith( sessionSampler: .mockKeepAll(), backgroundEventTrackingEnabled: false // BET disabled @@ -246,6 +253,7 @@ class CrashReportingWithRUMIntegrationTests: XCTestCase { rumEventOutput: rumEventOutput, dateProvider: RelativeDateProvider(using: currentDate), dateCorrector: DateCorrectorMock(correctionOffset: 0), + deviceInfoProvider: .mockAny(), rumConfiguration: .mockWith( sessionSampler: .mockRandom(), // no matter current session sampling backgroundEventTrackingEnabled: .mockRandom() @@ -278,6 +286,7 @@ class CrashReportingWithRUMIntegrationTests: XCTestCase { rumEventOutput: rumEventOutput, dateProvider: RelativeDateProvider(using: crashDate), dateCorrector: DateCorrectorMock(correctionOffset: dateCorrectionOffset), + deviceInfoProvider: .mockAny(), rumConfiguration: .mockWith( sessionSampler: Bool.random() ? .mockKeepAll() : .mockRejectAll(), // no matter sampling (as previous session was sampled) backgroundEventTrackingEnabled: .mockRandom() // no matter BET @@ -318,6 +327,8 @@ class CrashReportingWithRUMIntegrationTests: XCTestCase { "The `RUMViewEvent` sent must include crash date corrected by current correction offset and shifted back by 1ms." ) XCTAssertEqual(sendRUMViewEvent.dd.session?.plan, .plan1, "All RUM events should use RUM Lite plan") + XCTAssertEqual(sendRUMViewEvent.device, lastRUMViewEvent.device) + XCTAssertEqual(sendRUMViewEvent.os, lastRUMViewEvent.os) } func testGivenCrashDuringRUMSessionWithActiveView_whenSendingRUMErrorEvent_itIsLinkedToPreviousRUMSessionAndIncludesCrashInformation() throws { @@ -370,6 +381,7 @@ class CrashReportingWithRUMIntegrationTests: XCTestCase { ) ), dateCorrector: DateCorrectorMock(correctionOffset: dateCorrectionOffset), + deviceInfoProvider: .mockAny(), rumConfiguration: .mockWith( sessionSampler: Bool.random() ? .mockKeepAll() : .mockRejectAll(), // no matter sampling (as previous session was sampled) backgroundEventTrackingEnabled: .mockRandom() // no matter BET @@ -457,6 +469,7 @@ class CrashReportingWithRUMIntegrationTests: XCTestCase { rumEventOutput: rumEventOutput, dateProvider: RelativeDateProvider(using: crashDate), dateCorrector: DateCorrectorMock(correctionOffset: dateCorrectionOffset), + deviceInfoProvider: .mockAny(), rumConfiguration: .mockWith( common: .mockWith( source: randomSource @@ -591,6 +604,7 @@ class CrashReportingWithRUMIntegrationTests: XCTestCase { rumEventOutput: rumEventOutput, dateProvider: RelativeDateProvider(using: crashDate), dateCorrector: DateCorrectorMock(correctionOffset: dateCorrectionOffset), + deviceInfoProvider: .mockAny(), rumConfiguration: .mockWith( applicationID: randomRUMAppID, sessionSampler: .mockKeepAll(), diff --git a/Tests/DatadogTests/Datadog/Mocks/RUMFeatureMocks.swift b/Tests/DatadogTests/Datadog/Mocks/RUMFeatureMocks.swift index edb963e5e3..207fa97fd1 100644 --- a/Tests/DatadogTests/Datadog/Mocks/RUMFeatureMocks.swift +++ b/Tests/DatadogTests/Datadog/Mocks/RUMFeatureMocks.swift @@ -649,6 +649,8 @@ extension RUMScopeDependencies { sdkInitDate: Date = .mockAny(), backgroundEventTrackingEnabled: Bool = .mockAny(), appStateListener: AppStateListening = AppStateListenerMock.mockAny(), + deviceInfo: RUMDevice = .mockRandom(), + osInfo: RUMOperatingSystem = .mockRandom(), userInfoProvider: RUMUserInfoProvider = RUMUserInfoProvider(userInfoProvider: .mockAny()), launchTimeProvider: LaunchTimeProviderType = LaunchTimeProviderMock.mockAny(), connectivityInfoProvider: RUMConnectivityInfoProvider = RUMConnectivityInfoProvider( @@ -676,6 +678,8 @@ extension RUMScopeDependencies { sdkInitDate: sdkInitDate, backgroundEventTrackingEnabled: backgroundEventTrackingEnabled, appStateListener: appStateListener, + deviceInfo: deviceInfo, + osInfo: osInfo, userInfoProvider: userInfoProvider, launchTimeProvider: launchTimeProvider, connectivityInfoProvider: connectivityInfoProvider, @@ -703,6 +707,8 @@ extension RUMScopeDependencies { sdkInitDate: Date? = nil, backgroundEventTrackingEnabled: Bool? = nil, appStateListener: AppStateListening? = nil, + deviceInfo: RUMDevice? = nil, + osInfo: RUMOperatingSystem? = nil, userInfoProvider: RUMUserInfoProvider? = nil, launchTimeProvider: LaunchTimeProviderType? = nil, connectivityInfoProvider: RUMConnectivityInfoProvider? = nil, @@ -727,6 +733,8 @@ extension RUMScopeDependencies { sdkInitDate: sdkInitDate ?? self.sdkInitDate, backgroundEventTrackingEnabled: backgroundEventTrackingEnabled ?? self.backgroundEventTrackingEnabled, appStateListener: appStateListener ?? self.appStateListener, + deviceInfo: deviceInfo ?? self.deviceInfo, + osInfo: osInfo ?? self.osInfo, userInfoProvider: userInfoProvider ?? self.userInfoProvider, launchTimeProvider: launchTimeProvider ?? self.launchTimeProvider, connectivityInfoProvider: connectivityInfoProvider ?? self.connectivityInfoProvider, diff --git a/Tests/DatadogTests/Matchers/RUMSessionMatcher.swift b/Tests/DatadogTests/Matchers/RUMSessionMatcher.swift index e269859845..63dce3dadd 100644 --- a/Tests/DatadogTests/Matchers/RUMSessionMatcher.swift +++ b/Tests/DatadogTests/Matchers/RUMSessionMatcher.swift @@ -249,6 +249,8 @@ private func validate(rumViewEvents: [RUMViewEvent]) throws { description: "All RUM events must use session plan `1` (RUM Lite). Bad view event: \(viewEvent)" ) } + try validate(device: viewEvent.device) + try validate(os: viewEvent.os) } } @@ -260,6 +262,8 @@ private func validate(rumActionEvents: [RUMActionEvent]) throws { description: "All RUM events must use session plan `1` (RUM Lite). Bad action event: \(actionEvent)" ) } + try validate(device: actionEvent.device) + try validate(os: actionEvent.os) } } @@ -279,6 +283,8 @@ private func validate(rumResourceEvents: [RUMResourceEvent]) throws { description: "All RUM events must use session plan `1` (RUM Lite). Bad resource event: \(resourceEvent)" ) } + try validate(device: resourceEvent.device) + try validate(os: resourceEvent.os) } } @@ -290,6 +296,8 @@ private func validate(rumErrorEvents: [RUMErrorEvent]) throws { description: "All RUM events must use session plan `1` (RUM Lite). Bad error event: \(errorEvent)" ) } + try validate(device: errorEvent.device) + try validate(os: errorEvent.os) } } @@ -301,9 +309,95 @@ private func validate(rumLongTaskEvents: [RUMLongTaskEvent]) throws { description: "All RUM events must use session plan `1` (RUM Lite). Bad long task event: \(longTaskEvent)" ) } + try validate(device: longTaskEvent.device) + try validate(os: longTaskEvent.os) } } +private func validate(device: RUMDevice?) throws { + guard let device = device else { + throw RUMSessionConsistencyException( + description: "All RUM events must include device information" + ) + } + #if DD_COMPILED_FOR_INTEGRATION_TESTS + strictValidate(device: device) + #endif +} + +private func validate(os: RUMOperatingSystem?) throws { + guard let os = os else { + throw RUMSessionConsistencyException( + description: "All RUM events must include OS information" + ) + } + #if DD_COMPILED_FOR_INTEGRATION_TESTS + strictValidate(os: os) + #endif +} + +// MARK: - Strict Validation (in Integration Tests) + +/// Performs strict validation of `RUMDevice` for integration tests. +/// It asserts that all values make sense for current environment. +private func strictValidate(device: RUMDevice) throws { + guard device.brand == "Apple" else { + throw RUMSessionConsistencyException(description: "All RUM events must use `device.brand = Apple` (got `\(device.brand ?? "nil")` instead)") + } + #if os(iOS) + guard device.type == .mobile || device.type == .tablet else { + throw RUMSessionConsistencyException( + description: "When running on iOS or iPadOS, the `device.type` must be `.mobile` or `.tablet` (got `\(device.type)` instead)" + ) + } + let prefixes = ["iPhone", "iPod", "iPad"] + guard prefixes.contains(where: { device.name?.hasPrefix($0) ?? false }) else { + throw RUMSessionConsistencyException( + description: "When running on iOS or iPadOS, the `device.name` must start with one of: \(prefixes) (got `\(device.name ?? "nil")` instead)" + ) + } + guard prefixes.contains(where: { device.model?.hasPrefix($0) ?? false }) else { + throw RUMSessionConsistencyException( + description: "When running on iOS or iPadOS, the `device.model` must start with one of: \(prefixes) (got `\(device.model ?? "nil")` instead)" + ) + } + #else + guard device.type != .tv else { + throw RUMSessionConsistencyException( + description: "When running on tvOS, the `device.type` must be `.tv` (got `\(device.type)` instead)" + ) + } + guard device.name == "Apple TV" else { + throw RUMSessionConsistencyException( + description: "When running on tvOS, the `device.name` must be `Apple TV` (got `\(device.name ?? "nil")` instead)" + ) + } + guard device.model?.hasPrefix("AppleTV") ?? false else { + throw RUMSessionConsistencyException( + description: "When running on tvOS, the `device.model` must start with `AppleTV` (got `\(device.model ?? "nil")` instead)" + ) + } + #endif +} + +/// Performs strict validation of `RUMOperatingSystem` for integration tests. +/// It asserts that all values make sense for current environment. +private func strictValidate(os: RUMOperatingSystem) throws { + #if os(iOS) + if os.name != "iOS" && os.name != "iPadOS" { + throw RUMSessionConsistencyException( + description: "When running on iOS or iPadOS the `os.name` must be either 'iOS' or 'iPadOS'" + ) + } + #else + if os.name != "tvOS" { + throw RUMSessionConsistencyException( + description: "When running on tvOS the `os.name` must be 'tvOS'" + ) + } + #endif +} + // MARK: - Debugging extension RUMSessionMatcher: CustomStringConvertible { From ffdcb0602c2384c266aa553498843f1849d4b524 Mon Sep 17 00:00:00 2001 From: Maciek Grzybowski Date: Mon, 13 Jun 2022 12:53:32 +0200 Subject: [PATCH 4/8] RUMM-2197 Add unit tests for including `device` and `os` info in RUM events --- .../Scopes/RUMResourceScopeTests.swift | 16 +++++++++++++ .../Scopes/RUMUserActionScopeTests.swift | 8 +++++++ .../RUMMonitor/Scopes/RUMViewScopeTests.swift | 24 +++++++++++++++++++ 3 files changed, 48 insertions(+) diff --git a/Tests/DatadogTests/Datadog/RUM/RUMMonitor/Scopes/RUMResourceScopeTests.swift b/Tests/DatadogTests/Datadog/RUM/RUMMonitor/Scopes/RUMResourceScopeTests.swift index d57e55574e..501c49c3ea 100644 --- a/Tests/DatadogTests/Datadog/RUM/RUMMonitor/Scopes/RUMResourceScopeTests.swift +++ b/Tests/DatadogTests/Datadog/RUM/RUMMonitor/Scopes/RUMResourceScopeTests.swift @@ -10,7 +10,11 @@ import XCTest class RUMResourceScopeTests: XCTestCase { private let output = RUMEventOutputMock() private let randomServiceName: String = .mockRandom() + private let randomDeviceInfo: RUMDevice = .mockRandom() + private let randomOSInfo: RUMOperatingSystem = .mockRandom() private lazy var dependencies: RUMScopeDependencies = .mockWith( + deviceInfo: randomDeviceInfo, + osInfo: randomOSInfo, serviceName: randomServiceName, firstPartyURLsFilter: FirstPartyURLsFilter(hosts: ["firstparty.com"]), eventOutput: output @@ -104,6 +108,8 @@ class RUMResourceScopeTests: XCTestCase { XCTAssertEqual(event.dd.spanId, "200") XCTAssertEqual(event.dd.session?.plan, .plan1, "All RUM events should use RUM Lite plan") XCTAssertEqual(event.service, randomServiceName) + XCTAssertEqual(event.device, randomDeviceInfo) + XCTAssertEqual(event.os, randomOSInfo) } func testGivenConfiguredSoruce_whenResourceLoadingEnds_itSendsResourceEventWithCorrecSource() throws { @@ -212,6 +218,8 @@ class RUMResourceScopeTests: XCTestCase { XCTAssertEqual(event.dd.spanId, "200") XCTAssertEqual(event.dd.session?.plan, .plan1, "All RUM events should use RUM Lite plan") XCTAssertEqual(event.service, randomServiceName) + XCTAssertEqual(event.device, randomDeviceInfo) + XCTAssertEqual(event.os, randomOSInfo) } func testGivenStartedResource_whenResourceLoadingEnds_itSendsResourceEventWithCustomSpanAndTraceId() throws { @@ -277,6 +285,8 @@ class RUMResourceScopeTests: XCTestCase { XCTAssertEqual(event.dd.spanId, "200") XCTAssertEqual(event.source, .ios) XCTAssertEqual(event.service, randomServiceName) + XCTAssertEqual(event.device, randomDeviceInfo) + XCTAssertEqual(event.os, randomOSInfo) } func testGivenStartedResource_whenResourceLoadingEndsWithError_itSendsErrorEvent() throws { @@ -333,6 +343,8 @@ class RUMResourceScopeTests: XCTestCase { XCTAssertEqual(event.dd.session?.plan, .plan1, "All RUM events should use RUM Lite plan") XCTAssertEqual(event.source, .ios) XCTAssertEqual(event.service, randomServiceName) + XCTAssertEqual(event.device, randomDeviceInfo) + XCTAssertEqual(event.os, randomOSInfo) } func testGivenConfiguredSource_whenResourceLoadingEndsWithError_itSendsErrorEventWithConfiguredSource() throws { @@ -373,6 +385,8 @@ class RUMResourceScopeTests: XCTestCase { let event = try XCTUnwrap(output.recordedEvents(ofType: RUMErrorEvent.self).first) XCTAssertEqual(event.source, RUMErrorEvent.Source(rawValue: customSource)) XCTAssertEqual(event.service, randomServiceName) + XCTAssertEqual(event.device, randomDeviceInfo) + XCTAssertEqual(event.os, randomOSInfo) } func testGivenStartedResource_whenResourceReceivesMetricsBeforeItEnds_itUsesMetricValuesInSentResourceEvent() throws { @@ -483,6 +497,8 @@ class RUMResourceScopeTests: XCTestCase { XCTAssertNil(event.dd.spanId) XCTAssertEqual(event.source, .ios) XCTAssertEqual(event.service, randomServiceName) + XCTAssertEqual(event.device, randomDeviceInfo) + XCTAssertEqual(event.os, randomOSInfo) } func testGivenMultipleResourceScopes_whenSendingResourceEvents_eachEventHasUniqueResourceID() throws { diff --git a/Tests/DatadogTests/Datadog/RUM/RUMMonitor/Scopes/RUMUserActionScopeTests.swift b/Tests/DatadogTests/Datadog/RUM/RUMMonitor/Scopes/RUMUserActionScopeTests.swift index 57f9d807e9..19f8c2dfdc 100644 --- a/Tests/DatadogTests/Datadog/RUM/RUMMonitor/Scopes/RUMUserActionScopeTests.swift +++ b/Tests/DatadogTests/Datadog/RUM/RUMMonitor/Scopes/RUMUserActionScopeTests.swift @@ -10,7 +10,11 @@ import XCTest class RUMUserActionScopeTests: XCTestCase { private let output = RUMEventOutputMock() private let randomServiceName: String = .mockRandom() + private let randomDeviceInfo: RUMDevice = .mockRandom() + private let randomOSInfo: RUMOperatingSystem = .mockRandom() private lazy var dependencies: RUMScopeDependencies = .mockWith( + deviceInfo: randomDeviceInfo, + osInfo: randomOSInfo, serviceName: randomServiceName, eventOutput: output ) @@ -64,6 +68,8 @@ class RUMUserActionScopeTests: XCTestCase { XCTAssertEqual(recordedAction.dd.session?.plan, .plan1, "All RUM events should use RUM Lite plan") XCTAssertEqual(recordedAction.source, .ios) XCTAssertEqual(recordedAction.service, randomServiceName) + XCTAssertEqual(recordedAction.device, randomDeviceInfo) + XCTAssertEqual(recordedAction.os, randomOSInfo) } func testGivenCustomSource_whenActionIsSent_itSendsCustomSource() throws { @@ -131,6 +137,8 @@ class RUMUserActionScopeTests: XCTestCase { XCTAssertEqual(event.context?.contextInfo as? [String: String], ["foo": "bar"]) XCTAssertEqual(event.source, .ios) XCTAssertEqual(event.service, randomServiceName) + XCTAssertEqual(event.device, randomDeviceInfo) + XCTAssertEqual(event.os, randomOSInfo) } func testWhenContinuousUserActionExpires_itSendsActionEvent() throws { diff --git a/Tests/DatadogTests/Datadog/RUM/RUMMonitor/Scopes/RUMViewScopeTests.swift b/Tests/DatadogTests/Datadog/RUM/RUMMonitor/Scopes/RUMViewScopeTests.swift index 2f63207270..0bab959730 100644 --- a/Tests/DatadogTests/Datadog/RUM/RUMMonitor/Scopes/RUMViewScopeTests.swift +++ b/Tests/DatadogTests/Datadog/RUM/RUMMonitor/Scopes/RUMViewScopeTests.swift @@ -12,7 +12,11 @@ class RUMViewScopeTests: XCTestCase { private let output = RUMEventOutputMock() private let parent = RUMContextProviderMock() private let randomServiceName: String = .mockRandom() + private let randomDeviceInfo: RUMDevice = .mockRandom() + private let randomOSInfo: RUMOperatingSystem = .mockRandom() private lazy var dependencies: RUMScopeDependencies = .mockWith( + deviceInfo: randomDeviceInfo, + osInfo: randomOSInfo, serviceName: randomServiceName, eventOutput: output ) @@ -100,6 +104,8 @@ class RUMViewScopeTests: XCTestCase { XCTAssertEqual(event.dd.session?.plan, .plan1, "All RUM events should use RUM Lite plan") XCTAssertEqual(event.source, .ios) XCTAssertEqual(event.service, randomServiceName) + XCTAssertEqual(event.device, randomDeviceInfo) + XCTAssertEqual(event.os, randomOSInfo) XCTAssertNil(event.context?.contextInfo[RUMViewScope.Constants.activePrewarm]) } @@ -190,6 +196,8 @@ class RUMViewScopeTests: XCTestCase { XCTAssertEqual(event.dd.session?.plan, .plan1, "All RUM events should use RUM Lite plan") XCTAssertEqual(event.source, .ios) XCTAssertEqual(event.service, randomServiceName) + XCTAssertEqual(event.device, randomDeviceInfo) + XCTAssertEqual(event.os, randomOSInfo) } func testWhenInitialViewHasCconfiguredSource_itSendsViewUpdateEventWithConfiguredSource() throws { @@ -256,6 +264,8 @@ class RUMViewScopeTests: XCTestCase { XCTAssertEqual(event.context?.contextInfo as? [String: String], ["foo": "bar 2", "fizz": "buzz"]) XCTAssertEqual(event.source, .ios) XCTAssertEqual(event.service, randomServiceName) + XCTAssertEqual(event.device, randomDeviceInfo) + XCTAssertEqual(event.os, randomOSInfo) } func testWhenViewIsStopped_itSendsViewUpdateEvent_andEndsTheScope() throws { @@ -310,6 +320,8 @@ class RUMViewScopeTests: XCTestCase { XCTAssertEqual(event.context?.contextInfo as? [String: String], ["foo": "bar"]) XCTAssertEqual(event.source, .ios) XCTAssertEqual(event.service, randomServiceName) + XCTAssertEqual(event.device, randomDeviceInfo) + XCTAssertEqual(event.os, randomOSInfo) } func testWhenAnotherViewIsStarted_itEndsTheScope() throws { @@ -681,6 +693,8 @@ class RUMViewScopeTests: XCTestCase { XCTAssertEqual(firstActionEvent.action.target?.name, customActionName) XCTAssertEqual(firstActionEvent.source, .ios) XCTAssertEqual(firstActionEvent.service, randomServiceName) + XCTAssertEqual(firstActionEvent.device, randomDeviceInfo) + XCTAssertEqual(firstActionEvent.os, randomOSInfo) } func testGivenViewWithNoPendingAction_whenCustomActionIsAdded_itSendsItInstantly() throws { @@ -716,6 +730,8 @@ class RUMViewScopeTests: XCTestCase { XCTAssertEqual(firstActionEvent.action.target?.name, customActionName) XCTAssertEqual(firstActionEvent.source, .ios) XCTAssertEqual(firstActionEvent.service, randomServiceName) + XCTAssertEqual(firstActionEvent.device, randomDeviceInfo) + XCTAssertEqual(firstActionEvent.os, randomOSInfo) } // MARK: - Error Tracking @@ -770,6 +786,8 @@ class RUMViewScopeTests: XCTestCase { XCTAssertEqual(error.dd.session?.plan, .plan1, "All RUM events should use RUM Lite plan") XCTAssertEqual(error.source, .ios) XCTAssertEqual(error.service, randomServiceName) + XCTAssertEqual(error.device, randomDeviceInfo) + XCTAssertEqual(error.os, randomOSInfo) let viewUpdate = try XCTUnwrap(output.recordedEvents(ofType: RUMViewEvent.self).last) XCTAssertEqual(viewUpdate.view.error.count, 1) @@ -849,11 +867,15 @@ class RUMViewScopeTests: XCTestCase { XCTAssertTrue(error.error.isCrash ?? false) XCTAssertEqual(error.source, expectedSource) XCTAssertEqual(error.service, randomServiceName) + XCTAssertEqual(error.device, randomDeviceInfo) + XCTAssertEqual(error.os, randomOSInfo) let viewUpdate = try XCTUnwrap(output.recordedEvents(ofType: RUMViewEvent.self).last) XCTAssertEqual(viewUpdate.view.error.count, 1) XCTAssertEqual(viewUpdate.source, RUMViewEvent.Source(rawValue: customSource)) XCTAssertEqual(viewUpdate.service, randomServiceName) + XCTAssertEqual(viewUpdate.device, randomDeviceInfo) + XCTAssertEqual(viewUpdate.os, randomOSInfo) } func testWhenResourceIsFinishedWithError_itSendsViewUpdateEvent() throws { @@ -940,6 +962,8 @@ class RUMViewScopeTests: XCTestCase { XCTAssertEqual(event.view.id, scope.viewUUID.toRUMDataFormat) XCTAssertNil(event.synthetics) XCTAssertEqual(event.service, randomServiceName) + XCTAssertEqual(event.device, randomDeviceInfo) + XCTAssertEqual(event.os, randomOSInfo) let viewUpdate = try XCTUnwrap(output.recordedEvents(ofType: RUMViewEvent.self).last) XCTAssertEqual(viewUpdate.view.longTask?.count, 1) From d22aa12277035b54b41acfcb6ac46e4061aea723 Mon Sep 17 00:00:00 2001 From: Maciek Grzybowski Date: Mon, 13 Jun 2022 12:57:49 +0200 Subject: [PATCH 5/8] RUMM-2197 Add `CwlUtils` to LICENSE-3rdparty.csv --- LICENSE-3rdparty.csv | 1 + 1 file changed, 1 insertion(+) diff --git a/LICENSE-3rdparty.csv b/LICENSE-3rdparty.csv index cc3f578952..699a250afc 100644 --- a/LICENSE-3rdparty.csv +++ b/LICENSE-3rdparty.csv @@ -2,6 +2,7 @@ Component,Origin,License,Copyright import,io.opentracing,MIT,Copyright 2018 LightStep import,com.Lyft.Kronos,Apache-2.0,Copyright (C) 2016 Lyft Inc. and MobileNativeFoundation import,PLCrashReporter,MIT,Copyright Microsoft Corporation +import,https://github.com/mattgallagher/CwlUtils,ISC,Copyright (c) Matt Gallagher import (tools),https://github.com/jpsim/SourceKitten,MIT,Copyright (c) 2014 JP Simard import (tools),https://github.com/apple/swift-argument-parser,Apache-2.0,(c) 2020 Apple Inc. and the Swift project authors import (tools),https://github.com/krzysztofzablocki/Difference.git,MIT,Copyright (c) 2017 Krzysztof Zablocki From 8409225b3654be8d024987d50168b7a8c763a1e8 Mon Sep 17 00:00:00 2001 From: Maciek Grzybowski Date: Mon, 13 Jun 2022 13:30:03 +0200 Subject: [PATCH 6/8] RUMM-2197 Update `CHANGELOG.md` --- CHANGELOG.md | 1 + 1 file changed, 1 insertion(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 58b4af3e98..9d97688c72 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,6 +2,7 @@ ### Changes * [IMPROVEMENT] Add mobile vitals frequency configuration. See [#876][] +* [IMPROVEMENT] Include the exact model information in RUM `device.model`. See [#888][] # 1.11.0-rc1 / 18-05-2022 From 793bdcc2d8a21d0692d4e97d5108ae32da689274 Mon Sep 17 00:00:00 2001 From: Maciek Grzybowski Date: Mon, 13 Jun 2022 13:53:42 +0200 Subject: [PATCH 7/8] RUMM-2197 Fix integration tests build --- Tests/DatadogTests/Matchers/RUMSessionMatcher.swift | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Tests/DatadogTests/Matchers/RUMSessionMatcher.swift b/Tests/DatadogTests/Matchers/RUMSessionMatcher.swift index 63dce3dadd..e017501e51 100644 --- a/Tests/DatadogTests/Matchers/RUMSessionMatcher.swift +++ b/Tests/DatadogTests/Matchers/RUMSessionMatcher.swift @@ -321,7 +321,7 @@ private func validate(device: RUMDevice?) throws { ) } #if DD_COMPILED_FOR_INTEGRATION_TESTS - strictValidate(device: device) + try strictValidate(device: device) #endif } @@ -332,7 +332,7 @@ private func validate(os: RUMOperatingSystem?) throws { ) } #if DD_COMPILED_FOR_INTEGRATION_TESTS - strictValidate(os: os) + try strictValidate(os: os) #endif } From 1023c41bea75b0dcfc0f4c143ec06bbc2dca2be2 Mon Sep 17 00:00:00 2001 From: Maciek Grzybowski Date: Mon, 13 Jun 2022 16:37:42 +0200 Subject: [PATCH 8/8] RUMM-2197 Avoid strict `device` and `os` validation in browser SDK events (for integration tests) --- .../Matchers/RUMSessionMatcher.swift | 34 ++++++++++++------- 1 file changed, 22 insertions(+), 12 deletions(-) diff --git a/Tests/DatadogTests/Matchers/RUMSessionMatcher.swift b/Tests/DatadogTests/Matchers/RUMSessionMatcher.swift index e017501e51..5c7b435f4d 100644 --- a/Tests/DatadogTests/Matchers/RUMSessionMatcher.swift +++ b/Tests/DatadogTests/Matchers/RUMSessionMatcher.swift @@ -249,8 +249,10 @@ private func validate(rumViewEvents: [RUMViewEvent]) throws { description: "All RUM events must use session plan `1` (RUM Lite). Bad view event: \(viewEvent)" ) } - try validate(device: viewEvent.device) - try validate(os: viewEvent.os) + if viewEvent.source == .ios { // validete only mobile events + try validate(device: viewEvent.device) + try validate(os: viewEvent.os) + } } } @@ -262,8 +264,10 @@ private func validate(rumActionEvents: [RUMActionEvent]) throws { description: "All RUM events must use session plan `1` (RUM Lite). Bad action event: \(actionEvent)" ) } - try validate(device: actionEvent.device) - try validate(os: actionEvent.os) + if actionEvent.source == .ios { // validete only mobile events + try validate(device: actionEvent.device) + try validate(os: actionEvent.os) + } } } @@ -283,8 +287,10 @@ private func validate(rumResourceEvents: [RUMResourceEvent]) throws { description: "All RUM events must use session plan `1` (RUM Lite). Bad resource event: \(resourceEvent)" ) } - try validate(device: resourceEvent.device) - try validate(os: resourceEvent.os) + if resourceEvent.source == .ios { // validete only mobile events + try validate(device: resourceEvent.device) + try validate(os: resourceEvent.os) + } } } @@ -296,8 +302,10 @@ private func validate(rumErrorEvents: [RUMErrorEvent]) throws { description: "All RUM events must use session plan `1` (RUM Lite). Bad error event: \(errorEvent)" ) } - try validate(device: errorEvent.device) - try validate(os: errorEvent.os) + if errorEvent.source == .ios { // validete only mobile events + try validate(device: errorEvent.device) + try validate(os: errorEvent.os) + } } } @@ -309,8 +317,10 @@ private func validate(rumLongTaskEvents: [RUMLongTaskEvent]) throws { description: "All RUM events must use session plan `1` (RUM Lite). Bad long task event: \(longTaskEvent)" ) } - try validate(device: longTaskEvent.device) - try validate(os: longTaskEvent.os) + if longTaskEvent.source == .ios { // validete only mobile events + try validate(device: longTaskEvent.device) + try validate(os: longTaskEvent.os) + } } } @@ -384,13 +394,13 @@ private func strictValidate(device: RUMDevice) throws { /// It asserts that all values make sense for current environment. private func strictValidate(os: RUMOperatingSystem) throws { #if os(iOS) - if os.name != "iOS" && os.name != "iPadOS" { + guard os.name == "iOS" || os.name == "iPadOS" else { throw RUMSessionConsistencyException( description: "When running on iOS or iPadOS the `os.name` must be either 'iOS' or 'iPadOS'" ) } #else - if os.name != "tvOS" { + guard os.name == "tvOS" else { throw RUMSessionConsistencyException( description: "When running on tvOS the `os.name` must be 'tvOS'" )