diff --git a/packages/core/DatadogSDKReactNative.podspec b/packages/core/DatadogSDKReactNative.podspec index e04f5fc2e..cb4dac1bc 100644 --- a/packages/core/DatadogSDKReactNative.podspec +++ b/packages/core/DatadogSDKReactNative.podspec @@ -19,15 +19,15 @@ Pod::Spec.new do |s| s.dependency "React-Core" # /!\ Remember to keep the versions in sync with DatadogSDKReactNativeSessionReplay.podspec - s.dependency 'DatadogCore', '3.16.0' - s.dependency 'DatadogLogs', '3.16.0' - s.dependency 'DatadogTrace', '3.16.0' - s.dependency 'DatadogRUM', '3.16.0' - s.dependency 'DatadogCrashReporting', '3.16.0' - s.dependency 'DatadogFlags', '3.16.0' + s.dependency 'DatadogCore', '3.17.0' + s.dependency 'DatadogLogs', '3.17.0' + s.dependency 'DatadogTrace', '3.17.0' + s.dependency 'DatadogRUM', '3.17.0' + s.dependency 'DatadogCrashReporting', '3.17.0' + s.dependency 'DatadogFlags', '3.17.0' # DatadogWebViewTracking is not available for tvOS - s.ios.dependency 'DatadogWebViewTracking', '3.16.0' + s.ios.dependency 'DatadogWebViewTracking', '3.17.0' s.test_spec 'Tests' do |test_spec| test_spec.source_files = 'ios/Tests/**/*.{swift,json}' diff --git a/packages/core/ios/Sources/DdFlagsImplementation.swift b/packages/core/ios/Sources/DdFlagsImplementation.swift index 34020f410..d0a050069 100644 --- a/packages/core/ios/Sources/DdFlagsImplementation.swift +++ b/packages/core/ios/Sources/DdFlagsImplementation.swift @@ -172,7 +172,7 @@ extension FlagAssignment { case .unknown: NSNull() } - return [ + var dictionary: [String: Any] = [ "key": flagKey, "value": value, "allocationKey": allocationKey, @@ -184,9 +184,17 @@ extension FlagAssignment { "variationValue": "", "extraLogging": [:], ] + + if let serialID { + dictionary[serialIDKey] = String(serialID) + } + + return dictionary } } +private let serialIDKey = "serialId" + extension NSDictionary { func asFlagAssignment() -> FlagAssignment? { guard @@ -213,7 +221,8 @@ extension NSDictionary { variationKey: variationKey, variation: variation, reason: reason, - doLog: doLog + doLog: doLog, + serialID: (object(forKey: serialIDKey) as? String).flatMap(Int.init) ) } } diff --git a/packages/core/ios/Tests/DdFlagsTests.swift b/packages/core/ios/Tests/DdFlagsTests.swift index 3fca72ddc..915843485 100644 --- a/packages/core/ios/Tests/DdFlagsTests.swift +++ b/packages/core/ios/Tests/DdFlagsTests.swift @@ -368,6 +368,40 @@ class DdFlagsTests: XCTestCase { XCTAssertEqual(dict["variationType"] as? String, "") XCTAssertEqual(dict["variationValue"] as? String, "") XCTAssertNotNil(dict["extraLogging"] as? [String: Any]) + // An assignment with no serial ID omits the key rather than sending NSNull. + XCTAssertNil(dict["serialId"]) + } + + func testFlagAssignmentToDictionaryCarriesSerialID() { + let assignment = FlagAssignment( + allocationKey: "alloc", + variationKey: "var", + variation: .boolean(true), + reason: "reason", + doLog: true, + serialID: 340132 + ) + + let dict = assignment.asDictionary(flagKey: "flag1") + + // Sent as a String because the React Native bridge converts integers to Double. + XCTAssertEqual(dict["serialId"] as? String, "340132") + } + + func testFlagAssignmentToDictionaryCarriesSerialIDZero() { + // Serial IDs are zero-based per org, so 0 is a real value, not an absent one. + let assignment = FlagAssignment( + allocationKey: "alloc", + variationKey: "var", + variation: .boolean(true), + reason: "reason", + doLog: true, + serialID: 0 + ) + + let dict = assignment.asDictionary(flagKey: "flag1") + + XCTAssertEqual(dict["serialId"] as? String, "0") } func testDictionaryToFlagAssignment() { @@ -389,6 +423,71 @@ class DdFlagsTests: XCTestCase { } else { XCTFail("Expected string variation") } + XCTAssertNil(assignment?.serialID) + } + + func testDictionaryToFlagAssignmentReadsSerialID() { + let dict: NSDictionary = [ + "allocationKey": "alloc", + "variationKey": "var", + "reason": "reason", + "doLog": true, + "value": "string_value", + "serialId": "340132" + ] + + XCTAssertEqual(dict.asFlagAssignment()?.serialID, 340132) + } + + func testDictionaryToFlagAssignmentReadsSerialIDZero() { + let dict: NSDictionary = [ + "allocationKey": "alloc", + "variationKey": "var", + "reason": "reason", + "doLog": true, + "value": "string_value", + "serialId": "0" + ] + + XCTAssertEqual(dict.asFlagAssignment()?.serialID, 0) + } + + func testDictionaryToFlagAssignmentIgnoresMalformedSerialID() { + // A malformed serial ID binds to the serial ID. It must not reject the assignment, + // because that would drop the exposure event for the whole flag. + let malformedValues: [Any] = ["not-a-number", "", true, 340132] + + for malformed in malformedValues { + let dict: NSDictionary = [ + "allocationKey": "alloc", + "variationKey": "var", + "reason": "reason", + "doLog": true, + "value": "string_value", + "serialId": malformed + ] + + let assignment = dict.asFlagAssignment() + + XCTAssertNotNil(assignment, "Expected an assignment for serialId \(malformed)") + XCTAssertNil(assignment?.serialID, "Expected no serial ID for \(malformed)") + } + } + + func testFlagAssignmentSerialIDSurvivesARoundTrip() { + let assignment = FlagAssignment( + allocationKey: "alloc", + variationKey: "var", + variation: .string("string_value"), + reason: "reason", + doLog: true, + serialID: 0 + ) + + let roundTripped = (assignment.asDictionary(flagKey: "flag1") as NSDictionary) + .asFlagAssignment() + + XCTAssertEqual(roundTripped?.serialID, 0) } } diff --git a/packages/react-native-session-replay/DatadogSDKReactNativeSessionReplay.podspec b/packages/react-native-session-replay/DatadogSDKReactNativeSessionReplay.podspec index a78a62ca4..e80fb66ea 100644 --- a/packages/react-native-session-replay/DatadogSDKReactNativeSessionReplay.podspec +++ b/packages/react-native-session-replay/DatadogSDKReactNativeSessionReplay.podspec @@ -22,7 +22,7 @@ Pod::Spec.new do |s| s.dependency "React-Core" # /!\ Remember to keep the version in sync with DatadogSDKReactNative.podspec - s.dependency 'DatadogSessionReplay', '3.16.0' + s.dependency 'DatadogSessionReplay', '3.17.0' s.dependency 'DatadogSDKReactNative' s.test_spec 'Tests' do |test_spec| diff --git a/packages/react-native-webview/DatadogSDKReactNativeWebView.podspec b/packages/react-native-webview/DatadogSDKReactNativeWebView.podspec index 722e76634..fc9385219 100644 --- a/packages/react-native-webview/DatadogSDKReactNativeWebView.podspec +++ b/packages/react-native-webview/DatadogSDKReactNativeWebView.podspec @@ -23,8 +23,8 @@ Pod::Spec.new do |s| end # /!\ Remember to keep the version in sync with DatadogSDKReactNative.podspec - s.dependency 'DatadogWebViewTracking', '3.16.0' - s.dependency 'DatadogInternal', '3.16.0' + s.dependency 'DatadogWebViewTracking', '3.17.0' + s.dependency 'DatadogInternal', '3.17.0' s.dependency 'DatadogSDKReactNative' s.test_spec 'Tests' do |test_spec|