From 286d6a43a48cd1af287a37a5f960b14479ce1598 Mon Sep 17 00:00:00 2001 From: Yansong Date: Thu, 11 Mar 2021 12:34:39 -0600 Subject: [PATCH 1/8] migration stored V5 data to new format --- AEPTarget.xcodeproj/project.pbxproj | 8 + .../Preview/TargetPreviewManager.swift | 4 +- AEPTarget/Sources/Target.swift | 1 + AEPTarget/Sources/TargetConstants.swift | 20 +- AEPTarget/Sources/TargetV5Migrator.swift | 61 +++++++ AEPTarget/Tests/UnitTests/TargetTests.swift | 38 ++++ .../UnitTests/TargetV5MigratorTests.swift | 171 ++++++++++++++++++ Podfile.lock | 10 +- 8 files changed, 301 insertions(+), 12 deletions(-) create mode 100644 AEPTarget/Sources/TargetV5Migrator.swift create mode 100644 AEPTarget/Tests/UnitTests/TargetV5MigratorTests.swift diff --git a/AEPTarget.xcodeproj/project.pbxproj b/AEPTarget.xcodeproj/project.pbxproj index e95a34e..c5d6ed8 100644 --- a/AEPTarget.xcodeproj/project.pbxproj +++ b/AEPTarget.xcodeproj/project.pbxproj @@ -63,11 +63,13 @@ BB47C00E25547D6400EC6FB5 /* TargetOrder.swift in Sources */ = {isa = PBXBuildFile; fileRef = BB47C00D25547D6400EC6FB5 /* TargetOrder.swift */; }; BB47C01025547D8300EC6FB5 /* TargetProduct.swift in Sources */ = {isa = PBXBuildFile; fileRef = BB47C00F25547D8300EC6FB5 /* TargetProduct.swift */; }; BB47C01225547DAE00EC6FB5 /* TargetRequest.swift in Sources */ = {isa = PBXBuildFile; fileRef = BB47C01125547DAE00EC6FB5 /* TargetRequest.swift */; }; + BB57390925F9AD08008352D2 /* TargetV5Migrator.swift in Sources */ = {isa = PBXBuildFile; fileRef = BB57390825F9AD08008352D2 /* TargetV5Migrator.swift */; }; BB9C86EF255C9C90007AEF8B /* Event+TargetTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = BB9C86EE255C9C90007AEF8B /* Event+TargetTests.swift */; }; BB9C8707255EF203007AEF8B /* TargetDeliveryRequest.swift in Sources */ = {isa = PBXBuildFile; fileRef = BB9C8706255EF202007AEF8B /* TargetDeliveryRequest.swift */; }; BB9C870F25623692007AEF8B /* TargetPrefetch+Internal.swift in Sources */ = {isa = PBXBuildFile; fileRef = BB9C870E25623692007AEF8B /* TargetPrefetch+Internal.swift */; }; BB9C871A25623723007AEF8B /* TargetOrder+Internal.swift in Sources */ = {isa = PBXBuildFile; fileRef = BB9C871925623723007AEF8B /* TargetOrder+Internal.swift */; }; BB9C871F256237F2007AEF8B /* TargetProduct+Internal.swift in Sources */ = {isa = PBXBuildFile; fileRef = BB9C871E256237F2007AEF8B /* TargetProduct+Internal.swift */; }; + BB9F451A25F9CCB4002A54E7 /* TargetV5MigratorTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = BB9F451925F9CCB4002A54E7 /* TargetV5MigratorTests.swift */; }; /* End PBXBuildFile section */ /* Begin PBXContainerItemProxy section */ @@ -158,11 +160,13 @@ BB47C00D25547D6400EC6FB5 /* TargetOrder.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TargetOrder.swift; sourceTree = ""; }; BB47C00F25547D8300EC6FB5 /* TargetProduct.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TargetProduct.swift; sourceTree = ""; }; BB47C01125547DAE00EC6FB5 /* TargetRequest.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TargetRequest.swift; sourceTree = ""; }; + BB57390825F9AD08008352D2 /* TargetV5Migrator.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TargetV5Migrator.swift; sourceTree = ""; }; BB9C86EE255C9C90007AEF8B /* Event+TargetTests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = "Event+TargetTests.swift"; sourceTree = ""; }; BB9C8706255EF202007AEF8B /* TargetDeliveryRequest.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TargetDeliveryRequest.swift; sourceTree = ""; }; BB9C870E25623692007AEF8B /* TargetPrefetch+Internal.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "TargetPrefetch+Internal.swift"; sourceTree = ""; }; BB9C871925623723007AEF8B /* TargetOrder+Internal.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "TargetOrder+Internal.swift"; sourceTree = ""; }; BB9C871E256237F2007AEF8B /* TargetProduct+Internal.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "TargetProduct+Internal.swift"; sourceTree = ""; }; + BB9F451925F9CCB4002A54E7 /* TargetV5MigratorTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TargetV5MigratorTests.swift; sourceTree = ""; }; DBF5C7242A1D12FEEF9941D8 /* Pods-AEPTargetDemoApp.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-AEPTargetDemoApp.release.xcconfig"; path = "Target Support Files/Pods-AEPTargetDemoApp/Pods-AEPTargetDemoApp.release.xcconfig"; sourceTree = ""; }; F0D5358BA6FE1A780F4C2AA6 /* Pods-AEPTargetTests.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-AEPTargetTests.release.xcconfig"; path = "Target Support Files/Pods-AEPTargetTests/Pods-AEPTargetTests.release.xcconfig"; sourceTree = ""; }; /* End PBXFileReference section */ @@ -234,6 +238,7 @@ BB0C91492575F72200F635B8 /* TargetState.swift */, BB0C915A25775F1100F635B8 /* TargetError.swift */, 780DF564258924B70033F107 /* URL+Target.swift */, + BB57390825F9AD08008352D2 /* TargetV5Migrator.swift */, 78B36A5D25C87B3500D6D25F /* Preview */, ); path = Sources; @@ -331,6 +336,7 @@ BB1DBE8F25D22C3D00DDBA15 /* Target+PublicAPITests.swift */, BB1DBE9925D2F30400DDBA15 /* TargetTests.swift */, BB1DBEB725D30A4A00DDBA15 /* DeliveryRequestBuilderTests.swift */, + BB9F451925F9CCB4002A54E7 /* TargetV5MigratorTests.swift */, ); path = UnitTests; sourceTree = ""; @@ -635,6 +641,7 @@ BB0C915B25775F1100F635B8 /* TargetError.swift in Sources */, 7885141425532281008E6999 /* Target.swift in Sources */, BB9C871A25623723007AEF8B /* TargetOrder+Internal.swift in Sources */, + BB57390925F9AD08008352D2 /* TargetV5Migrator.swift in Sources */, 780DF56A258924C40033F107 /* TargetPreviewManager.swift in Sources */, 786C00DE25C1D95300F26D34 /* TargetPreviewManagerFloatingButtonDelegate.swift in Sources */, BB47C01225547DAE00EC6FB5 /* TargetRequest.swift in Sources */, @@ -653,6 +660,7 @@ 92BF53FB25F362E600403FCD /* TargetNetworkServiceMock.swift in Sources */, BB1DBEA125D2F33D00DDBA15 /* TargetTests.swift in Sources */, BB1DBE9525D2377600DDBA15 /* MockExtension.swift in Sources */, + BB9F451A25F9CCB4002A54E7 /* TargetV5MigratorTests.swift in Sources */, 92BF53E625F362B700403FCD /* TargetPreviewManagerTests.swift in Sources */, BB1DBE9025D22C3D00DDBA15 /* Target+PublicAPITests.swift in Sources */, BB9C86EF255C9C90007AEF8B /* Event+TargetTests.swift in Sources */, diff --git a/AEPTarget/Sources/Preview/TargetPreviewManager.swift b/AEPTarget/Sources/Preview/TargetPreviewManager.swift index 0d7ea60..d374158 100644 --- a/AEPTarget/Sources/Preview/TargetPreviewManager.swift +++ b/AEPTarget/Sources/Preview/TargetPreviewManager.swift @@ -46,8 +46,8 @@ class TargetPreviewManager: PreviewManager { typealias httpResponseConstants = HttpConnectionConstants.ResponseCodes typealias httpHeaderConstants = HttpConnectionConstants.Header - public var floatingButtonDelegate: FloatingButtonDelegate? - public var fullscreenMessageDelegate: FullscreenMessageDelegate? + public weak var floatingButtonDelegate: FloatingButtonDelegate? + public weak var fullscreenMessageDelegate: FullscreenMessageDelegate? private var urlOpeningService: URLOpening { ServiceProvider.shared.urlService diff --git a/AEPTarget/Sources/Target.swift b/AEPTarget/Sources/Target.swift index a9819f0..521c51b 100644 --- a/AEPTarget/Sources/Target.swift +++ b/AEPTarget/Sources/Target.swift @@ -40,6 +40,7 @@ public class Target: NSObject, Extension { public required init?(runtime: ExtensionRuntime) { self.runtime = runtime + TargetV5Migrator.migrate() targetState = TargetState() super.init() } diff --git a/AEPTarget/Sources/TargetConstants.swift b/AEPTarget/Sources/TargetConstants.swift index 18da479..2d15783 100644 --- a/AEPTarget/Sources/TargetConstants.swift +++ b/AEPTarget/Sources/TargetConstants.swift @@ -108,12 +108,22 @@ enum TargetConstants { } } + enum V5Migration { + static let TNT_ID = "Adobe.ADOBEMOBILE_TARGET.TNT_ID" + static let THIRD_PARTY_ID = "Adobe.ADOBEMOBILE_TARGET.THIRD_PARTY_ID" + static let EDGE_HOST = "Adobe.ADOBEMOBILE_TARGET.EDGE_HOST" + static let SESSION_ID = "Adobe.ADOBEMOBILE_TARGET.SESSION_ID" + static let SESSION_TIMESTAMP = "Adobe.ADOBEMOBILE_TARGET.SESSION_TIMESTAMP" + static let MOST_RECENT_REQUEST_TIMESTAMP = "Adobe.ADOBEMOBILE_TARGET.MOST_RECENT_REQUEST_TIMESTAMP" // TODO: it's not used in current V5 code, remove it ?? + } + enum DataStoreKeys { - static let SESSION_TIMESTAMP = "SESSION_TIMESTAMP" - static let SESSION_ID = "SESSION_ID" - static let TNT_ID = "TNT_ID" - static let EDGE_HOST = "EDGE_HOST" - static let THIRD_PARTY_ID = "THIRD_PARTY_ID" + static let SESSION_TIMESTAMP = "session.timestamp" + static let SESSION_ID = "session.id" + static let TNT_ID = "tnt.id" + static let EDGE_HOST = "edge.host" + static let THIRD_PARTY_ID = "third.party.id" + static let V5_MIGRATION_COMPLETE = "v5.migration.complete" } enum TargetRequestValue { diff --git a/AEPTarget/Sources/TargetV5Migrator.swift b/AEPTarget/Sources/TargetV5Migrator.swift new file mode 100644 index 0000000..d6a40cf --- /dev/null +++ b/AEPTarget/Sources/TargetV5Migrator.swift @@ -0,0 +1,61 @@ +/* + Copyright 2021 Adobe. All rights reserved. + This file is licensed to you under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. You may obtain a copy + of the License at http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software distributed under + the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR REPRESENTATIONS + OF ANY KIND, either express or implied. See the License for the specific language + governing permissions and limitations under the License. + */ + +import AEPServices +import Foundation + +enum TargetV5Migrator { + private static func getUserDefault() -> UserDefaults { + if let v5AppGroup = ServiceProvider.shared.namedKeyValueService.getAppGroup(), !v5AppGroup.isEmpty { + return UserDefaults(suiteName: v5AppGroup) ?? UserDefaults.standard + } + + return UserDefaults.standard + } + + static func migrate() { + /// Migrates the c++ V5 Target values into the Swift V5 Target data store + + let userDefaultV5 = getUserDefault() + let targetDataStore = NamedCollectionDataStore(name: TargetConstants.DATASTORE_NAME) + + guard targetDataStore.getBool(key: TargetConstants.DataStoreKeys.V5_MIGRATION_COMPLETE) == nil else { + return + } + + // load old values + let edgeHost = userDefaultV5.string(forKey: TargetConstants.V5Migration.EDGE_HOST) + let sessionTimeStamp = userDefaultV5.double(forKey: TargetConstants.V5Migration.SESSION_TIMESTAMP) + let sessionId = userDefaultV5.string(forKey: TargetConstants.V5Migration.SESSION_ID) + let thirdPartyId = userDefaultV5.string(forKey: TargetConstants.V5Migration.THIRD_PARTY_ID) + let tntId = userDefaultV5.string(forKey: TargetConstants.V5Migration.TNT_ID) + + // save values + targetDataStore.set(key: TargetConstants.DataStoreKeys.EDGE_HOST, value: edgeHost) + if sessionTimeStamp > 0 { + targetDataStore.set(key: TargetConstants.DataStoreKeys.SESSION_TIMESTAMP, value: sessionTimeStamp) + } + targetDataStore.set(key: TargetConstants.DataStoreKeys.SESSION_ID, value: sessionId) + targetDataStore.set(key: TargetConstants.DataStoreKeys.THIRD_PARTY_ID, value: thirdPartyId) + targetDataStore.set(key: TargetConstants.DataStoreKeys.TNT_ID, value: tntId) + + // remove old values + userDefaultV5.removeObject(forKey: TargetConstants.V5Migration.EDGE_HOST) + userDefaultV5.removeObject(forKey: TargetConstants.V5Migration.SESSION_TIMESTAMP) + userDefaultV5.removeObject(forKey: TargetConstants.V5Migration.SESSION_ID) + userDefaultV5.removeObject(forKey: TargetConstants.V5Migration.THIRD_PARTY_ID) + userDefaultV5.removeObject(forKey: TargetConstants.V5Migration.TNT_ID) + + // mark migration complete + targetDataStore.set(key: TargetConstants.DataStoreKeys.V5_MIGRATION_COMPLETE, value: true) + } +} diff --git a/AEPTarget/Tests/UnitTests/TargetTests.swift b/AEPTarget/Tests/UnitTests/TargetTests.swift index 711ca3b..52760fc 100644 --- a/AEPTarget/Tests/UnitTests/TargetTests.swift +++ b/AEPTarget/Tests/UnitTests/TargetTests.swift @@ -30,6 +30,27 @@ class TargetTests: XCTestCase { target = Target(runtime: mockRuntime) } + private func cleanUserDefaults() { + ServiceProvider.shared.namedKeyValueService.setAppGroup(nil) + for _ in 0 ... 5 { + for key in UserDefaults.standard.dictionaryRepresentation().keys { + UserDefaults.standard.removeObject(forKey: key) + } + } + } + + private func getTargetDataStore() -> NamedCollectionDataStore { + return NamedCollectionDataStore(name: "com.adobe.module.target") + } + + private func getUserDefaultV5() -> UserDefaults { + if let v5AppGroup = ServiceProvider.shared.namedKeyValueService.getAppGroup(), !v5AppGroup.isEmpty { + return UserDefaults(suiteName: v5AppGroup) ?? UserDefaults.standard + } + + return UserDefaults.standard + } + func testRegisterExtension_registersWithoutAnyErrorOrCrash() { XCTAssertNoThrow(MobileCore.registerExtensions([Target.self])) } @@ -39,6 +60,23 @@ class TargetTests: XCTestCase { XCTAssertEqual(5, mockRuntime.listeners.count) } + func testTargetInitWithDataMigration() { + let userDefaultsV5 = getUserDefaultV5() + let targetDataStore = getTargetDataStore() + cleanUserDefaults() + XCTAssertEqual(nil, targetDataStore.getBool(key: "v5.migration.complete")) + + userDefaultsV5.set("edge.host.com", forKey: "Adobe.ADOBEMOBILE_TARGET.EDGE_HOST") + userDefaultsV5.set("id_1", forKey: "Adobe.ADOBEMOBILE_TARGET.TNT_ID") + userDefaultsV5.set("id_2", forKey: "Adobe.ADOBEMOBILE_TARGET.THIRD_PARTY_ID") + userDefaultsV5.set("E621E1F8-C36C-495A-93FC-0C247A3E6E5F", forKey: "Adobe.ADOBEMOBILE_TARGET.SESSION_ID") + userDefaultsV5.set(1_615_436_587, forKey: "Adobe.ADOBEMOBILE_TARGET.SESSION_TIMESTAMP") + + let target = Target(runtime: mockRuntime) + XCTAssertEqual(true, targetDataStore.getBool(key: "v5.migration.complete")) + XCTAssertEqual("id_1", target?.targetState.tntId) + } + func testReadyForEvent() { let event = Event(name: "", type: "", source: "", data: nil) mockRuntime.simulateSharedState(extensionName: "com.adobe.module.configuration", event: event, data: (value: ["target.clientCode": "code_123"], status: .set)) diff --git a/AEPTarget/Tests/UnitTests/TargetV5MigratorTests.swift b/AEPTarget/Tests/UnitTests/TargetV5MigratorTests.swift new file mode 100644 index 0000000..b593c7f --- /dev/null +++ b/AEPTarget/Tests/UnitTests/TargetV5MigratorTests.swift @@ -0,0 +1,171 @@ +/* + Copyright 2021 Adobe. All rights reserved. + This file is licensed to you under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. You may obtain a copy + of the License at http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software distributed under + the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR REPRESENTATIONS + OF ANY KIND, either express or implied. See the License for the specific language + governing permissions and limitations under the License. + */ + +import AEPServices +@testable import AEPTarget +import Foundation +import XCTest + +class TargetV5MigratorTests: XCTestCase { + private let appGroup = "test_app_group" + + override func setUpWithError() throws { + if let userDefaults = UserDefaults(suiteName: appGroup) { + for _ in 0 ... 5 { + for key in userDefaults.dictionaryRepresentation().keys { + userDefaults.removeObject(forKey: key) + } + } + } + for _ in 0 ... 5 { + for key in UserDefaults.standard.dictionaryRepresentation().keys { + UserDefaults.standard.removeObject(forKey: key) + } + } + + ServiceProvider.shared.namedKeyValueService.setAppGroup(nil) + } + + private func getTargetDataStore() -> NamedCollectionDataStore { + return NamedCollectionDataStore(name: "com.adobe.module.target") + } + + private func getUserDefaultV5() -> UserDefaults { + if let v5AppGroup = ServiceProvider.shared.namedKeyValueService.getAppGroup(), !v5AppGroup.isEmpty { + return UserDefaults(suiteName: v5AppGroup) ?? UserDefaults.standard + } + + return UserDefaults.standard + } + + func testDataMigration() { + let userDefaultsV5 = getUserDefaultV5() + let targetDataStore = getTargetDataStore() + XCTAssertEqual(nil, targetDataStore.getBool(key: "v5.migration.complete")) + + userDefaultsV5.set("edge.host.com", forKey: "Adobe.ADOBEMOBILE_TARGET.EDGE_HOST") + userDefaultsV5.set("id_1", forKey: "Adobe.ADOBEMOBILE_TARGET.TNT_ID") + userDefaultsV5.set("id_2", forKey: "Adobe.ADOBEMOBILE_TARGET.THIRD_PARTY_ID") + userDefaultsV5.set("E621E1F8-C36C-495A-93FC-0C247A3E6E5F", forKey: "Adobe.ADOBEMOBILE_TARGET.SESSION_ID") + userDefaultsV5.set(1_615_436_587, forKey: "Adobe.ADOBEMOBILE_TARGET.SESSION_TIMESTAMP") + TargetV5Migrator.migrate() + + guard userDefaultsV5.object(forKey: "Adobe.ADOBEMOBILE_TARGET.EDGE_HOST") == nil, + userDefaultsV5.object(forKey: "Adobe.ADOBEMOBILE_TARGET.TNT_ID") == nil, + userDefaultsV5.object(forKey: "Adobe.ADOBEMOBILE_TARGET.THIRD_PARTY_ID") == nil, + userDefaultsV5.object(forKey: "Adobe.ADOBEMOBILE_TARGET.SESSION_ID") == nil, + userDefaultsV5.object(forKey: "Adobe.ADOBEMOBILE_TARGET.SESSION_TIMESTAMP") == nil + else { + XCTFail() + return + } + XCTAssertEqual("edge.host.com", targetDataStore.getString(key: "edge.host")) + XCTAssertEqual("id_1", targetDataStore.getString(key: "tnt.id")) + XCTAssertEqual("id_2", targetDataStore.getString(key: "third.party.id")) + XCTAssertEqual("E621E1F8-C36C-495A-93FC-0C247A3E6E5F", targetDataStore.getString(key: "session.id")) + XCTAssertEqual(1_615_436_587, targetDataStore.getDouble(key: "session.timestamp")) + XCTAssertEqual(true, targetDataStore.getBool(key: "v5.migration.complete")) + } + + func testDataMigrationPartial() { + let userDefaultsV5 = getUserDefaultV5() + let targetDataStore = getTargetDataStore() + XCTAssertEqual(nil, targetDataStore.getBool(key: "v5.migration.complete")) + + userDefaultsV5.set("edge.host.com", forKey: "Adobe.ADOBEMOBILE_TARGET.EDGE_HOST") + userDefaultsV5.set("id_1", forKey: "Adobe.ADOBEMOBILE_TARGET.TNT_ID") + userDefaultsV5.set("id_2", forKey: "Adobe.ADOBEMOBILE_TARGET.THIRD_PARTY_ID") + + TargetV5Migrator.migrate() + + guard userDefaultsV5.object(forKey: "Adobe.ADOBEMOBILE_TARGET.EDGE_HOST") == nil, + userDefaultsV5.object(forKey: "Adobe.ADOBEMOBILE_TARGET.TNT_ID") == nil, + userDefaultsV5.object(forKey: "Adobe.ADOBEMOBILE_TARGET.THIRD_PARTY_ID") == nil, + userDefaultsV5.object(forKey: "Adobe.ADOBEMOBILE_TARGET.SESSION_ID") == nil, + userDefaultsV5.object(forKey: "Adobe.ADOBEMOBILE_TARGET.SESSION_TIMESTAMP") == nil + else { + XCTFail() + return + } + XCTAssertEqual("edge.host.com", targetDataStore.getString(key: "edge.host")) + XCTAssertEqual("id_1", targetDataStore.getString(key: "tnt.id")) + XCTAssertEqual("id_2", targetDataStore.getString(key: "third.party.id")) + XCTAssertEqual(nil, targetDataStore.getString(key: "session.id")) + XCTAssertEqual(nil, targetDataStore.getDouble(key: "session.timestamp")) + XCTAssertEqual(true, targetDataStore.getBool(key: "v5.migration.complete")) + } + + func testDataMigrationInAppGroup() { + ServiceProvider.shared.namedKeyValueService.setAppGroup(appGroup) + let userDefaultsV5 = getUserDefaultV5() + let targetDataStore = getTargetDataStore() + XCTAssertEqual(nil, targetDataStore.getBool(key: "v5.migration.complete")) + + userDefaultsV5.set("edge.host.com", forKey: "Adobe.ADOBEMOBILE_TARGET.EDGE_HOST") + userDefaultsV5.set("id_1", forKey: "Adobe.ADOBEMOBILE_TARGET.TNT_ID") + userDefaultsV5.set("id_2", forKey: "Adobe.ADOBEMOBILE_TARGET.THIRD_PARTY_ID") + userDefaultsV5.set("E621E1F8-C36C-495A-93FC-0C247A3E6E5F", forKey: "Adobe.ADOBEMOBILE_TARGET.SESSION_ID") + userDefaultsV5.set(1_615_436_587, forKey: "Adobe.ADOBEMOBILE_TARGET.SESSION_TIMESTAMP") + TargetV5Migrator.migrate() + + guard userDefaultsV5.object(forKey: "Adobe.ADOBEMOBILE_TARGET.EDGE_HOST") == nil, + userDefaultsV5.object(forKey: "Adobe.ADOBEMOBILE_TARGET.TNT_ID") == nil, + userDefaultsV5.object(forKey: "Adobe.ADOBEMOBILE_TARGET.THIRD_PARTY_ID") == nil, + userDefaultsV5.object(forKey: "Adobe.ADOBEMOBILE_TARGET.SESSION_ID") == nil, + userDefaultsV5.object(forKey: "Adobe.ADOBEMOBILE_TARGET.SESSION_TIMESTAMP") == nil + else { + XCTFail() + return + } + XCTAssertEqual("edge.host.com", targetDataStore.getString(key: "edge.host")) + XCTAssertEqual("id_1", targetDataStore.getString(key: "tnt.id")) + XCTAssertEqual("id_2", targetDataStore.getString(key: "third.party.id")) + XCTAssertEqual("E621E1F8-C36C-495A-93FC-0C247A3E6E5F", targetDataStore.getString(key: "session.id")) + XCTAssertEqual(1_615_436_587, targetDataStore.getDouble(key: "session.timestamp")) + XCTAssertEqual(true, targetDataStore.getBool(key: "v5.migration.complete")) + } + + func testDataMigrationInNewAppGroup() { + let targetDataStore = getTargetDataStore() + UserDefaults.standard.set("edge.host.com", forKey: "Adobe.ADOBEMOBILE_TARGET.EDGE_HOST") + UserDefaults.standard.set("id_1", forKey: "Adobe.ADOBEMOBILE_TARGET.TNT_ID") + UserDefaults.standard.set("id_2", forKey: "Adobe.ADOBEMOBILE_TARGET.THIRD_PARTY_ID") + UserDefaults.standard.set("E621E1F8-C36C-495A-93FC-0C247A3E6E5F", forKey: "Adobe.ADOBEMOBILE_TARGET.SESSION_ID") + UserDefaults.standard.set(1_615_436_587, forKey: "Adobe.ADOBEMOBILE_TARGET.SESSION_TIMESTAMP") + + ServiceProvider.shared.namedKeyValueService.setAppGroup("test_app_group") + XCTAssertEqual(nil, targetDataStore.getBool(key: "v5.migration.complete")) + + TargetV5Migrator.migrate() + + guard UserDefaults.standard.object(forKey: "Adobe.ADOBEMOBILE_TARGET.EDGE_HOST") != nil, + UserDefaults.standard.object(forKey: "Adobe.ADOBEMOBILE_TARGET.TNT_ID") != nil, + UserDefaults.standard.object(forKey: "Adobe.ADOBEMOBILE_TARGET.THIRD_PARTY_ID") != nil, + UserDefaults.standard.object(forKey: "Adobe.ADOBEMOBILE_TARGET.SESSION_ID") != nil, + UserDefaults.standard.double(forKey: "Adobe.ADOBEMOBILE_TARGET.SESSION_TIMESTAMP") > 0 + else { + XCTFail() + return + } + + guard targetDataStore.getString(key: "edge.host") == nil, + targetDataStore.getString(key: "tnt.id") == nil, + targetDataStore.getString(key: "third.party.id") == nil, + targetDataStore.getString(key: "session.id") == nil, + targetDataStore.getDouble(key: "session.timestamp") == nil + else { + XCTFail() + return + } + XCTAssertEqual(true, targetDataStore.getBool(key: "v5.migration.complete")) + } +} diff --git a/Podfile.lock b/Podfile.lock index 9d19f51..fe78677 100644 --- a/Podfile.lock +++ b/Podfile.lock @@ -41,22 +41,22 @@ EXTERNAL SOURCES: CHECKOUT OPTIONS: AEPCore: - :commit: 7ab4a04ca9855298261e5e18f7a9d315d9da6477 + :commit: 763fc146314a9b4dad73e27361de74e46dfe3b64 :git: https://github.com/adobe/aepsdk-core-ios.git AEPIdentity: - :commit: 7ab4a04ca9855298261e5e18f7a9d315d9da6477 + :commit: 763fc146314a9b4dad73e27361de74e46dfe3b64 :git: https://github.com/adobe/aepsdk-core-ios.git AEPLifecycle: - :commit: 7ab4a04ca9855298261e5e18f7a9d315d9da6477 + :commit: 763fc146314a9b4dad73e27361de74e46dfe3b64 :git: https://github.com/adobe/aepsdk-core-ios.git AEPRulesEngine: :commit: 1e270654b330b9f07a6b1ec374e686f2e631e039 :git: https://github.com/adobe/aepsdk-rulesengine-ios.git AEPServices: - :commit: 7ab4a04ca9855298261e5e18f7a9d315d9da6477 + :commit: 763fc146314a9b4dad73e27361de74e46dfe3b64 :git: https://github.com/adobe/aepsdk-core-ios.git AEPSignal: - :commit: 7ab4a04ca9855298261e5e18f7a9d315d9da6477 + :commit: 763fc146314a9b4dad73e27361de74e46dfe3b64 :git: https://github.com/adobe/aepsdk-core-ios.git SPEC CHECKSUMS: From 64bec417138b3f4bd5d96772b2aa0882bf2a4cd2 Mon Sep 17 00:00:00 2001 From: Yansong Date: Thu, 11 Mar 2021 13:42:11 -0600 Subject: [PATCH 2/8] no message --- .../Sources/DeliveryRequestBuilder.swift | 3 +- AEPTarget/Sources/Target.swift | 3 +- AEPTarget/Sources/TargetV5Migrator.swift | 8 ++-- .../UnitTests/TargetV5MigratorTests.swift | 43 +++++++++++++++++-- 4 files changed, 45 insertions(+), 12 deletions(-) diff --git a/AEPTarget/Sources/DeliveryRequestBuilder.swift b/AEPTarget/Sources/DeliveryRequestBuilder.swift index bbdd10c..ae7e86e 100644 --- a/AEPTarget/Sources/DeliveryRequestBuilder.swift +++ b/AEPTarget/Sources/DeliveryRequestBuilder.swift @@ -149,8 +149,7 @@ enum DeliveryRequestBuilder { for visitorId in visitorIds { if let id = visitorId[TargetConstants.Identity.SharedState.Keys.VISITORID_ID] as? String, let code = visitorId[TargetConstants.Identity.SharedState.Keys.VISITORID_TYPE] as? String, - let authenticatedState = visitorId[TargetConstants.Identity.SharedState.Keys.VISITORID_AUTHENTICATION_STATE] as? Int - { + let authenticatedState = visitorId[TargetConstants.Identity.SharedState.Keys.VISITORID_AUTHENTICATION_STATE] as? Int { if customerIds == nil { customerIds = [CustomerID]() } customerIds?.append(CustomerID(id: id, integrationCode: code, authenticatedState: AuthenticatedState.from(state: authenticatedState))) } diff --git a/AEPTarget/Sources/Target.swift b/AEPTarget/Sources/Target.swift index 521c51b..0c9e5bd 100644 --- a/AEPTarget/Sources/Target.swift +++ b/AEPTarget/Sources/Target.swift @@ -512,8 +512,7 @@ public class Target: NSObject, Extension { lifecycleData: [String: Any]? = nil, identityData: [String: Any]? = nil, propertyToken: String? = nil, - completionHandler: ((HttpConnection) -> Void)?) -> String? - { + completionHandler: ((HttpConnection) -> Void)?) -> String? { let tntId = targetState.tntId let thirdPartyId = targetState.thirdPartyId let environmentId: Int64 = configData[TargetConstants.Configuration.SharedState.Keys.TARGET_ENVIRONMENT_ID] as? Int64 ?? 0 diff --git a/AEPTarget/Sources/TargetV5Migrator.swift b/AEPTarget/Sources/TargetV5Migrator.swift index d6a40cf..70e7317 100644 --- a/AEPTarget/Sources/TargetV5Migrator.swift +++ b/AEPTarget/Sources/TargetV5Migrator.swift @@ -13,8 +13,9 @@ import AEPServices import Foundation +/// Provides functionality for migrating stored data from c++ V5 to Swift V5 enum TargetV5Migrator { - private static func getUserDefault() -> UserDefaults { + private static func getUserDefaultV5() -> UserDefaults { if let v5AppGroup = ServiceProvider.shared.namedKeyValueService.getAppGroup(), !v5AppGroup.isEmpty { return UserDefaults(suiteName: v5AppGroup) ?? UserDefaults.standard } @@ -22,10 +23,9 @@ enum TargetV5Migrator { return UserDefaults.standard } + /// Migrates the c++ V5 Target values into the Swift V5 Target data store static func migrate() { - /// Migrates the c++ V5 Target values into the Swift V5 Target data store - - let userDefaultV5 = getUserDefault() + let userDefaultV5 = getUserDefaultV5() let targetDataStore = NamedCollectionDataStore(name: TargetConstants.DATASTORE_NAME) guard targetDataStore.getBool(key: TargetConstants.DataStoreKeys.V5_MIGRATION_COMPLETE) == nil else { diff --git a/AEPTarget/Tests/UnitTests/TargetV5MigratorTests.swift b/AEPTarget/Tests/UnitTests/TargetV5MigratorTests.swift index b593c7f..8e09ac8 100644 --- a/AEPTarget/Tests/UnitTests/TargetV5MigratorTests.swift +++ b/AEPTarget/Tests/UnitTests/TargetV5MigratorTests.swift @@ -47,18 +47,40 @@ class TargetV5MigratorTests: XCTestCase { return UserDefaults.standard } + /// No V5 data exists + func testNoV5Data() { + let targetDataStore = getTargetDataStore() + XCTAssertEqual(nil, targetDataStore.getBool(key: "v5.migration.complete")) + + TargetV5Migrator.migrate() + + // verify: didn't do data migration and no data was stored with default values + guard targetDataStore.getString(key: "edge.host") == nil, + targetDataStore.getString(key: "tnt.id") == nil, + targetDataStore.getString(key: "third.party.id") == nil, + targetDataStore.getString(key: "session.id") == nil, + targetDataStore.getDouble(key: "session.timestamp") == nil + else { + XCTFail() + return + } + } + + /// Migrates all of the supported V5 data keys to the new data keys func testDataMigration() { let userDefaultsV5 = getUserDefaultV5() let targetDataStore = getTargetDataStore() XCTAssertEqual(nil, targetDataStore.getBool(key: "v5.migration.complete")) - + // V5 Target data with old keys userDefaultsV5.set("edge.host.com", forKey: "Adobe.ADOBEMOBILE_TARGET.EDGE_HOST") userDefaultsV5.set("id_1", forKey: "Adobe.ADOBEMOBILE_TARGET.TNT_ID") userDefaultsV5.set("id_2", forKey: "Adobe.ADOBEMOBILE_TARGET.THIRD_PARTY_ID") userDefaultsV5.set("E621E1F8-C36C-495A-93FC-0C247A3E6E5F", forKey: "Adobe.ADOBEMOBILE_TARGET.SESSION_ID") userDefaultsV5.set(1_615_436_587, forKey: "Adobe.ADOBEMOBILE_TARGET.SESSION_TIMESTAMP") + TargetV5Migrator.migrate() + // V5 Target data keys should be deleted guard userDefaultsV5.object(forKey: "Adobe.ADOBEMOBILE_TARGET.EDGE_HOST") == nil, userDefaultsV5.object(forKey: "Adobe.ADOBEMOBILE_TARGET.TNT_ID") == nil, userDefaultsV5.object(forKey: "Adobe.ADOBEMOBILE_TARGET.THIRD_PARTY_ID") == nil, @@ -68,6 +90,7 @@ class TargetV5MigratorTests: XCTestCase { XCTFail() return } + // verify: Target data with new keys XCTAssertEqual("edge.host.com", targetDataStore.getString(key: "edge.host")) XCTAssertEqual("id_1", targetDataStore.getString(key: "tnt.id")) XCTAssertEqual("id_2", targetDataStore.getString(key: "third.party.id")) @@ -76,17 +99,19 @@ class TargetV5MigratorTests: XCTestCase { XCTAssertEqual(true, targetDataStore.getBool(key: "v5.migration.complete")) } + /// Migrates part of the supported V5 data keys to the new data keys func testDataMigrationPartial() { let userDefaultsV5 = getUserDefaultV5() let targetDataStore = getTargetDataStore() XCTAssertEqual(nil, targetDataStore.getBool(key: "v5.migration.complete")) - + // V5 Target data with old keys userDefaultsV5.set("edge.host.com", forKey: "Adobe.ADOBEMOBILE_TARGET.EDGE_HOST") userDefaultsV5.set("id_1", forKey: "Adobe.ADOBEMOBILE_TARGET.TNT_ID") userDefaultsV5.set("id_2", forKey: "Adobe.ADOBEMOBILE_TARGET.THIRD_PARTY_ID") TargetV5Migrator.migrate() + // V5 Target data keys should be deleted guard userDefaultsV5.object(forKey: "Adobe.ADOBEMOBILE_TARGET.EDGE_HOST") == nil, userDefaultsV5.object(forKey: "Adobe.ADOBEMOBILE_TARGET.TNT_ID") == nil, userDefaultsV5.object(forKey: "Adobe.ADOBEMOBILE_TARGET.THIRD_PARTY_ID") == nil, @@ -96,6 +121,8 @@ class TargetV5MigratorTests: XCTestCase { XCTFail() return } + + // verify: Target data with new keys XCTAssertEqual("edge.host.com", targetDataStore.getString(key: "edge.host")) XCTAssertEqual("id_1", targetDataStore.getString(key: "tnt.id")) XCTAssertEqual("id_2", targetDataStore.getString(key: "third.party.id")) @@ -104,12 +131,14 @@ class TargetV5MigratorTests: XCTestCase { XCTAssertEqual(true, targetDataStore.getBool(key: "v5.migration.complete")) } + /// Migrate V5 data if using `app group` in the SDK func testDataMigrationInAppGroup() { ServiceProvider.shared.namedKeyValueService.setAppGroup(appGroup) let userDefaultsV5 = getUserDefaultV5() let targetDataStore = getTargetDataStore() XCTAssertEqual(nil, targetDataStore.getBool(key: "v5.migration.complete")) + // V5 Target data with old keys userDefaultsV5.set("edge.host.com", forKey: "Adobe.ADOBEMOBILE_TARGET.EDGE_HOST") userDefaultsV5.set("id_1", forKey: "Adobe.ADOBEMOBILE_TARGET.TNT_ID") userDefaultsV5.set("id_2", forKey: "Adobe.ADOBEMOBILE_TARGET.THIRD_PARTY_ID") @@ -117,6 +146,7 @@ class TargetV5MigratorTests: XCTestCase { userDefaultsV5.set(1_615_436_587, forKey: "Adobe.ADOBEMOBILE_TARGET.SESSION_TIMESTAMP") TargetV5Migrator.migrate() + // V5 Target data keys should be deleted guard userDefaultsV5.object(forKey: "Adobe.ADOBEMOBILE_TARGET.EDGE_HOST") == nil, userDefaultsV5.object(forKey: "Adobe.ADOBEMOBILE_TARGET.TNT_ID") == nil, userDefaultsV5.object(forKey: "Adobe.ADOBEMOBILE_TARGET.THIRD_PARTY_ID") == nil, @@ -126,6 +156,7 @@ class TargetV5MigratorTests: XCTestCase { XCTFail() return } + // verify: Target data with new keys XCTAssertEqual("edge.host.com", targetDataStore.getString(key: "edge.host")) XCTAssertEqual("id_1", targetDataStore.getString(key: "tnt.id")) XCTAssertEqual("id_2", targetDataStore.getString(key: "third.party.id")) @@ -134,19 +165,23 @@ class TargetV5MigratorTests: XCTestCase { XCTAssertEqual(true, targetDataStore.getBool(key: "v5.migration.complete")) } + /// Migrate V5 data if using a new `app group` in the SDK func testDataMigrationInNewAppGroup() { let targetDataStore = getTargetDataStore() + XCTAssertEqual(nil, targetDataStore.getBool(key: "v5.migration.complete")) + + // V5 Target data with old keys UserDefaults.standard.set("edge.host.com", forKey: "Adobe.ADOBEMOBILE_TARGET.EDGE_HOST") UserDefaults.standard.set("id_1", forKey: "Adobe.ADOBEMOBILE_TARGET.TNT_ID") UserDefaults.standard.set("id_2", forKey: "Adobe.ADOBEMOBILE_TARGET.THIRD_PARTY_ID") UserDefaults.standard.set("E621E1F8-C36C-495A-93FC-0C247A3E6E5F", forKey: "Adobe.ADOBEMOBILE_TARGET.SESSION_ID") UserDefaults.standard.set(1_615_436_587, forKey: "Adobe.ADOBEMOBILE_TARGET.SESSION_TIMESTAMP") + // set a `app group` value and do data migration ServiceProvider.shared.namedKeyValueService.setAppGroup("test_app_group") - XCTAssertEqual(nil, targetDataStore.getBool(key: "v5.migration.complete")) - TargetV5Migrator.migrate() + // verify: V5 Target data will no be migrated guard UserDefaults.standard.object(forKey: "Adobe.ADOBEMOBILE_TARGET.EDGE_HOST") != nil, UserDefaults.standard.object(forKey: "Adobe.ADOBEMOBILE_TARGET.TNT_ID") != nil, UserDefaults.standard.object(forKey: "Adobe.ADOBEMOBILE_TARGET.THIRD_PARTY_ID") != nil, From 44a79b37af9c41a7b7cc90fcdaed9e33746d073b Mon Sep 17 00:00:00 2001 From: Yansong Date: Tue, 23 Mar 2021 18:36:21 -0500 Subject: [PATCH 3/8] data migration for V4 --- AEPTarget.xcodeproj/project.pbxproj | 8 + AEPTarget/Sources/Target.swift | 1 + AEPTarget/Sources/TargetConstants.swift | 7 + AEPTarget/Sources/TargetV4Migrator.swift | 53 +++++ AEPTarget/Sources/TargetV5Migrator.swift | 24 ++- AEPTarget/Tests/UnitTests/TargetTests.swift | 28 ++- .../UnitTests/TargetV4MigratorTests.swift | 192 ++++++++++++++++++ 7 files changed, 298 insertions(+), 15 deletions(-) create mode 100644 AEPTarget/Sources/TargetV4Migrator.swift create mode 100644 AEPTarget/Tests/UnitTests/TargetV4MigratorTests.swift diff --git a/AEPTarget.xcodeproj/project.pbxproj b/AEPTarget.xcodeproj/project.pbxproj index 8a592dc..ef5f5ff 100644 --- a/AEPTarget.xcodeproj/project.pbxproj +++ b/AEPTarget.xcodeproj/project.pbxproj @@ -58,6 +58,8 @@ BB0C915B25775F1100F635B8 /* TargetError.swift in Sources */ = {isa = PBXBuildFile; fileRef = BB0C915A25775F1100F635B8 /* TargetError.swift */; }; BB1CE6B0260A76E0000BDEB8 /* TargetV5Migrator.swift in Sources */ = {isa = PBXBuildFile; fileRef = BB1CE6AF260A76E0000BDEB8 /* TargetV5Migrator.swift */; }; BB1CE6B6260A76F1000BDEB8 /* TargetV5MigratorTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = BB1CE6B5260A76F1000BDEB8 /* TargetV5MigratorTests.swift */; }; + BB1CE6C0260AA7B5000BDEB8 /* TargetV4Migrator.swift in Sources */ = {isa = PBXBuildFile; fileRef = BB1CE6BF260AA7B5000BDEB8 /* TargetV4Migrator.swift */; }; + BB1CE6CA260AAB4B000BDEB8 /* TargetV4MigratorTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = BB1CE6C9260AAB4B000BDEB8 /* TargetV4MigratorTests.swift */; }; BB1DBE9025D22C3D00DDBA15 /* Target+PublicAPITests.swift in Sources */ = {isa = PBXBuildFile; fileRef = BB1DBE8F25D22C3D00DDBA15 /* Target+PublicAPITests.swift */; }; BB1DBEA125D2F33D00DDBA15 /* TargetTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = BB1DBE9925D2F30400DDBA15 /* TargetTests.swift */; }; BB1DBEB825D30A4A00DDBA15 /* DeliveryRequestBuilderTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = BB1DBEB725D30A4A00DDBA15 /* DeliveryRequestBuilderTests.swift */; }; @@ -176,6 +178,8 @@ BB0C915A25775F1100F635B8 /* TargetError.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TargetError.swift; sourceTree = ""; }; BB1CE6AF260A76E0000BDEB8 /* TargetV5Migrator.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = TargetV5Migrator.swift; sourceTree = ""; }; BB1CE6B5260A76F1000BDEB8 /* TargetV5MigratorTests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = TargetV5MigratorTests.swift; sourceTree = ""; }; + BB1CE6BF260AA7B5000BDEB8 /* TargetV4Migrator.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TargetV4Migrator.swift; sourceTree = ""; }; + BB1CE6C9260AAB4B000BDEB8 /* TargetV4MigratorTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TargetV4MigratorTests.swift; sourceTree = ""; }; BB1DBE8F25D22C3D00DDBA15 /* Target+PublicAPITests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "Target+PublicAPITests.swift"; sourceTree = ""; }; BB1DBE9925D2F30400DDBA15 /* TargetTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TargetTests.swift; sourceTree = ""; }; BB1DBEB725D30A4A00DDBA15 /* DeliveryRequestBuilderTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = DeliveryRequestBuilderTests.swift; sourceTree = ""; }; @@ -282,6 +286,7 @@ 92AE6D0A25D8E31700F46C59 /* TargetDeliveryRequestBuilder.swift */, BB1E55A02575BC4B006632E4 /* TargetDeliveryResponse.swift */, BB1CE6AF260A76E0000BDEB8 /* TargetV5Migrator.swift */, + BB1CE6BF260AA7B5000BDEB8 /* TargetV4Migrator.swift */, BB0C91492575F72200F635B8 /* TargetState.swift */, BB0C915A25775F1100F635B8 /* TargetError.swift */, 780DF564258924B70033F107 /* URL+Target.swift */, @@ -405,6 +410,7 @@ BB1DBE9925D2F30400DDBA15 /* TargetTests.swift */, BB1DBEB725D30A4A00DDBA15 /* DeliveryRequestBuilderTests.swift */, BB1CE6B5260A76F1000BDEB8 /* TargetV5MigratorTests.swift */, + BB1CE6C9260AAB4B000BDEB8 /* TargetV4MigratorTests.swift */, ); path = UnitTests; sourceTree = ""; @@ -798,6 +804,7 @@ 780DF56A258924C40033F107 /* TargetPreviewManager.swift in Sources */, 786C00DE25C1D95300F26D34 /* TargetPreviewManagerFloatingButtonDelegate.swift in Sources */, BB47C01225547DAE00EC6FB5 /* TargetRequest.swift in Sources */, + BB1CE6C0260AA7B5000BDEB8 /* TargetV4Migrator.swift in Sources */, BB9C870F25623692007AEF8B /* TargetPrefetch+Internal.swift in Sources */, BB1E55892574A35A006632E4 /* TargetParameters+Internal.swift in Sources */, 7885141E255322D9008E6999 /* Event+Target.swift in Sources */, @@ -814,6 +821,7 @@ BB8FF0EE2602A705006C80D9 /* TargetIntegrationTests.swift in Sources */, BB1DBEA125D2F33D00DDBA15 /* TargetTests.swift in Sources */, 92BF53E625F362B700403FCD /* TargetPreviewManagerTests.swift in Sources */, + BB1CE6CA260AAB4B000BDEB8 /* TargetV4MigratorTests.swift in Sources */, BB1DBE9025D22C3D00DDBA15 /* Target+PublicAPITests.swift in Sources */, BB9C86EF255C9C90007AEF8B /* Event+TargetTests.swift in Sources */, BB8FF1262602A72C006C80D9 /* MockUIService.swift in Sources */, diff --git a/AEPTarget/Sources/Target.swift b/AEPTarget/Sources/Target.swift index 28f8c5b..9db9cbd 100644 --- a/AEPTarget/Sources/Target.swift +++ b/AEPTarget/Sources/Target.swift @@ -41,6 +41,7 @@ public class Target: NSObject, Extension { public required init?(runtime: ExtensionRuntime) { self.runtime = runtime TargetV5Migrator.migrate() + TargetV4Migrator.migrate() targetState = TargetState() super.init() } diff --git a/AEPTarget/Sources/TargetConstants.swift b/AEPTarget/Sources/TargetConstants.swift index 518a9df..ac78607 100644 --- a/AEPTarget/Sources/TargetConstants.swift +++ b/AEPTarget/Sources/TargetConstants.swift @@ -127,6 +127,12 @@ enum TargetConstants { static let SESSION_TIMESTAMP = "Adobe.ADOBEMOBILE_TARGET.SESSION_TIMESTAMP" } + enum V4Migration { + static let TNT_ID = "ADBMOBILE_TARGET_TNT_ID" + static let THIRD_PARTY_ID = "ADBMOBILE_TARGET_3RD_PARTY_ID" + static let V4_DATA_MIGRATED = "ADBMOBILE_TARGET_DATA_MIGRATED" + } + enum DataStoreKeys { static let SESSION_TIMESTAMP = "session.timestamp" static let SESSION_ID = "session.id" @@ -134,6 +140,7 @@ enum TargetConstants { static let EDGE_HOST = "edge.host" static let THIRD_PARTY_ID = "thirdparty.id" static let V5_MIGRATION_COMPLETE = "v5.migration.complete" + static let V4_MIGRATION_COMPLETE = "v4.migration.complete" } enum TargetRequestValue { diff --git a/AEPTarget/Sources/TargetV4Migrator.swift b/AEPTarget/Sources/TargetV4Migrator.swift new file mode 100644 index 0000000..0b62b21 --- /dev/null +++ b/AEPTarget/Sources/TargetV4Migrator.swift @@ -0,0 +1,53 @@ +/* + Copyright 2021 Adobe. All rights reserved. + This file is licensed to you under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. You may obtain a copy + of the License at http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software distributed under + the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR REPRESENTATIONS + OF ANY KIND, either express or implied. See the License for the specific language + governing permissions and limitations under the License. + */ + +import AEPServices +import Foundation + +/// Provides functionality for migrating stored data from V4 to Swift V5 +enum TargetV4Migrator { + private static var userDefaultV4: UserDefaults { + if let v4AppGroup = ServiceProvider.shared.namedKeyValueService.getAppGroup(), !v4AppGroup.isEmpty { + return UserDefaults(suiteName: v4AppGroup) ?? UserDefaults.standard + } + + return UserDefaults.standard + } + + /// Migrates the V4 Target values into the Swift V5 Target data store + static func migrate() { + let targetDataStore = NamedCollectionDataStore(name: TargetConstants.DATASTORE_NAME) + + guard targetDataStore.getBool(key: TargetConstants.DataStoreKeys.V4_MIGRATION_COMPLETE) == nil else { + return + } + + // save values + if let thirdPartyId = userDefaultV4.string(forKey: TargetConstants.V4Migration.THIRD_PARTY_ID), + targetDataStore.getString(key: TargetConstants.DataStoreKeys.THIRD_PARTY_ID) == nil + { + targetDataStore.set(key: TargetConstants.DataStoreKeys.THIRD_PARTY_ID, value: thirdPartyId) + } + if let tntId = userDefaultV4.string(forKey: TargetConstants.V4Migration.TNT_ID), + targetDataStore.getString(key: TargetConstants.DataStoreKeys.TNT_ID) == nil + { + targetDataStore.set(key: TargetConstants.DataStoreKeys.TNT_ID, value: tntId) + } + + // remove old values + userDefaultV4.removeObject(forKey: TargetConstants.V4Migration.THIRD_PARTY_ID) + userDefaultV4.removeObject(forKey: TargetConstants.V4Migration.TNT_ID) + userDefaultV4.removeObject(forKey: TargetConstants.V4Migration.V4_DATA_MIGRATED) + + targetDataStore.set(key: TargetConstants.DataStoreKeys.V4_MIGRATION_COMPLETE, value: true) + } +} diff --git a/AEPTarget/Sources/TargetV5Migrator.swift b/AEPTarget/Sources/TargetV5Migrator.swift index 58255bc..d6fd000 100644 --- a/AEPTarget/Sources/TargetV5Migrator.swift +++ b/AEPTarget/Sources/TargetV5Migrator.swift @@ -32,21 +32,23 @@ enum TargetV5Migrator { return } - // load old values - let edgeHost = userDefaultV5.string(forKey: TargetConstants.V5Migration.EDGE_HOST) - let sessionTimestamp = userDefaultV5.integer(forKey: TargetConstants.V5Migration.SESSION_TIMESTAMP) - let sessionId = userDefaultV5.string(forKey: TargetConstants.V5Migration.SESSION_ID) - let thirdPartyId = userDefaultV5.string(forKey: TargetConstants.V5Migration.THIRD_PARTY_ID) - let tntId = userDefaultV5.string(forKey: TargetConstants.V5Migration.TNT_ID) - // save values - targetDataStore.set(key: TargetConstants.DataStoreKeys.EDGE_HOST, value: edgeHost) + if let edgeHost = userDefaultV5.string(forKey: TargetConstants.V5Migration.EDGE_HOST) { + targetDataStore.set(key: TargetConstants.DataStoreKeys.EDGE_HOST, value: edgeHost) + } + let sessionTimestamp = userDefaultV5.integer(forKey: TargetConstants.V5Migration.SESSION_TIMESTAMP) if sessionTimestamp > 0 { targetDataStore.set(key: TargetConstants.DataStoreKeys.SESSION_TIMESTAMP, value: sessionTimestamp) } - targetDataStore.set(key: TargetConstants.DataStoreKeys.SESSION_ID, value: sessionId) - targetDataStore.set(key: TargetConstants.DataStoreKeys.THIRD_PARTY_ID, value: thirdPartyId) - targetDataStore.set(key: TargetConstants.DataStoreKeys.TNT_ID, value: tntId) + if let sessionId = userDefaultV5.string(forKey: TargetConstants.V5Migration.SESSION_ID) { + targetDataStore.set(key: TargetConstants.DataStoreKeys.SESSION_ID, value: sessionId) + } + if let thirdPartyId = userDefaultV5.string(forKey: TargetConstants.V5Migration.THIRD_PARTY_ID) { + targetDataStore.set(key: TargetConstants.DataStoreKeys.THIRD_PARTY_ID, value: thirdPartyId) + } + if let tntId = userDefaultV5.string(forKey: TargetConstants.V5Migration.TNT_ID) { + targetDataStore.set(key: TargetConstants.DataStoreKeys.TNT_ID, value: tntId) + } // remove old values userDefaultV5.removeObject(forKey: TargetConstants.V5Migration.EDGE_HOST) diff --git a/AEPTarget/Tests/UnitTests/TargetTests.swift b/AEPTarget/Tests/UnitTests/TargetTests.swift index 137c85e..cb1c1bb 100644 --- a/AEPTarget/Tests/UnitTests/TargetTests.swift +++ b/AEPTarget/Tests/UnitTests/TargetTests.swift @@ -32,7 +32,7 @@ class TargetTests: XCTestCase { private func cleanUserDefaults() { for _ in 0 ... 5 { - for key in getUserDefaultsV5().dictionaryRepresentation().keys { + for key in getUserDefaults().dictionaryRepresentation().keys { UserDefaults.standard.removeObject(forKey: key) } } @@ -48,7 +48,7 @@ class TargetTests: XCTestCase { return NamedCollectionDataStore(name: "com.adobe.module.target") } - private func getUserDefaultsV5() -> UserDefaults { + private func getUserDefaults() -> UserDefaults { if let v5AppGroup = ServiceProvider.shared.namedKeyValueService.getAppGroup(), !v5AppGroup.isEmpty { return UserDefaults(suiteName: v5AppGroup) ?? UserDefaults.standard } @@ -65,11 +65,12 @@ class TargetTests: XCTestCase { XCTAssertEqual(5, mockRuntime.listeners.count) } - func testTargetInitWithDataMigration() { - let userDefaultsV5 = getUserDefaultsV5() + func testTargetInitWithDataMigrationFromV5() { + let userDefaultsV5 = getUserDefaults() let targetDataStore = getTargetDataStore() cleanUserDefaults() XCTAssertEqual(nil, targetDataStore.getBool(key: "v5.migration.complete")) + XCTAssertEqual(nil, targetDataStore.getBool(key: "v4.migration.complete")) let timestamp = Date().getUnixTimeInSeconds() userDefaultsV5.set("edge.host.com", forKey: "Adobe.ADOBEMOBILE_TARGET.EDGE_HOST") @@ -80,6 +81,7 @@ class TargetTests: XCTestCase { let target = Target(runtime: mockRuntime) XCTAssertEqual(true, targetDataStore.getBool(key: "v5.migration.complete")) + XCTAssertEqual(true, targetDataStore.getBool(key: "v4.migration.complete")) XCTAssertEqual("edge.host.com", target?.targetState.edgeHost) XCTAssertEqual("id_1", target?.targetState.tntId) XCTAssertEqual("id_2", target?.targetState.thirdPartyId) @@ -87,6 +89,24 @@ class TargetTests: XCTestCase { XCTAssertEqual(timestamp, target?.targetState.sessionTimestampInSeconds) } + func testTargetInitWithDataMigrationFromV4() { + let userDefaultsV4 = getUserDefaults() + let targetDataStore = getTargetDataStore() + cleanUserDefaults() + XCTAssertEqual(nil, targetDataStore.getBool(key: "v5.migration.complete")) + XCTAssertEqual(nil, targetDataStore.getBool(key: "v4.migration.complete")) + + userDefaultsV4.set("id_1", forKey: "ADBMOBILE_TARGET_TNT_ID") + userDefaultsV4.set("id_2", forKey: "ADBMOBILE_TARGET_3RD_PARTY_ID") + userDefaultsV4.set(true, forKey: "ADBMOBILE_TARGET_DATA_MIGRATED") + + let target = Target(runtime: mockRuntime) + XCTAssertEqual(true, targetDataStore.getBool(key: "v5.migration.complete")) + XCTAssertEqual(true, targetDataStore.getBool(key: "v4.migration.complete")) + XCTAssertEqual("id_1", target?.targetState.tntId) + XCTAssertEqual("id_2", target?.targetState.thirdPartyId) + } + func testReadyForEvent() { let event = Event(name: "", type: "", source: "", data: nil) mockRuntime.simulateSharedState(extensionName: "com.adobe.module.configuration", event: event, data: (value: ["target.clientCode": "code_123"], status: .set)) diff --git a/AEPTarget/Tests/UnitTests/TargetV4MigratorTests.swift b/AEPTarget/Tests/UnitTests/TargetV4MigratorTests.swift new file mode 100644 index 0000000..4460da4 --- /dev/null +++ b/AEPTarget/Tests/UnitTests/TargetV4MigratorTests.swift @@ -0,0 +1,192 @@ +/* + Copyright 2021 Adobe. All rights reserved. + This file is licensed to you under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. You may obtain a copy + of the License at http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software distributed under + the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR REPRESENTATIONS + OF ANY KIND, either express or implied. See the License for the specific language + governing permissions and limitations under the License. + */ + +import AEPServices +@testable import AEPTarget +import Foundation +import XCTest + +class TargetV4MigratorTests: XCTestCase { + private let appGroup = "test_app_group" + + override func setUpWithError() throws { + if let userDefaults = UserDefaults(suiteName: appGroup) { + for _ in 0 ... 5 { + for key in userDefaults.dictionaryRepresentation().keys { + userDefaults.removeObject(forKey: key) + } + } + } + for _ in 0 ... 5 { + for key in UserDefaults.standard.dictionaryRepresentation().keys { + UserDefaults.standard.removeObject(forKey: key) + } + } + + ServiceProvider.shared.namedKeyValueService.setAppGroup(nil) + } + + private func getTargetDataStore() -> NamedCollectionDataStore { + return NamedCollectionDataStore(name: "com.adobe.module.target") + } + + private func getUserDefaultsV4() -> UserDefaults { + if let v4AppGroup = ServiceProvider.shared.namedKeyValueService.getAppGroup(), !v4AppGroup.isEmpty { + return UserDefaults(suiteName: v4AppGroup) ?? UserDefaults.standard + } + + return UserDefaults.standard + } + + /// No V4 data exists + func testNoV4Data() { + let targetDataStore = getTargetDataStore() + XCTAssertEqual(nil, targetDataStore.getBool(key: "v4.migration.complete")) + + TargetV4Migrator.migrate() + + // verify: didn't do data migration and no data was stored with default values + guard targetDataStore.getString(key: "edge.host") == nil, + targetDataStore.getString(key: "tnt.id") == nil, + targetDataStore.getString(key: "thirdparty.id") == nil, + targetDataStore.getString(key: "session.id") == nil, + targetDataStore.getInt(key: "session.timestamp") == nil + else { + XCTFail("should not do data migration if no data was stored in V4 c++ SDK") + return + } + } + + /// Migrates all of the supported V4 data keys to the new data keys + func testDataMigration() { + let userDefaultsV4 = getUserDefaultsV4() + let targetDataStore = getTargetDataStore() + XCTAssertEqual(nil, targetDataStore.getBool(key: "v4.migration.complete")) + + // V4 Target data with old keys + userDefaultsV4.set("id_1", forKey: "ADBMOBILE_TARGET_TNT_ID") + userDefaultsV4.set("id_2", forKey: "ADBMOBILE_TARGET_3RD_PARTY_ID") + userDefaultsV4.set(true, forKey: "ADBMOBILE_TARGET_DATA_MIGRATED") + + TargetV4Migrator.migrate() + + // V4 Target data keys should be deleted + guard userDefaultsV4.object(forKey: "ADBMOBILE_TARGET_TNT_ID") == nil, + userDefaultsV4.object(forKey: "ADBMOBILE_TARGET_3RD_PARTY_ID") == nil, + userDefaultsV4.object(forKey: "ADBMOBILE_TARGET_DATA_MIGRATED") == nil + else { + XCTFail("the old V4 data is not deleted") + return + } + // verify: Target data with new keys + XCTAssertEqual("id_1", targetDataStore.getString(key: "tnt.id")) + XCTAssertEqual("id_2", targetDataStore.getString(key: "thirdparty.id")) + XCTAssertEqual(nil, targetDataStore.getString(key: "session.id")) + XCTAssertEqual(nil, targetDataStore.getInt(key: "session.timestamp")) + XCTAssertEqual(true, targetDataStore.getBool(key: "v4.migration.complete")) + } + + /// Migrates part of the supported V4 data keys to the new data keys + func testDataMigrationPartial() { + let userDefaultsV4 = getUserDefaultsV4() + let targetDataStore = getTargetDataStore() + XCTAssertEqual(nil, targetDataStore.getBool(key: "v4.migration.complete")) + // V4 Target data with old keys + userDefaultsV4.set("id_1", forKey: "ADBMOBILE_TARGET_TNT_ID") + userDefaultsV4.set(true, forKey: "ADBMOBILE_TARGET_DATA_MIGRATED") + + TargetV4Migrator.migrate() + + // V4 Target data keys should be deleted + guard userDefaultsV4.object(forKey: "ADBMOBILE_TARGET_TNT_ID") == nil, + userDefaultsV4.object(forKey: "ADBMOBILE_TARGET_3RD_PARTY_ID") == nil, + userDefaultsV4.object(forKey: "ADBMOBILE_TARGET_DATA_MIGRATED") == nil + else { + XCTFail("the old V4 data is not deleted") + return + } + + // verify: Target data with new keys + + XCTAssertEqual("id_1", targetDataStore.getString(key: "tnt.id")) + XCTAssertEqual(nil, targetDataStore.getString(key: "thirdparty.id")) + XCTAssertEqual(nil, targetDataStore.getString(key: "session.id")) + XCTAssertEqual(nil, targetDataStore.getInt(key: "session.timestamp")) + XCTAssertEqual(true, targetDataStore.getBool(key: "v4.migration.complete")) + } + + /// Migrate V4 data if using `app group` in the SDK + func testDataMigrationInAppGroup() { + ServiceProvider.shared.namedKeyValueService.setAppGroup(appGroup) + let userDefaultsV4 = getUserDefaultsV4() + let targetDataStore = getTargetDataStore() + XCTAssertEqual(nil, targetDataStore.getBool(key: "v4.migration.complete")) + + // V4 Target data with old keys + userDefaultsV4.set("id_1", forKey: "ADBMOBILE_TARGET_TNT_ID") + userDefaultsV4.set("id_2", forKey: "ADBMOBILE_TARGET_3RD_PARTY_ID") + userDefaultsV4.set(true, forKey: "ADBMOBILE_TARGET_DATA_MIGRATED") + + TargetV4Migrator.migrate() + + // V4 Target data keys should be deleted + guard userDefaultsV4.object(forKey: "ADBMOBILE_TARGET_TNT_ID") == nil, + userDefaultsV4.object(forKey: "ADBMOBILE_TARGET_3RD_PARTY_ID") == nil, + userDefaultsV4.object(forKey: "ADBMOBILE_TARGET_DATA_MIGRATED") == nil + else { + XCTFail("the old V4 data is not deleted") + return + } + // verify: Target data with new keys + XCTAssertEqual("id_1", targetDataStore.getString(key: "tnt.id")) + XCTAssertEqual("id_2", targetDataStore.getString(key: "thirdparty.id")) + XCTAssertEqual(nil, targetDataStore.getString(key: "session.id")) + XCTAssertEqual(nil, targetDataStore.getInt(key: "session.timestamp")) + XCTAssertEqual(true, targetDataStore.getBool(key: "v4.migration.complete")) + } + + /// Migrate V4 data if using a new `app group` in the SDK + /// The `app group` is not stored in V4 ACPCore code, this bug is logged in Jira (AMSDK-11223) + func testDataMigrationInNewAppGroup() { + let targetDataStore = getTargetDataStore() + XCTAssertEqual(nil, targetDataStore.getBool(key: "v4.migration.complete")) + + // V4 Target data with old keys + UserDefaults.standard.set(true, forKey: "ADBMOBILE_TARGET_DATA_MIGRATED") + UserDefaults.standard.set("id_1", forKey: "ADBMOBILE_TARGET_TNT_ID") + UserDefaults.standard.set("id_2", forKey: "ADBMOBILE_TARGET_3RD_PARTY_ID") + + // set a `app group` value and do data migration + ServiceProvider.shared.namedKeyValueService.setAppGroup("test_app_group") + TargetV4Migrator.migrate() + + // verify: V4 Target data will no be migrated + guard UserDefaults.standard.object(forKey: "ADBMOBILE_TARGET_DATA_MIGRATED") != nil, + UserDefaults.standard.object(forKey: "ADBMOBILE_TARGET_TNT_ID") != nil, + UserDefaults.standard.object(forKey: "ADBMOBILE_TARGET_3RD_PARTY_ID") != nil + else { + XCTFail("the old V4 data should not be deleted") + return + } + + guard targetDataStore.getString(key: "edge.host") == nil, + targetDataStore.getString(key: "tnt.id") == nil, + targetDataStore.getString(key: "thirdparty.id") == nil, + targetDataStore.getString(key: "session.id") == nil, + targetDataStore.getInt(key: "session.timestamp") == nil + else { + XCTFail("should not do data migration if app group changed") + return + } + XCTAssertEqual(true, targetDataStore.getBool(key: "v4.migration.complete")) + } +} From 04937ed5735357a1e07abe3b048ea0e055a7f4e9 Mon Sep 17 00:00:00 2001 From: Yansong Date: Wed, 24 Mar 2021 16:11:02 -0500 Subject: [PATCH 4/8] manually merges the missing code --- AEPTarget/Tests/UnitTests/TargetTests.swift | 1 + AEPTarget/Tests/UnitTests/TargetV5MigratorTests.swift | 2 +- 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/AEPTarget/Tests/UnitTests/TargetTests.swift b/AEPTarget/Tests/UnitTests/TargetTests.swift index cb1c1bb..4a79a34 100644 --- a/AEPTarget/Tests/UnitTests/TargetTests.swift +++ b/AEPTarget/Tests/UnitTests/TargetTests.swift @@ -26,6 +26,7 @@ class TargetTests: XCTestCase { var mockConfigSharedState = ["target.clientCode": "code_123", "global.privacy": "optedin"] override func setUp() { + cleanUserDefaults() mockRuntime = TestableExtensionRuntime() target = Target(runtime: mockRuntime) } diff --git a/AEPTarget/Tests/UnitTests/TargetV5MigratorTests.swift b/AEPTarget/Tests/UnitTests/TargetV5MigratorTests.swift index 8c3c2a9..655c315 100644 --- a/AEPTarget/Tests/UnitTests/TargetV5MigratorTests.swift +++ b/AEPTarget/Tests/UnitTests/TargetV5MigratorTests.swift @@ -187,7 +187,7 @@ class TargetV5MigratorTests: XCTestCase { UserDefaults.standard.object(forKey: "Adobe.ADOBEMOBILE_TARGET.TNT_ID") != nil, UserDefaults.standard.object(forKey: "Adobe.ADOBEMOBILE_TARGET.THIRD_PARTY_ID") != nil, UserDefaults.standard.object(forKey: "Adobe.ADOBEMOBILE_TARGET.SESSION_ID") != nil, - UserDefaults.standard.double(forKey: "Adobe.ADOBEMOBILE_TARGET.SESSION_TIMESTAMP") > 0 + UserDefaults.standard.integer(forKey: "Adobe.ADOBEMOBILE_TARGET.SESSION_TIMESTAMP") > 0 else { XCTFail("the old V5 data should not be deleted") return From 71b876f39e349e030cb427b1b48eb40ada986670 Mon Sep 17 00:00:00 2001 From: Yansong Date: Wed, 24 Mar 2021 17:11:49 -0500 Subject: [PATCH 5/8] revert changes --- AEPTarget/Tests/UnitTests/TargetV5MigratorTests.swift | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/AEPTarget/Tests/UnitTests/TargetV5MigratorTests.swift b/AEPTarget/Tests/UnitTests/TargetV5MigratorTests.swift index 655c315..34ea6d4 100644 --- a/AEPTarget/Tests/UnitTests/TargetV5MigratorTests.swift +++ b/AEPTarget/Tests/UnitTests/TargetV5MigratorTests.swift @@ -59,7 +59,7 @@ class TargetV5MigratorTests: XCTestCase { targetDataStore.getString(key: "tnt.id") == nil, targetDataStore.getString(key: "thirdparty.id") == nil, targetDataStore.getString(key: "session.id") == nil, - targetDataStore.getInt(key: "session.timestamp") == nil + targetDataStore.getLong(key: "session.timestamp") == nil else { XCTFail("should not do data migration if no data was stored in V5 c++ SDK") return @@ -95,7 +95,7 @@ class TargetV5MigratorTests: XCTestCase { XCTAssertEqual("id_1", targetDataStore.getString(key: "tnt.id")) XCTAssertEqual("id_2", targetDataStore.getString(key: "thirdparty.id")) XCTAssertEqual("E621E1F8-C36C-495A-93FC-0C247A3E6E5F", targetDataStore.getString(key: "session.id")) - XCTAssertEqual(1_615_436_587, targetDataStore.getInt(key: "session.timestamp")) + XCTAssertEqual(1_615_436_587, targetDataStore.getLong(key: "session.timestamp")) XCTAssertEqual(true, targetDataStore.getBool(key: "v5.migration.complete")) } @@ -127,7 +127,7 @@ class TargetV5MigratorTests: XCTestCase { XCTAssertEqual("id_1", targetDataStore.getString(key: "tnt.id")) XCTAssertEqual("id_2", targetDataStore.getString(key: "thirdparty.id")) XCTAssertEqual(nil, targetDataStore.getString(key: "session.id")) - XCTAssertEqual(nil, targetDataStore.getInt(key: "session.timestamp")) + XCTAssertEqual(nil, targetDataStore.getLong(key: "session.timestamp")) XCTAssertEqual(true, targetDataStore.getBool(key: "v5.migration.complete")) } @@ -161,7 +161,7 @@ class TargetV5MigratorTests: XCTestCase { XCTAssertEqual("id_1", targetDataStore.getString(key: "tnt.id")) XCTAssertEqual("id_2", targetDataStore.getString(key: "thirdparty.id")) XCTAssertEqual("E621E1F8-C36C-495A-93FC-0C247A3E6E5F", targetDataStore.getString(key: "session.id")) - XCTAssertEqual(1_615_436_587, targetDataStore.getInt(key: "session.timestamp")) + XCTAssertEqual(1_615_436_587, targetDataStore.getLong(key: "session.timestamp")) XCTAssertEqual(true, targetDataStore.getBool(key: "v5.migration.complete")) } @@ -197,7 +197,7 @@ class TargetV5MigratorTests: XCTestCase { targetDataStore.getString(key: "tnt.id") == nil, targetDataStore.getString(key: "thirdparty.id") == nil, targetDataStore.getString(key: "session.id") == nil, - targetDataStore.getInt(key: "session.timestamp") == nil + targetDataStore.getLong(key: "session.timestamp") == nil else { XCTFail("should not do data migration if app group changed") return From e5bdc1f695c6a5b332e73c2d2307adccd474060a Mon Sep 17 00:00:00 2001 From: Yansong Date: Tue, 30 Mar 2021 14:00:39 -0500 Subject: [PATCH 6/8] no message --- AEPTarget/Sources/TargetV5Migrator.swift | 37 ++++++++++++++---------- 1 file changed, 22 insertions(+), 15 deletions(-) diff --git a/AEPTarget/Sources/TargetV5Migrator.swift b/AEPTarget/Sources/TargetV5Migrator.swift index d6fd000..95745df 100644 --- a/AEPTarget/Sources/TargetV5Migrator.swift +++ b/AEPTarget/Sources/TargetV5Migrator.swift @@ -33,21 +33,28 @@ enum TargetV5Migrator { } // save values - if let edgeHost = userDefaultV5.string(forKey: TargetConstants.V5Migration.EDGE_HOST) { - targetDataStore.set(key: TargetConstants.DataStoreKeys.EDGE_HOST, value: edgeHost) - } - let sessionTimestamp = userDefaultV5.integer(forKey: TargetConstants.V5Migration.SESSION_TIMESTAMP) - if sessionTimestamp > 0 { - targetDataStore.set(key: TargetConstants.DataStoreKeys.SESSION_TIMESTAMP, value: sessionTimestamp) - } - if let sessionId = userDefaultV5.string(forKey: TargetConstants.V5Migration.SESSION_ID) { - targetDataStore.set(key: TargetConstants.DataStoreKeys.SESSION_ID, value: sessionId) - } - if let thirdPartyId = userDefaultV5.string(forKey: TargetConstants.V5Migration.THIRD_PARTY_ID) { - targetDataStore.set(key: TargetConstants.DataStoreKeys.THIRD_PARTY_ID, value: thirdPartyId) - } - if let tntId = userDefaultV5.string(forKey: TargetConstants.V5Migration.TNT_ID) { - targetDataStore.set(key: TargetConstants.DataStoreKeys.TNT_ID, value: tntId) + if targetDataStore.getString(key: TargetConstants.DataStoreKeys.THIRD_PARTY_ID) == nil, + targetDataStore.getString(key: TargetConstants.DataStoreKeys.TNT_ID) == nil, + targetDataStore.getString(key: TargetConstants.DataStoreKeys.SESSION_ID) == nil, + targetDataStore.getLong(key: TargetConstants.DataStoreKeys.SESSION_TIMESTAMP) == nil, + targetDataStore.getString(key: TargetConstants.DataStoreKeys.EDGE_HOST) == nil + { + if let edgeHost = userDefaultV5.string(forKey: TargetConstants.V5Migration.EDGE_HOST) { + targetDataStore.set(key: TargetConstants.DataStoreKeys.EDGE_HOST, value: edgeHost) + } + let sessionTimestamp = userDefaultV5.integer(forKey: TargetConstants.V5Migration.SESSION_TIMESTAMP) + if sessionTimestamp > 0 { + targetDataStore.set(key: TargetConstants.DataStoreKeys.SESSION_TIMESTAMP, value: sessionTimestamp) + } + if let sessionId = userDefaultV5.string(forKey: TargetConstants.V5Migration.SESSION_ID) { + targetDataStore.set(key: TargetConstants.DataStoreKeys.SESSION_ID, value: sessionId) + } + if let thirdPartyId = userDefaultV5.string(forKey: TargetConstants.V5Migration.THIRD_PARTY_ID) { + targetDataStore.set(key: TargetConstants.DataStoreKeys.THIRD_PARTY_ID, value: thirdPartyId) + } + if let tntId = userDefaultV5.string(forKey: TargetConstants.V5Migration.TNT_ID) { + targetDataStore.set(key: TargetConstants.DataStoreKeys.TNT_ID, value: tntId) + } } // remove old values From f8e6ad2dfa56eb6cf1cd94d80c5cbbb55f9187a2 Mon Sep 17 00:00:00 2001 From: Yansong Date: Tue, 30 Mar 2021 16:57:55 -0500 Subject: [PATCH 7/8] fix review comments --- AEPTarget/Sources/TargetConstants.swift | 2 - AEPTarget/Sources/TargetV4Migrator.swift | 53 +++++++----------- AEPTarget/Sources/TargetV5Migrator.swift | 54 +++++++------------ .../TargetFunctionalTests.swift | 18 +++---- AEPTarget/Tests/UnitTests/TargetTests.swift | 4 +- .../UnitTests/TargetV4MigratorTests.swift | 9 ---- .../UnitTests/TargetV5MigratorTests.swift | 9 ---- 7 files changed, 50 insertions(+), 99 deletions(-) diff --git a/AEPTarget/Sources/TargetConstants.swift b/AEPTarget/Sources/TargetConstants.swift index d44bd79..d6fad46 100644 --- a/AEPTarget/Sources/TargetConstants.swift +++ b/AEPTarget/Sources/TargetConstants.swift @@ -142,8 +142,6 @@ enum TargetConstants { static let TNT_ID = "tnt.id" static let EDGE_HOST = "edge.host" static let THIRD_PARTY_ID = "thirdparty.id" - static let V5_MIGRATION_COMPLETE = "v5.migration.complete" - static let V4_MIGRATION_COMPLETE = "v4.migration.complete" } enum TargetRequestValue { diff --git a/AEPTarget/Sources/TargetV4Migrator.swift b/AEPTarget/Sources/TargetV4Migrator.swift index bf89756..5628953 100644 --- a/AEPTarget/Sources/TargetV4Migrator.swift +++ b/AEPTarget/Sources/TargetV4Migrator.swift @@ -15,7 +15,7 @@ import Foundation /// Provides functionality for migrating stored data from V4 to Swift V5 enum TargetV4Migrator { - private static var userDefaultV4: UserDefaults { + private static var userDefaultsV4: UserDefaults { if let v4AppGroup = ServiceProvider.shared.namedKeyValueService.getAppGroup(), !v4AppGroup.isEmpty { return UserDefaults(suiteName: v4AppGroup) ?? UserDefaults.standard } @@ -27,43 +27,30 @@ enum TargetV4Migrator { static func migrate() { let targetDataStore = NamedCollectionDataStore(name: TargetConstants.DATASTORE_NAME) - guard targetDataStore.getBool(key: TargetConstants.DataStoreKeys.V4_MIGRATION_COMPLETE) == nil else { + guard targetDataStore.getString(key: TargetConstants.DataStoreKeys.THIRD_PARTY_ID) == nil, + targetDataStore.getString(key: TargetConstants.DataStoreKeys.TNT_ID) == nil, + targetDataStore.getString(key: TargetConstants.DataStoreKeys.SESSION_ID) == nil, + targetDataStore.getLong(key: TargetConstants.DataStoreKeys.SESSION_TIMESTAMP) == nil, + targetDataStore.getString(key: TargetConstants.DataStoreKeys.EDGE_HOST) == nil + else { return } - // save values - if targetDataStore.getString(key: TargetConstants.DataStoreKeys.THIRD_PARTY_ID) == nil, - targetDataStore.getString(key: TargetConstants.DataStoreKeys.TNT_ID) == nil, - targetDataStore.getString(key: TargetConstants.DataStoreKeys.SESSION_ID) == nil, - targetDataStore.getLong(key: TargetConstants.DataStoreKeys.SESSION_TIMESTAMP) == nil, - targetDataStore.getString(key: TargetConstants.DataStoreKeys.EDGE_HOST) == nil - { - if let thirdPartyId = userDefaultV4.string(forKey: TargetConstants.V4Migration.THIRD_PARTY_ID) { - targetDataStore.set(key: TargetConstants.DataStoreKeys.THIRD_PARTY_ID, value: thirdPartyId) - } - if let tntId = userDefaultV4.string(forKey: TargetConstants.V4Migration.TNT_ID) { - targetDataStore.set(key: TargetConstants.DataStoreKeys.TNT_ID, value: tntId) - } - if let edgeHost = userDefaultV4.string(forKey: TargetConstants.V4Migration.EDGE_HOST) { - targetDataStore.set(key: TargetConstants.DataStoreKeys.EDGE_HOST, value: edgeHost) - } - let timestamp = userDefaultV4.integer(forKey: TargetConstants.V4Migration.LAST_TIMESTAMP) - if timestamp > 0 { - targetDataStore.set(key: TargetConstants.DataStoreKeys.SESSION_TIMESTAMP, value: timestamp) - } - if let sessionId = userDefaultV4.string(forKey: TargetConstants.V4Migration.SESSION_ID) { - targetDataStore.set(key: TargetConstants.DataStoreKeys.SESSION_ID, value: sessionId) - } + targetDataStore.set(key: TargetConstants.DataStoreKeys.THIRD_PARTY_ID, value: userDefaultsV4.string(forKey: TargetConstants.V4Migration.THIRD_PARTY_ID)) + targetDataStore.set(key: TargetConstants.DataStoreKeys.TNT_ID, value: userDefaultsV4.string(forKey: TargetConstants.V4Migration.TNT_ID)) + targetDataStore.set(key: TargetConstants.DataStoreKeys.EDGE_HOST, value: userDefaultsV4.string(forKey: TargetConstants.V4Migration.EDGE_HOST)) + let timestamp = userDefaultsV4.integer(forKey: TargetConstants.V4Migration.LAST_TIMESTAMP) + if timestamp > 0 { + targetDataStore.set(key: TargetConstants.DataStoreKeys.SESSION_TIMESTAMP, value: timestamp) } + targetDataStore.set(key: TargetConstants.DataStoreKeys.SESSION_ID, value: userDefaultsV4.string(forKey: TargetConstants.V4Migration.SESSION_ID)) // remove old values - userDefaultV4.removeObject(forKey: TargetConstants.V4Migration.THIRD_PARTY_ID) - userDefaultV4.removeObject(forKey: TargetConstants.V4Migration.TNT_ID) - userDefaultV4.removeObject(forKey: TargetConstants.V4Migration.EDGE_HOST) - userDefaultV4.removeObject(forKey: TargetConstants.V4Migration.SESSION_ID) - userDefaultV4.removeObject(forKey: TargetConstants.V4Migration.LAST_TIMESTAMP) - userDefaultV4.removeObject(forKey: TargetConstants.V4Migration.V4_DATA_MIGRATED) - - targetDataStore.set(key: TargetConstants.DataStoreKeys.V4_MIGRATION_COMPLETE, value: true) + userDefaultsV4.removeObject(forKey: TargetConstants.V4Migration.THIRD_PARTY_ID) + userDefaultsV4.removeObject(forKey: TargetConstants.V4Migration.TNT_ID) + userDefaultsV4.removeObject(forKey: TargetConstants.V4Migration.EDGE_HOST) + userDefaultsV4.removeObject(forKey: TargetConstants.V4Migration.SESSION_ID) + userDefaultsV4.removeObject(forKey: TargetConstants.V4Migration.LAST_TIMESTAMP) + userDefaultsV4.removeObject(forKey: TargetConstants.V4Migration.V4_DATA_MIGRATED) } } diff --git a/AEPTarget/Sources/TargetV5Migrator.swift b/AEPTarget/Sources/TargetV5Migrator.swift index 95745df..91cac64 100644 --- a/AEPTarget/Sources/TargetV5Migrator.swift +++ b/AEPTarget/Sources/TargetV5Migrator.swift @@ -15,56 +15,42 @@ import Foundation /// Provides functionality for migrating stored data from c++ V5 to Swift V5 enum TargetV5Migrator { - private static func getUserDefaultsV5() -> UserDefaults { + private static var userDefaultsV5: UserDefaults { if let v5AppGroup = ServiceProvider.shared.namedKeyValueService.getAppGroup(), !v5AppGroup.isEmpty { return UserDefaults(suiteName: v5AppGroup) ?? UserDefaults.standard } - return UserDefaults.standard } /// Migrates the c++ V5 Target values into the Swift V5 Target data store static func migrate() { - let userDefaultV5 = getUserDefaultsV5() let targetDataStore = NamedCollectionDataStore(name: TargetConstants.DATASTORE_NAME) - guard targetDataStore.getBool(key: TargetConstants.DataStoreKeys.V5_MIGRATION_COMPLETE) == nil else { + guard targetDataStore.getString(key: TargetConstants.DataStoreKeys.THIRD_PARTY_ID) == nil, + targetDataStore.getString(key: TargetConstants.DataStoreKeys.TNT_ID) == nil, + targetDataStore.getString(key: TargetConstants.DataStoreKeys.SESSION_ID) == nil, + targetDataStore.getLong(key: TargetConstants.DataStoreKeys.SESSION_TIMESTAMP) == nil, + targetDataStore.getString(key: TargetConstants.DataStoreKeys.EDGE_HOST) == nil + else { return } // save values - if targetDataStore.getString(key: TargetConstants.DataStoreKeys.THIRD_PARTY_ID) == nil, - targetDataStore.getString(key: TargetConstants.DataStoreKeys.TNT_ID) == nil, - targetDataStore.getString(key: TargetConstants.DataStoreKeys.SESSION_ID) == nil, - targetDataStore.getLong(key: TargetConstants.DataStoreKeys.SESSION_TIMESTAMP) == nil, - targetDataStore.getString(key: TargetConstants.DataStoreKeys.EDGE_HOST) == nil - { - if let edgeHost = userDefaultV5.string(forKey: TargetConstants.V5Migration.EDGE_HOST) { - targetDataStore.set(key: TargetConstants.DataStoreKeys.EDGE_HOST, value: edgeHost) - } - let sessionTimestamp = userDefaultV5.integer(forKey: TargetConstants.V5Migration.SESSION_TIMESTAMP) - if sessionTimestamp > 0 { - targetDataStore.set(key: TargetConstants.DataStoreKeys.SESSION_TIMESTAMP, value: sessionTimestamp) - } - if let sessionId = userDefaultV5.string(forKey: TargetConstants.V5Migration.SESSION_ID) { - targetDataStore.set(key: TargetConstants.DataStoreKeys.SESSION_ID, value: sessionId) - } - if let thirdPartyId = userDefaultV5.string(forKey: TargetConstants.V5Migration.THIRD_PARTY_ID) { - targetDataStore.set(key: TargetConstants.DataStoreKeys.THIRD_PARTY_ID, value: thirdPartyId) - } - if let tntId = userDefaultV5.string(forKey: TargetConstants.V5Migration.TNT_ID) { - targetDataStore.set(key: TargetConstants.DataStoreKeys.TNT_ID, value: tntId) - } + targetDataStore.set(key: TargetConstants.DataStoreKeys.EDGE_HOST, value: userDefaultsV5.string(forKey: TargetConstants.V5Migration.EDGE_HOST)) + + let sessionTimestamp = userDefaultsV5.integer(forKey: TargetConstants.V5Migration.SESSION_TIMESTAMP) + if sessionTimestamp > 0 { + targetDataStore.set(key: TargetConstants.DataStoreKeys.SESSION_TIMESTAMP, value: sessionTimestamp) } + targetDataStore.set(key: TargetConstants.DataStoreKeys.SESSION_ID, value: userDefaultsV5.string(forKey: TargetConstants.V5Migration.SESSION_ID)) + targetDataStore.set(key: TargetConstants.DataStoreKeys.THIRD_PARTY_ID, value: userDefaultsV5.string(forKey: TargetConstants.V5Migration.THIRD_PARTY_ID)) + targetDataStore.set(key: TargetConstants.DataStoreKeys.TNT_ID, value: userDefaultsV5.string(forKey: TargetConstants.V5Migration.TNT_ID)) // remove old values - userDefaultV5.removeObject(forKey: TargetConstants.V5Migration.EDGE_HOST) - userDefaultV5.removeObject(forKey: TargetConstants.V5Migration.SESSION_TIMESTAMP) - userDefaultV5.removeObject(forKey: TargetConstants.V5Migration.SESSION_ID) - userDefaultV5.removeObject(forKey: TargetConstants.V5Migration.THIRD_PARTY_ID) - userDefaultV5.removeObject(forKey: TargetConstants.V5Migration.TNT_ID) - - // mark migration complete - targetDataStore.set(key: TargetConstants.DataStoreKeys.V5_MIGRATION_COMPLETE, value: true) + userDefaultsV5.removeObject(forKey: TargetConstants.V5Migration.EDGE_HOST) + userDefaultsV5.removeObject(forKey: TargetConstants.V5Migration.SESSION_TIMESTAMP) + userDefaultsV5.removeObject(forKey: TargetConstants.V5Migration.SESSION_ID) + userDefaultsV5.removeObject(forKey: TargetConstants.V5Migration.THIRD_PARTY_ID) + userDefaultsV5.removeObject(forKey: TargetConstants.V5Migration.TNT_ID) } } diff --git a/AEPTarget/Tests/FunctionalTests/TargetFunctionalTests.swift b/AEPTarget/Tests/FunctionalTests/TargetFunctionalTests.swift index 8dd9ac7..49752b5 100644 --- a/AEPTarget/Tests/FunctionalTests/TargetFunctionalTests.swift +++ b/AEPTarget/Tests/FunctionalTests/TargetFunctionalTests.swift @@ -83,8 +83,8 @@ class TargetFunctionalTests: XCTestCase { } private func getUserDefaults() -> UserDefaults { - if let v5AppGroup = ServiceProvider.shared.namedKeyValueService.getAppGroup(), !v5AppGroup.isEmpty { - return UserDefaults(suiteName: v5AppGroup) ?? UserDefaults.standard + if let appGroup = ServiceProvider.shared.namedKeyValueService.getAppGroup(), !appGroup.isEmpty { + return UserDefaults(suiteName: appGroup) ?? UserDefaults.standard } return UserDefaults.standard @@ -124,8 +124,6 @@ class TargetFunctionalTests: XCTestCase { let userDefaultsV5 = getUserDefaults() let targetDataStore = getTargetDataStore() cleanUserDefaults() - XCTAssertEqual(nil, targetDataStore.getBool(key: "v5.migration.complete")) - XCTAssertEqual(nil, targetDataStore.getBool(key: "v4.migration.complete")) let timestamp = Date().getUnixTimeInSeconds() userDefaultsV5.set("edge.host.com", forKey: "Adobe.ADOBEMOBILE_TARGET.EDGE_HOST") @@ -135,8 +133,6 @@ class TargetFunctionalTests: XCTestCase { userDefaultsV5.set(timestamp, forKey: "Adobe.ADOBEMOBILE_TARGET.SESSION_TIMESTAMP") let target = Target(runtime: mockRuntime) - XCTAssertEqual(true, targetDataStore.getBool(key: "v5.migration.complete")) - XCTAssertEqual(true, targetDataStore.getBool(key: "v4.migration.complete")) XCTAssertEqual("edge.host.com", target?.targetState.edgeHost) XCTAssertEqual("id_1", target?.targetState.tntId) XCTAssertEqual("id_2", target?.targetState.thirdPartyId) @@ -148,18 +144,20 @@ class TargetFunctionalTests: XCTestCase { let userDefaultsV4 = getUserDefaults() let targetDataStore = getTargetDataStore() cleanUserDefaults() - XCTAssertEqual(nil, targetDataStore.getBool(key: "v5.migration.complete")) - XCTAssertEqual(nil, targetDataStore.getBool(key: "v4.migration.complete")) userDefaultsV4.set("id_1", forKey: "ADBMOBILE_TARGET_TNT_ID") userDefaultsV4.set("id_2", forKey: "ADBMOBILE_TARGET_3RD_PARTY_ID") userDefaultsV4.set(true, forKey: "ADBMOBILE_TARGET_DATA_MIGRATED") + userDefaultsV4.set("E621E1F8-C36C-495A-93FC-0C247A3E6E5F", forKey: "ADBMOBILE_TARGET_SESSION_ID") + userDefaultsV4.set("edge.host.com", forKey: "ADBMOBILE_TARGET_EDGE_HOST") + userDefaultsV4.set(1_615_436_587, forKey: "ADBMOBILE_TARGET_LAST_TIMESTAMP") let target = Target(runtime: mockRuntime) - XCTAssertEqual(true, targetDataStore.getBool(key: "v5.migration.complete")) - XCTAssertEqual(true, targetDataStore.getBool(key: "v4.migration.complete")) XCTAssertEqual("id_1", target?.targetState.tntId) XCTAssertEqual("id_2", target?.targetState.thirdPartyId) + XCTAssertEqual("edge.host.com", targetDataStore.getString(key: "edge.host")) + XCTAssertEqual("E621E1F8-C36C-495A-93FC-0C247A3E6E5F", targetDataStore.getString(key: "session.id")) + XCTAssertEqual(1_615_436_587, targetDataStore.getInt(key: "session.timestamp")) } // MARK: - Prefetch diff --git a/AEPTarget/Tests/UnitTests/TargetTests.swift b/AEPTarget/Tests/UnitTests/TargetTests.swift index a79bfac..a044e43 100644 --- a/AEPTarget/Tests/UnitTests/TargetTests.swift +++ b/AEPTarget/Tests/UnitTests/TargetTests.swift @@ -44,8 +44,8 @@ class TargetTests: XCTestCase { } private func getUserDefaults() -> UserDefaults { - if let v5AppGroup = ServiceProvider.shared.namedKeyValueService.getAppGroup(), !v5AppGroup.isEmpty { - return UserDefaults(suiteName: v5AppGroup) ?? UserDefaults.standard + if let appGroup = ServiceProvider.shared.namedKeyValueService.getAppGroup(), !appGroup.isEmpty { + return UserDefaults(suiteName: appGroup) ?? UserDefaults.standard } return UserDefaults.standard diff --git a/AEPTarget/Tests/UnitTests/TargetV4MigratorTests.swift b/AEPTarget/Tests/UnitTests/TargetV4MigratorTests.swift index 97349aa..eb816fc 100644 --- a/AEPTarget/Tests/UnitTests/TargetV4MigratorTests.swift +++ b/AEPTarget/Tests/UnitTests/TargetV4MigratorTests.swift @@ -50,7 +50,6 @@ class TargetV4MigratorTests: XCTestCase { /// No V4 data exists func testNoV4Data() { let targetDataStore = getTargetDataStore() - XCTAssertEqual(nil, targetDataStore.getBool(key: "v4.migration.complete")) TargetV4Migrator.migrate() @@ -70,7 +69,6 @@ class TargetV4MigratorTests: XCTestCase { func testDataMigration() { let userDefaultsV4 = getUserDefaultsV4() let targetDataStore = getTargetDataStore() - XCTAssertEqual(nil, targetDataStore.getBool(key: "v4.migration.complete")) // V4 Target data with old keys userDefaultsV4.set("id_1", forKey: "ADBMOBILE_TARGET_TNT_ID") @@ -99,14 +97,12 @@ class TargetV4MigratorTests: XCTestCase { XCTAssertEqual("edge.host.com", targetDataStore.getString(key: "edge.host")) XCTAssertEqual("E621E1F8-C36C-495A-93FC-0C247A3E6E5F", targetDataStore.getString(key: "session.id")) XCTAssertEqual(1_615_436_587, targetDataStore.getInt(key: "session.timestamp")) - XCTAssertEqual(true, targetDataStore.getBool(key: "v4.migration.complete")) } /// Migrates part of the supported V4 data keys to the new data keys func testDataMigrationPartial() { let userDefaultsV4 = getUserDefaultsV4() let targetDataStore = getTargetDataStore() - XCTAssertEqual(nil, targetDataStore.getBool(key: "v4.migration.complete")) // V4 Target data with old keys userDefaultsV4.set("id_1", forKey: "ADBMOBILE_TARGET_TNT_ID") userDefaultsV4.set(true, forKey: "ADBMOBILE_TARGET_DATA_MIGRATED") @@ -128,7 +124,6 @@ class TargetV4MigratorTests: XCTestCase { XCTAssertEqual(nil, targetDataStore.getString(key: "thirdparty.id")) XCTAssertEqual(nil, targetDataStore.getString(key: "session.id")) XCTAssertEqual(nil, targetDataStore.getInt(key: "session.timestamp")) - XCTAssertEqual(true, targetDataStore.getBool(key: "v4.migration.complete")) } /// Migrate V4 data if using `app group` in the SDK @@ -136,7 +131,6 @@ class TargetV4MigratorTests: XCTestCase { ServiceProvider.shared.namedKeyValueService.setAppGroup(appGroup) let userDefaultsV4 = getUserDefaultsV4() let targetDataStore = getTargetDataStore() - XCTAssertEqual(nil, targetDataStore.getBool(key: "v4.migration.complete")) // V4 Target data with old keys userDefaultsV4.set("id_1", forKey: "ADBMOBILE_TARGET_TNT_ID") @@ -166,14 +160,12 @@ class TargetV4MigratorTests: XCTestCase { XCTAssertEqual("edge.host.com", targetDataStore.getString(key: "edge.host")) XCTAssertEqual("E621E1F8-C36C-495A-93FC-0C247A3E6E5F", targetDataStore.getString(key: "session.id")) XCTAssertEqual(1_615_436_587, targetDataStore.getInt(key: "session.timestamp")) - XCTAssertEqual(true, targetDataStore.getBool(key: "v4.migration.complete")) } /// Migrate V4 data if using a new `app group` in the SDK /// The `app group` is not stored in V4 ACPCore code, this bug is logged in Jira (AMSDK-11223) func testDataMigrationInNewAppGroup() { let targetDataStore = getTargetDataStore() - XCTAssertEqual(nil, targetDataStore.getBool(key: "v4.migration.complete")) // V4 Target data with old keys UserDefaults.standard.set(true, forKey: "ADBMOBILE_TARGET_DATA_MIGRATED") @@ -208,6 +200,5 @@ class TargetV4MigratorTests: XCTestCase { XCTFail("should not do data migration if app group changed") return } - XCTAssertEqual(true, targetDataStore.getBool(key: "v4.migration.complete")) } } diff --git a/AEPTarget/Tests/UnitTests/TargetV5MigratorTests.swift b/AEPTarget/Tests/UnitTests/TargetV5MigratorTests.swift index 34ea6d4..e1af10f 100644 --- a/AEPTarget/Tests/UnitTests/TargetV5MigratorTests.swift +++ b/AEPTarget/Tests/UnitTests/TargetV5MigratorTests.swift @@ -50,7 +50,6 @@ class TargetV5MigratorTests: XCTestCase { /// No V5 data exists func testNoV5Data() { let targetDataStore = getTargetDataStore() - XCTAssertEqual(nil, targetDataStore.getBool(key: "v5.migration.complete")) TargetV5Migrator.migrate() @@ -70,7 +69,6 @@ class TargetV5MigratorTests: XCTestCase { func testDataMigration() { let userDefaultsV5 = getUserDefaultsV5() let targetDataStore = getTargetDataStore() - XCTAssertEqual(nil, targetDataStore.getBool(key: "v5.migration.complete")) // V5 Target data with old keys userDefaultsV5.set("edge.host.com", forKey: "Adobe.ADOBEMOBILE_TARGET.EDGE_HOST") userDefaultsV5.set("id_1", forKey: "Adobe.ADOBEMOBILE_TARGET.TNT_ID") @@ -96,14 +94,12 @@ class TargetV5MigratorTests: XCTestCase { XCTAssertEqual("id_2", targetDataStore.getString(key: "thirdparty.id")) XCTAssertEqual("E621E1F8-C36C-495A-93FC-0C247A3E6E5F", targetDataStore.getString(key: "session.id")) XCTAssertEqual(1_615_436_587, targetDataStore.getLong(key: "session.timestamp")) - XCTAssertEqual(true, targetDataStore.getBool(key: "v5.migration.complete")) } /// Migrates part of the supported V5 data keys to the new data keys func testDataMigrationPartial() { let userDefaultsV5 = getUserDefaultsV5() let targetDataStore = getTargetDataStore() - XCTAssertEqual(nil, targetDataStore.getBool(key: "v5.migration.complete")) // V5 Target data with old keys userDefaultsV5.set("edge.host.com", forKey: "Adobe.ADOBEMOBILE_TARGET.EDGE_HOST") userDefaultsV5.set("id_1", forKey: "Adobe.ADOBEMOBILE_TARGET.TNT_ID") @@ -128,7 +124,6 @@ class TargetV5MigratorTests: XCTestCase { XCTAssertEqual("id_2", targetDataStore.getString(key: "thirdparty.id")) XCTAssertEqual(nil, targetDataStore.getString(key: "session.id")) XCTAssertEqual(nil, targetDataStore.getLong(key: "session.timestamp")) - XCTAssertEqual(true, targetDataStore.getBool(key: "v5.migration.complete")) } /// Migrate V5 data if using `app group` in the SDK @@ -136,7 +131,6 @@ class TargetV5MigratorTests: XCTestCase { ServiceProvider.shared.namedKeyValueService.setAppGroup(appGroup) let userDefaultsV5 = getUserDefaultsV5() let targetDataStore = getTargetDataStore() - XCTAssertEqual(nil, targetDataStore.getBool(key: "v5.migration.complete")) // V5 Target data with old keys userDefaultsV5.set("edge.host.com", forKey: "Adobe.ADOBEMOBILE_TARGET.EDGE_HOST") @@ -162,14 +156,12 @@ class TargetV5MigratorTests: XCTestCase { XCTAssertEqual("id_2", targetDataStore.getString(key: "thirdparty.id")) XCTAssertEqual("E621E1F8-C36C-495A-93FC-0C247A3E6E5F", targetDataStore.getString(key: "session.id")) XCTAssertEqual(1_615_436_587, targetDataStore.getLong(key: "session.timestamp")) - XCTAssertEqual(true, targetDataStore.getBool(key: "v5.migration.complete")) } /// Migrate V5 data if using a new `app group` in the SDK /// The `app group` is not stored in V5 ACPCore code, this bug is logged in Jira (AMSDK-11223) func testDataMigrationInNewAppGroup() { let targetDataStore = getTargetDataStore() - XCTAssertEqual(nil, targetDataStore.getBool(key: "v5.migration.complete")) // V5 Target data with old keys UserDefaults.standard.set("edge.host.com", forKey: "Adobe.ADOBEMOBILE_TARGET.EDGE_HOST") @@ -202,6 +194,5 @@ class TargetV5MigratorTests: XCTestCase { XCTFail("should not do data migration if app group changed") return } - XCTAssertEqual(true, targetDataStore.getBool(key: "v5.migration.complete")) } } From b0e600f8e7397ba15b7ad8eaf22cbb66e77046b6 Mon Sep 17 00:00:00 2001 From: Yansong Date: Tue, 30 Mar 2021 18:17:46 -0500 Subject: [PATCH 8/8] add some trace logs --- AEPTarget/Sources/TargetV4Migrator.swift | 3 +++ AEPTarget/Sources/TargetV5Migrator.swift | 3 +++ 2 files changed, 6 insertions(+) diff --git a/AEPTarget/Sources/TargetV4Migrator.swift b/AEPTarget/Sources/TargetV4Migrator.swift index 5628953..00059f8 100644 --- a/AEPTarget/Sources/TargetV4Migrator.swift +++ b/AEPTarget/Sources/TargetV4Migrator.swift @@ -15,6 +15,7 @@ import Foundation /// Provides functionality for migrating stored data from V4 to Swift V5 enum TargetV4Migrator { + static let LOG_TAG = "TargetV4Migrator" private static var userDefaultsV4: UserDefaults { if let v4AppGroup = ServiceProvider.shared.namedKeyValueService.getAppGroup(), !v4AppGroup.isEmpty { return UserDefaults(suiteName: v4AppGroup) ?? UserDefaults.standard @@ -33,6 +34,7 @@ enum TargetV4Migrator { targetDataStore.getLong(key: TargetConstants.DataStoreKeys.SESSION_TIMESTAMP) == nil, targetDataStore.getString(key: TargetConstants.DataStoreKeys.EDGE_HOST) == nil else { + Log.trace(label: Target.LOG_TAG, "Found new Target data keys, not need to do V4 data migration.") return } @@ -52,5 +54,6 @@ enum TargetV4Migrator { userDefaultsV4.removeObject(forKey: TargetConstants.V4Migration.SESSION_ID) userDefaultsV4.removeObject(forKey: TargetConstants.V4Migration.LAST_TIMESTAMP) userDefaultsV4.removeObject(forKey: TargetConstants.V4Migration.V4_DATA_MIGRATED) + Log.trace(label: Target.LOG_TAG, "Target V4 data migration completed.") } } diff --git a/AEPTarget/Sources/TargetV5Migrator.swift b/AEPTarget/Sources/TargetV5Migrator.swift index 91cac64..162d7cd 100644 --- a/AEPTarget/Sources/TargetV5Migrator.swift +++ b/AEPTarget/Sources/TargetV5Migrator.swift @@ -15,6 +15,7 @@ import Foundation /// Provides functionality for migrating stored data from c++ V5 to Swift V5 enum TargetV5Migrator { + static let LOG_TAG = "TargetV5Migrator" private static var userDefaultsV5: UserDefaults { if let v5AppGroup = ServiceProvider.shared.namedKeyValueService.getAppGroup(), !v5AppGroup.isEmpty { return UserDefaults(suiteName: v5AppGroup) ?? UserDefaults.standard @@ -32,6 +33,7 @@ enum TargetV5Migrator { targetDataStore.getLong(key: TargetConstants.DataStoreKeys.SESSION_TIMESTAMP) == nil, targetDataStore.getString(key: TargetConstants.DataStoreKeys.EDGE_HOST) == nil else { + Log.trace(label: Target.LOG_TAG, "Found new Target data keys, not need to do V5 data migration.") return } @@ -52,5 +54,6 @@ enum TargetV5Migrator { userDefaultsV5.removeObject(forKey: TargetConstants.V5Migration.SESSION_ID) userDefaultsV5.removeObject(forKey: TargetConstants.V5Migration.THIRD_PARTY_ID) userDefaultsV5.removeObject(forKey: TargetConstants.V5Migration.TNT_ID) + Log.trace(label: Target.LOG_TAG, "Target V5 data migration completed.") } }