From 023ef6134ae9757081a48c985dceae10aa6ef940 Mon Sep 17 00:00:00 2001 From: Maxime Epain Date: Fri, 29 Jul 2022 13:09:30 +0200 Subject: [PATCH 1/2] RUMM-2341 Expose server date provider interface --- Datadog/Datadog.xcodeproj/project.pbxproj | 18 +++++++---- Datadog/E2ETests/NTP/KronosE2ETests.swift | 2 +- .../Datadog/Core/FeaturesConfiguration.swift | 4 ++- ...der.swift => DatadogNTPDateProvider.swift} | 18 ++--------- .../System/Time/ServerDateCorrector.swift | 2 ++ .../Core/System/Time/ServerDateProvider.swift | 23 ++++++++++++++ Sources/Datadog/Datadog.swift | 2 +- Sources/Datadog/DatadogConfiguration.swift | 15 ++++++++++ Sources/Datadog/Kronos/KronosClock.swift | 6 +++- .../DatadogConfiguration+objc.swift | 30 +++++++++++++++++++ .../System/Time/DateCorrectionTests.swift | 16 +++++----- .../DatadogConfigurationBuilderTests.swift | 3 ++ Tests/DatadogTests/Datadog/DatadogTests.swift | 22 ++++++++++++++ .../Datadog/Mocks/CoreMocks.swift | 18 +++++++++-- .../DatadogObjc/DDConfigurationTests.swift | 8 +++++ 15 files changed, 151 insertions(+), 36 deletions(-) rename Sources/Datadog/Core/System/Time/{NTPServerDateProvider.swift => DatadogNTPDateProvider.swift} (74%) create mode 100644 Sources/Datadog/Core/System/Time/ServerDateProvider.swift diff --git a/Datadog/Datadog.xcodeproj/project.pbxproj b/Datadog/Datadog.xcodeproj/project.pbxproj index 9e4c490e03..1a75e87660 100644 --- a/Datadog/Datadog.xcodeproj/project.pbxproj +++ b/Datadog/Datadog.xcodeproj/project.pbxproj @@ -378,7 +378,7 @@ 61BB2B1B244A185D009F3F56 /* PerformancePreset.swift in Sources */ = {isa = PBXBuildFile; fileRef = 61BB2B1A244A185D009F3F56 /* PerformancePreset.swift */; }; 61BBD19524ED4E9E0023E65F /* FeaturesConfiguration.swift in Sources */ = {isa = PBXBuildFile; fileRef = 61BBD19424ED4E9E0023E65F /* FeaturesConfiguration.swift */; }; 61BBD19724ED50040023E65F /* FeaturesConfigurationTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 61BBD19624ED50040023E65F /* FeaturesConfigurationTests.swift */; }; - 61BCB81F256EB77F0039887B /* NTPServerDateProvider.swift in Sources */ = {isa = PBXBuildFile; fileRef = 61BCB81E256EB77F0039887B /* NTPServerDateProvider.swift */; }; + 61BCB81F256EB77F0039887B /* DatadogNTPDateProvider.swift in Sources */ = {isa = PBXBuildFile; fileRef = 61BCB81E256EB77F0039887B /* DatadogNTPDateProvider.swift */; }; 61C1510D25AC8C1B00362D4B /* RUMViewIdentityTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 61C1510C25AC8C1B00362D4B /* RUMViewIdentityTests.swift */; }; 61C2C20724C098FC00C0321C /* RUMSessionScope.swift in Sources */ = {isa = PBXBuildFile; fileRef = 61C2C20624C098FC00C0321C /* RUMSessionScope.swift */; }; 61C2C20924C0C75500C0321C /* RUMSessionScopeTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 61C2C20824C0C75500C0321C /* RUMSessionScopeTests.swift */; }; @@ -700,7 +700,7 @@ D2CB6E4527C50EAE00A62B57 /* RUMResourceScope.swift in Sources */ = {isa = PBXBuildFile; fileRef = 61494CB024C839460082C633 /* RUMResourceScope.swift */; }; D2CB6E4627C50EAE00A62B57 /* RUMSessionScope.swift in Sources */ = {isa = PBXBuildFile; fileRef = 61C2C20624C098FC00C0321C /* RUMSessionScope.swift */; }; D2CB6E4727C50EAE00A62B57 /* TracingUUID.swift in Sources */ = {isa = PBXBuildFile; fileRef = 617CEB382456BC3A00AD4669 /* TracingUUID.swift */; }; - D2CB6E4827C50EAE00A62B57 /* NTPServerDateProvider.swift in Sources */ = {isa = PBXBuildFile; fileRef = 61BCB81E256EB77F0039887B /* NTPServerDateProvider.swift */; }; + D2CB6E4827C50EAE00A62B57 /* DatadogNTPDateProvider.swift in Sources */ = {isa = PBXBuildFile; fileRef = 61BCB81E256EB77F0039887B /* DatadogNTPDateProvider.swift */; }; D2CB6E4927C50EAE00A62B57 /* AttributesSanitizer.swift in Sources */ = {isa = PBXBuildFile; fileRef = 61122ED925B1BA9700F9C7F5 /* AttributesSanitizer.swift */; }; D2CB6E4C27C50EAE00A62B57 /* RUMDataModelsMapping.swift in Sources */ = {isa = PBXBuildFile; fileRef = 618715F824DC13A100FC0F69 /* RUMDataModelsMapping.swift */; }; D2CB6E4D27C50EAE00A62B57 /* Globals.swift in Sources */ = {isa = PBXBuildFile; fileRef = 61C3638424361E9200C4D4E6 /* Globals.swift */; }; @@ -1036,6 +1036,8 @@ D2DC4BBD27F234E000E4FB96 /* CITestIntegrationTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = E143CCAE27D236F600F4018A /* CITestIntegrationTests.swift */; }; D2DC4BF627F484AA00E4FB96 /* DataEncryption.swift in Sources */ = {isa = PBXBuildFile; fileRef = D2DC4BF527F484AA00E4FB96 /* DataEncryption.swift */; }; D2DC4BF727F484AA00E4FB96 /* DataEncryption.swift in Sources */ = {isa = PBXBuildFile; fileRef = D2DC4BF527F484AA00E4FB96 /* DataEncryption.swift */; }; + D2E2C2592893E54600E336BE /* ServerDateProvider.swift in Sources */ = {isa = PBXBuildFile; fileRef = D2E2C2582893E54600E336BE /* ServerDateProvider.swift */; }; + D2E2C25A2893E54600E336BE /* ServerDateProvider.swift in Sources */ = {isa = PBXBuildFile; fileRef = D2E2C2582893E54600E336BE /* ServerDateProvider.swift */; }; D2EFA86B286DCDBB00F1FAA6 /* DateCorrector.swift in Sources */ = {isa = PBXBuildFile; fileRef = D2EFA86A286DCDBB00F1FAA6 /* DateCorrector.swift */; }; D2EFA86C286DCDBB00F1FAA6 /* DateCorrector.swift in Sources */ = {isa = PBXBuildFile; fileRef = D2EFA86A286DCDBB00F1FAA6 /* DateCorrector.swift */; }; D2EFF3D32731822A00D09F33 /* RUMViewsHandler.swift in Sources */ = {isa = PBXBuildFile; fileRef = D2EFF3D22731822A00D09F33 /* RUMViewsHandler.swift */; }; @@ -1598,7 +1600,7 @@ 61BB2B1A244A185D009F3F56 /* PerformancePreset.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = PerformancePreset.swift; sourceTree = ""; }; 61BBD19424ED4E9E0023E65F /* FeaturesConfiguration.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = FeaturesConfiguration.swift; sourceTree = ""; }; 61BBD19624ED50040023E65F /* FeaturesConfigurationTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = FeaturesConfigurationTests.swift; sourceTree = ""; }; - 61BCB81E256EB77F0039887B /* NTPServerDateProvider.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = NTPServerDateProvider.swift; sourceTree = ""; }; + 61BCB81E256EB77F0039887B /* DatadogNTPDateProvider.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = DatadogNTPDateProvider.swift; sourceTree = ""; }; 61C1510C25AC8C1B00362D4B /* RUMViewIdentityTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = RUMViewIdentityTests.swift; sourceTree = ""; }; 61C2C20624C098FC00C0321C /* RUMSessionScope.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = RUMSessionScope.swift; sourceTree = ""; }; 61C2C20824C0C75500C0321C /* RUMSessionScopeTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = RUMSessionScopeTests.swift; sourceTree = ""; }; @@ -1820,6 +1822,7 @@ D2CB6FEC27C5352300A62B57 /* DatadogCrashReportingTests.xctest */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = DatadogCrashReportingTests.xctest; sourceTree = BUILT_PRODUCTS_DIR; }; D2D37DBE2846335F00FB4348 /* DatadogV1CoreProtocol.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = DatadogV1CoreProtocol.swift; sourceTree = ""; }; D2DC4BF527F484AA00E4FB96 /* DataEncryption.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = DataEncryption.swift; sourceTree = ""; }; + D2E2C2582893E54600E336BE /* ServerDateProvider.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ServerDateProvider.swift; sourceTree = ""; }; D2EFA86A286DCDBB00F1FAA6 /* DateCorrector.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = DateCorrector.swift; sourceTree = ""; }; D2EFF3D22731822A00D09F33 /* RUMViewsHandler.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = RUMViewsHandler.swift; sourceTree = ""; }; D2F1B81026D795F3009F3293 /* DDNoopRUMMonitor.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = DDNoopRUMMonitor.swift; sourceTree = ""; }; @@ -3527,8 +3530,9 @@ 61C576C4256E655600295F7C /* Time */ = { isa = PBXGroup; children = ( - 61BCB81E256EB77F0039887B /* NTPServerDateProvider.swift */, + D2E2C2582893E54600E336BE /* ServerDateProvider.swift */, 61C576C5256E65BD00295F7C /* ServerDateCorrector.swift */, + 61BCB81E256EB77F0039887B /* DatadogNTPDateProvider.swift */, ); path = Time; sourceTree = ""; @@ -5127,7 +5131,7 @@ 61C2C20724C098FC00C0321C /* RUMSessionScope.swift in Sources */, 617CEB392456BC3A00AD4669 /* TracingUUID.swift in Sources */, D2956CA82869BA23007D5462 /* DatadogContext.swift in Sources */, - 61BCB81F256EB77F0039887B /* NTPServerDateProvider.swift in Sources */, + 61BCB81F256EB77F0039887B /* DatadogNTPDateProvider.swift in Sources */, 61122EDA25B1BA9700F9C7F5 /* AttributesSanitizer.swift in Sources */, 618715F924DC13A100FC0F69 /* RUMDataModelsMapping.swift in Sources */, 61C3638524361E9200C4D4E6 /* Globals.swift in Sources */, @@ -5221,6 +5225,7 @@ B3FC3C0926526F0000DEED9E /* VitalInfo.swift in Sources */, 61DA8CAF28620C760074A606 /* Cryptography.swift in Sources */, 616F1FB32840125400651A3A /* RUMV2Configuration.swift in Sources */, + D2E2C2592893E54600E336BE /* ServerDateProvider.swift in Sources */, 613E81F025A740140084B751 /* RUMEventsMapper.swift in Sources */, 61D980BA24E28D0100E03345 /* RUMIntegrations.swift in Sources */, 61C5A88424509A0C00DA608C /* DDSpan.swift in Sources */, @@ -5724,6 +5729,7 @@ D2CB6E2927C50EAE00A62B57 /* KronosInternetAddress.swift in Sources */, D2CB6E2A27C50EAE00A62B57 /* RUMContextProvider.swift in Sources */, 6122514927FDFF82004F5AE4 /* RUMScopeDependencies.swift in Sources */, + D2E2C25A2893E54600E336BE /* ServerDateProvider.swift in Sources */, D2CB6E2B27C50EAE00A62B57 /* RUMViewScope.swift in Sources */, D2CB6E2C27C50EAE00A62B57 /* KronosNTPPacket.swift in Sources */, D2CB6E2D27C50EAE00A62B57 /* CrashReportingFeature.swift in Sources */, @@ -5763,7 +5769,7 @@ 61DA8CB028620C760074A606 /* Cryptography.swift in Sources */, D2DC4BF727F484AA00E4FB96 /* DataEncryption.swift in Sources */, D2CB6E4727C50EAE00A62B57 /* TracingUUID.swift in Sources */, - D2CB6E4827C50EAE00A62B57 /* NTPServerDateProvider.swift in Sources */, + D2CB6E4827C50EAE00A62B57 /* DatadogNTPDateProvider.swift in Sources */, D2CB6E4927C50EAE00A62B57 /* AttributesSanitizer.swift in Sources */, 6194E4BD2878AF7600EB6307 /* ConsoleLogger.swift in Sources */, D2CB6E4C27C50EAE00A62B57 /* RUMDataModelsMapping.swift in Sources */, diff --git a/Datadog/E2ETests/NTP/KronosE2ETests.swift b/Datadog/E2ETests/NTP/KronosE2ETests.swift index 452f19649f..9f7b4e88a0 100644 --- a/Datadog/E2ETests/NTP/KronosE2ETests.swift +++ b/Datadog/E2ETests/NTP/KronosE2ETests.swift @@ -83,7 +83,7 @@ class KronosE2ETests: E2ETests { } // Run test for each Datadog NTP pool: - NTPServerDateProvider.datadogNTPServers.forEach { ddNTPPool in + DatadogNTPDateProvider.datadogNTPServers.forEach { ddNTPPool in let result = measure(resourceName: DD.PerfSpanName.fromCurrentMethodName()) { performKronosSync(using: ddNTPPool) } diff --git a/Sources/Datadog/Core/FeaturesConfiguration.swift b/Sources/Datadog/Core/FeaturesConfiguration.swift index e08c4c7499..8bbb9f4ab4 100644 --- a/Sources/Datadog/Core/FeaturesConfiguration.swift +++ b/Sources/Datadog/Core/FeaturesConfiguration.swift @@ -27,6 +27,7 @@ internal struct FeaturesConfiguration { let sdkVersion: String let proxyConfiguration: [AnyHashable: Any]? let encryption: DataEncryption? + let serverDateProvider: ServerDateProvider? } struct Logging { @@ -168,7 +169,8 @@ extension FeaturesConfiguration { origin: CITestIntegration.active?.origin, sdkVersion: sdkVersion, proxyConfiguration: configuration.proxyConfiguration, - encryption: configuration.encryption + encryption: configuration.encryption, + serverDateProvider: configuration.serverDateProvider ) if configuration.loggingEnabled { diff --git a/Sources/Datadog/Core/System/Time/NTPServerDateProvider.swift b/Sources/Datadog/Core/System/Time/DatadogNTPDateProvider.swift similarity index 74% rename from Sources/Datadog/Core/System/Time/NTPServerDateProvider.swift rename to Sources/Datadog/Core/System/Time/DatadogNTPDateProvider.swift index af09cd93f0..c2bb09ca7d 100644 --- a/Sources/Datadog/Core/System/Time/NTPServerDateProvider.swift +++ b/Sources/Datadog/Core/System/Time/DatadogNTPDateProvider.swift @@ -6,21 +6,7 @@ import Foundation -/// Abstract the monotonic clock synchronized with the server using NTP. -internal protocol ServerDateProvider { - /// Start the clock synchronisation with NTP server. - /// Calls the `completion` by passing it the server time offset when the synchronization succeeds or`nil` if it fails. - func synchronize(update: @escaping (TimeInterval) -> Void) -} - -internal class NTPServerDateProvider: ServerDateProvider { - static let datadogNTPServers = [ - "0.datadog.pool.ntp.org", - "1.datadog.pool.ntp.org", - "2.datadog.pool.ntp.org", - "3.datadog.pool.ntp.org" - ] - +internal class DatadogNTPDateProvider: ServerDateProvider { let kronos: KronosClockProtocol init(kronos: KronosClockProtocol = KronosClock()) { @@ -29,7 +15,7 @@ internal class NTPServerDateProvider: ServerDateProvider { func synchronize(update: @escaping (TimeInterval) -> Void) { kronos.sync( - from: NTPServerDateProvider.datadogNTPServers.randomElement()!, // swiftlint:disable:this force_unwrapping + from: DatadogNTPServers.randomElement()!, // swiftlint:disable:this force_unwrapping first: { _, offset in update(offset) }, diff --git a/Sources/Datadog/Core/System/Time/ServerDateCorrector.swift b/Sources/Datadog/Core/System/Time/ServerDateCorrector.swift index cd960f5a8a..8b77f5579f 100644 --- a/Sources/Datadog/Core/System/Time/ServerDateCorrector.swift +++ b/Sources/Datadog/Core/System/Time/ServerDateCorrector.swift @@ -10,8 +10,10 @@ import Foundation internal class ServerDateCorrector: DateCorrector { /// Server offset publisher. private let publisher: ValuePublisher = ValuePublisher(initialValue: 0) + private let provider: ServerDateProvider init(serverDateProvider: ServerDateProvider) { + self.provider = serverDateProvider serverDateProvider.synchronize(update: publisher.publishAsync) } diff --git a/Sources/Datadog/Core/System/Time/ServerDateProvider.swift b/Sources/Datadog/Core/System/Time/ServerDateProvider.swift new file mode 100644 index 0000000000..df859e0d3a --- /dev/null +++ b/Sources/Datadog/Core/System/Time/ServerDateProvider.swift @@ -0,0 +1,23 @@ +/* + * 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 + +/// List of Datadog NTP pools. +public let DatadogNTPServers = [ + "0.datadog.pool.ntp.org", + "1.datadog.pool.ntp.org", + "2.datadog.pool.ntp.org", + "3.datadog.pool.ntp.org" +] + +/// Abstract the monotonic clock synchronized with the server using NTP. +public protocol ServerDateProvider { + /// Start the clock synchronisation with NTP server. + /// + /// Calls the `completion` by passing it the server time offset when the synchronization succeeds. + func synchronize(update: @escaping (TimeInterval) -> Void) +} diff --git a/Sources/Datadog/Datadog.swift b/Sources/Datadog/Datadog.swift index 932a9f6749..1b7ca6d3e1 100644 --- a/Sources/Datadog/Datadog.swift +++ b/Sources/Datadog/Datadog.swift @@ -177,7 +177,7 @@ public class Datadog { let userInfoProvider = UserInfoProvider() let dateProvider = SystemDateProvider() let dateCorrector = ServerDateCorrector( - serverDateProvider: NTPServerDateProvider() + serverDateProvider: configuration.common.serverDateProvider ?? DatadogNTPDateProvider() ) let networkConnectionInfoProvider = NetworkConnectionInfoProvider() let carrierInfoProvider = CarrierInfoProvider() diff --git a/Sources/Datadog/DatadogConfiguration.swift b/Sources/Datadog/DatadogConfiguration.swift index ccf5ad41ff..f1e16b02c9 100644 --- a/Sources/Datadog/DatadogConfiguration.swift +++ b/Sources/Datadog/DatadogConfiguration.swift @@ -242,6 +242,7 @@ extension Datadog { private(set) var loggingEnabled: Bool private(set) var tracingEnabled: Bool private(set) var rumEnabled: Bool + private(set) var serverDateProvider: ServerDateProvider? private(set) var crashReportingPlugin: DDCrashReportingPluginType? /// If `DatadogEndpoint` is set, it will override `logsEndpoint`, `tracesEndpoint` and `rumEndpoint` values. @@ -398,6 +399,20 @@ extension Datadog { return self } + /// Sets a custom NTP synchronization interface. + /// + /// By default, the Datadog SDK synchronizes with dedicated NTP pools provided by the + /// https://www.ntppool.org/ . Using different pools or setting a no-op `ServerDateProvider` + /// implementation will result in desynchronization of the SDK instance and the Datadog servers. + /// This can lead to significant time shift in RUM sessions or distributed traces. + /// + /// - Parameter serverDateProvider: An object that complies with `ServerDateProvider` + /// for provider clock synchronisation. + public func set(serverDateProvider: ServerDateProvider) -> Builder { + configuration.serverDateProvider = serverDateProvider + return self + } + // MARK: - Logging Configuration /// Enables or disables the logging feature. diff --git a/Sources/Datadog/Kronos/KronosClock.swift b/Sources/Datadog/Kronos/KronosClock.swift index 7c718c18fe..c8da80a6ce 100644 --- a/Sources/Datadog/Kronos/KronosClock.swift +++ b/Sources/Datadog/Kronos/KronosClock.swift @@ -125,7 +125,11 @@ internal final class KronosClock: KronosClockProtocol { ) { self.loadFromDefaults() - KronosNTPClient().query(pool: pool, numberOfSamples: samples) { offset, done, total in + KronosNTPClient().query(pool: pool, numberOfSamples: samples) { [weak self] offset, done, total in + guard let self = self else { + return + } + if let offset = offset { self.stableTime = KronosTimeFreeze(offset: offset) diff --git a/Sources/DatadogObjc/DatadogConfiguration+objc.swift b/Sources/DatadogObjc/DatadogConfiguration+objc.swift index e0815a8a90..703ee84a8f 100644 --- a/Sources/DatadogObjc/DatadogConfiguration+objc.swift +++ b/Sources/DatadogObjc/DatadogConfiguration+objc.swift @@ -191,6 +191,22 @@ internal struct DDDataEncryptionBridge: DataEncryption { } } +@objc +public protocol DDServerDateProvider: AnyObject { + /// Start the clock synchronisation with NTP server. + /// + /// Calls the `completion` by passing it the server time offset when the synchronization succeeds or`nil` if it fails. + func synchronize(update: @escaping (TimeInterval) -> Void) +} + +internal struct DDServerDateProviderBridge: ServerDateProvider { + let objcProvider: DDServerDateProvider + + func synchronize(update: @escaping (TimeInterval) -> Void) { + objcProvider.synchronize(update: update) + } +} + @objc public class DDConfiguration: NSObject { internal let sdkConfiguration: Datadog.Configuration @@ -267,6 +283,20 @@ public class DDConfigurationBuilder: NSObject { _ = sdkBuilder.set(customRUMEndpoint: customRUMEndpoint) } + /// Sets a custom NTP synchronization interface. + /// + /// By default, the Datadog SDK synchronizes with dedicated NTP pools provided by the + /// https://www.ntppool.org/ . Using different pools or setting a no-op `DDServerDateProvider` + /// implementation will result in desynchronization of the SDK instance and the Datadog servers. + /// This can lead to significant time shift in RUM sessions or distributed traces. + /// + /// - Parameter serverDateProvider: An object that complies with `DDServerDateProvider` + /// for provider clock synchronisation. + @objc + public func set(serverDateProvider: DDServerDateProvider) { + _ = sdkBuilder.set(serverDateProvider: DDServerDateProviderBridge(objcProvider: serverDateProvider)) + } + @available(*, deprecated, message: "This option is replaced by `set(endpoint:)`. Refer to the new API comment for details.") @objc public func set(logsEndpoint: DDLogsEndpoint) { diff --git a/Tests/DatadogTests/Datadog/Core/System/Time/DateCorrectionTests.swift b/Tests/DatadogTests/Datadog/Core/System/Time/DateCorrectionTests.swift index df7a48e4c0..6ff16b557a 100644 --- a/Tests/DatadogTests/Datadog/Core/System/Time/DateCorrectionTests.swift +++ b/Tests/DatadogTests/Datadog/Core/System/Time/DateCorrectionTests.swift @@ -32,7 +32,7 @@ private class KronosClockMock: KronosClockProtocol { class DateCorrectorTests: XCTestCase { func testWhenInitialized_itSynchronizesWithOneOfDatadogNTPServers() throws { let kronos = KronosClockMock() - let serverDateProvider = NTPServerDateProvider(kronos: kronos) + let serverDateProvider = DatadogNTPDateProvider(kronos: kronos) var randomlyChosenServers: Set = [] @@ -43,7 +43,7 @@ class DateCorrectorTests: XCTestCase { randomlyChosenServers.insert(pool) } - let allAvailableServers = Set(NTPServerDateProvider.datadogNTPServers) + let allAvailableServers = Set(DatadogNTPServers) XCTAssertEqual(randomlyChosenServers, allAvailableServers, "Each time Datadog NTP server should be picked randomly.") } @@ -53,7 +53,7 @@ class DateCorrectorTests: XCTestCase { // When let kronos = KronosClockMock() - let serverDateProvider = NTPServerDateProvider(kronos: kronos) + let serverDateProvider = DatadogNTPDateProvider(kronos: kronos) serverDateProvider.synchronize { _ in } kronos.completion?(.init(timeIntervalSinceNow: -1), nil) @@ -73,7 +73,7 @@ class DateCorrectorTests: XCTestCase { // When let kronos = KronosClockMock() - let serverDateProvider = NTPServerDateProvider(kronos: kronos) + let serverDateProvider = DatadogNTPDateProvider(kronos: kronos) serverDateProvider.synchronize { _ in } kronos.completion?(nil, -1) @@ -93,7 +93,7 @@ class DateCorrectorTests: XCTestCase { // When let kronos = KronosClockMock() - let serverDateProvider = NTPServerDateProvider(kronos: kronos) + let serverDateProvider = DatadogNTPDateProvider(kronos: kronos) serverDateProvider.synchronize { _ in } kronos.completion?(nil, nil) @@ -109,7 +109,7 @@ class DateCorrectorTests: XCTestCase { func testWhenServerTimeIsNotAvailable_itDoesNoCorrection() { let kronos = KronosClockMock() - let serverDateProvider = NTPServerDateProvider(kronos: kronos) + let serverDateProvider = DatadogNTPDateProvider(kronos: kronos) // When let corrector = ServerDateCorrector(serverDateProvider: serverDateProvider) @@ -124,7 +124,7 @@ class DateCorrectorTests: XCTestCase { let deviceDateProvider = RelativeDateProvider(using: .mockRandomInThePast()) let kronos = KronosClockMock() - let serverDateProvider = NTPServerDateProvider(kronos: kronos) + let serverDateProvider = DatadogNTPDateProvider(kronos: kronos) // When var serverOffset: TimeInterval = .mockRandomInThePast() @@ -171,7 +171,7 @@ class DateCorrectorTests: XCTestCase { func testRandomlyCallingCorrectionConcurrentlyDoesNotCrash() { let kronos = KronosClockMock() - let serverDateProvider = NTPServerDateProvider(kronos: kronos) + let serverDateProvider = DatadogNTPDateProvider(kronos: kronos) let corrector = ServerDateCorrector(serverDateProvider: serverDateProvider) kronos.completion?(nil, .mockRandomInThePast()) diff --git a/Tests/DatadogTests/Datadog/DatadogConfigurationBuilderTests.swift b/Tests/DatadogTests/Datadog/DatadogConfigurationBuilderTests.swift index 71f63c1fcb..f91595c7e8 100644 --- a/Tests/DatadogTests/Datadog/DatadogConfigurationBuilderTests.swift +++ b/Tests/DatadogTests/Datadog/DatadogConfigurationBuilderTests.swift @@ -62,6 +62,7 @@ class DatadogConfigurationBuilderTests: XCTestCase { XCTAssertEqual(configuration.uploadFrequency, .average) XCTAssertEqual(configuration.additionalConfiguration.count, 0) XCTAssertNil(configuration.encryption) + XCTAssertNil(configuration.serverDateProvider) } } @@ -114,6 +115,7 @@ class DatadogConfigurationBuilderTests: XCTestCase { kCFProxyPasswordKey: "proxypass", ]) .set(encryption: DataEncryptionMock()) + .set(serverDateProvider: ServerDateProviderMock()) return builder } @@ -175,6 +177,7 @@ class DatadogConfigurationBuilderTests: XCTestCase { XCTAssertEqual(configuration.proxyConfiguration?[kCFProxyUsernameKey] as? String, "proxyuser") XCTAssertEqual(configuration.proxyConfiguration?[kCFProxyPasswordKey] as? String, "proxypass") XCTAssertTrue(configuration.encryption is DataEncryptionMock) + XCTAssertTrue(configuration.serverDateProvider is ServerDateProviderMock) } XCTAssertTrue(rumConfigurationWithDefaultValues.rumUIKitViewsPredicate is DefaultUIKitRUMViewsPredicate) diff --git a/Tests/DatadogTests/Datadog/DatadogTests.swift b/Tests/DatadogTests/Datadog/DatadogTests.swift index 8f1ff2304e..c49bc545b7 100644 --- a/Tests/DatadogTests/Datadog/DatadogTests.swift +++ b/Tests/DatadogTests/Datadog/DatadogTests.swift @@ -466,6 +466,28 @@ class DatadogTests: XCTestCase { Datadog.flushAndDeinitialize() } + + func testServerDateProvider() throws { + // Given + let serverDateProvider = ServerDateProviderMock() + + // When + Datadog.initialize( + appContext: .mockAny(), + trackingConsent: .mockRandom(), + configuration: defaultBuilder + .set(serverDateProvider: serverDateProvider) + .build() + ) + + serverDateProvider.offset = -1 + + // Then + let core = try XCTUnwrap(defaultDatadogCore as? DatadogCore) + XCTAssertEqual(core.dependencies.dateCorrector.offset, -1) + + Datadog.flushAndDeinitialize() + } } class AppContextTests: XCTestCase { diff --git a/Tests/DatadogTests/Datadog/Mocks/CoreMocks.swift b/Tests/DatadogTests/Datadog/Mocks/CoreMocks.swift index d315e45e58..9423a99f39 100644 --- a/Tests/DatadogTests/Datadog/Mocks/CoreMocks.swift +++ b/Tests/DatadogTests/Datadog/Mocks/CoreMocks.swift @@ -207,7 +207,8 @@ extension FeaturesConfiguration.Common { origin: String? = nil, sdkVersion: String = .mockAny(), proxyConfiguration: [AnyHashable: Any]? = nil, - encryption: DataEncryption? = nil + encryption: DataEncryption? = nil, + serverDateProvider: ServerDateProvider? = nil ) -> Self { return .init( site: site, @@ -222,7 +223,8 @@ extension FeaturesConfiguration.Common { origin: origin, sdkVersion: sdkVersion, proxyConfiguration: proxyConfiguration, - encryption: encryption + encryption: encryption, + serverDateProvider: serverDateProvider ) } } @@ -371,6 +373,18 @@ struct DataEncryptionMock: DataEncryption { func decrypt(data: Data) throws -> Data { try dec(data) } } +class ServerDateProviderMock: ServerDateProvider { + private var update: (TimeInterval) -> Void = { _ in } + + var offset: TimeInterval = .zero { + didSet { update(offset) } + } + + func synchronize(update: @escaping (TimeInterval) -> Void) { + self.update = update + } +} + // MARK: - PerformancePreset Mocks struct StoragePerformanceMock: StoragePerformancePreset { diff --git a/Tests/DatadogTests/DatadogObjc/DDConfigurationTests.swift b/Tests/DatadogTests/DatadogObjc/DDConfigurationTests.swift index 44ff36e659..093c8d32fd 100644 --- a/Tests/DatadogTests/DatadogObjc/DDConfigurationTests.swift +++ b/Tests/DatadogTests/DatadogObjc/DDConfigurationTests.swift @@ -66,6 +66,7 @@ class DDConfigurationTests: XCTestCase { XCTAssertNil(configuration.rumErrorEventMapper) XCTAssertEqual(configuration.additionalConfiguration.count, 0) XCTAssertNil(configuration.encryption) + XCTAssertNil(configuration.serverDateProvider) } } @@ -213,6 +214,13 @@ class DDConfigurationTests: XCTestCase { let dataEncryption = ObjCDataEncryption() objcBuilder.set(encryption: dataEncryption) XCTAssertTrue((objcBuilder.build().sdkConfiguration.encryption as? DDDataEncryptionBridge)?.objcEncryption === dataEncryption) + + class ObjcServerDateProvider: DDServerDateProvider { + func synchronize(update: @escaping (TimeInterval) -> Void) { } + } + let serverDateProvider = ObjcServerDateProvider() + objcBuilder.set(serverDateProvider: serverDateProvider) + XCTAssertTrue((objcBuilder.build().sdkConfiguration.serverDateProvider as? DDServerDateProviderBridge)?.objcProvider === serverDateProvider) } func testScrubbingRUMEvents() { From b8a839c616c8b78395b2ba769b407798ee35f156 Mon Sep 17 00:00:00 2001 From: Maxime Epain Date: Fri, 29 Jul 2022 13:16:26 +0200 Subject: [PATCH 2/2] RUMM-2341 Update CHANGELOG --- CHANGELOG.md | 2 ++ 1 file changed, 2 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index c43a7b3dce..0b27415f48 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -6,6 +6,7 @@ * [IMPROVEMENT] Include the exact model information in RUM `device.model`. See [#888][] * [FEATURE] Allow filtering outgoing logs with a status threshold. See [#867][] * [BUGFIX] Fix compilation issue in SwiftUI Previews. See [#949][] +* [IMPROVEMENT] Expose server date provider for custom clock synchronization. See [#950][] # 1.11.1 / 20-06-2022 @@ -397,6 +398,7 @@ [#876]: https://github.com/DataDog/dd-sdk-ios/issues/876 [#894]: https://github.com/DataDog/dd-sdk-ios/issues/894 [#949]: https://github.com/DataDog/dd-sdk-ios/issues/949 +[#950]: https://github.com/DataDog/dd-sdk-ios/issues/950 [@00FA9A]: https://github.com/00FA9A [@Britton-Earnin]: https://github.com/Britton-Earnin [@Hengyu]: https://github.com/Hengyu