Skip to content

Commit

Permalink
Fix migration bugs (#594)
Browse files Browse the repository at this point in the history
* update anycodable nil handling

* Add nil check

* update API def for AnyCodable

* dont case in migrators

* fix v4 migration

* typo

* Update any codable tests

* Revert rules parser change

* Update v4 migrator tests to use NSDate

* Remove un-needed nil check

* format
  • Loading branch information
nporter-adbe authored Mar 31, 2021
1 parent 5aaf3a0 commit e3ea968
Show file tree
Hide file tree
Showing 5 changed files with 35 additions and 24 deletions.
14 changes: 7 additions & 7 deletions AEPCore/Sources/migration/V4Migrator.swift
Original file line number Diff line number Diff line change
Expand Up @@ -122,7 +122,7 @@ struct V4Migrator {

// save values
let identityDataStore = NamedCollectionDataStore(name: V4MigrationConstants.Identity.DATASTORE_NAME)
let identityPropsData = AnyCodable.from(dictionary: identityPropsDict as [String: Any])
let identityPropsData = AnyCodable.from(dictionary: identityPropsDict)
identityDataStore.setObject(key: V4MigrationConstants.Identity.DataStoreKeys.IDENTITY_PROPERTIES, value: identityPropsData)
identityDataStore.set(key: V4MigrationConstants.Identity.DataStoreKeys.PUSH_ENABLED, value: pushEnabled)

Expand All @@ -142,19 +142,19 @@ struct V4Migrator {

/// Migrates the v4 Lifecycle values into the v5 Lifecycle data store
private func migrateLifecycleLocalStorage() {
let installDate = v4Defaults.object(forKey: V4MigrationConstants.Lifecycle.V4_INSTALL_DATE) as? Date
let installDate = v4Defaults.object(forKey: V4MigrationConstants.Lifecycle.V4_INSTALL_DATE) as? NSDate
let lastVersion = v4Defaults.string(forKey: V4MigrationConstants.Lifecycle.V4_LAST_VERSION)
let lastUsedDate = v4Defaults.object(forKey: V4MigrationConstants.Lifecycle.V4_LAST_USED_DATE) as? Date
let lastUsedDate = v4Defaults.object(forKey: V4MigrationConstants.Lifecycle.V4_LAST_USED_DATE) as? NSDate
let launches = v4Defaults.integer(forKey: V4MigrationConstants.Lifecycle.V4_LAUNCHES)
let successfulClose = v4Defaults.bool(forKey: V4MigrationConstants.Lifecycle.V4_SUCCESSFUL_CLOSE)

let lifecycleDataStore = NamedCollectionDataStore(name: V4MigrationConstants.Lifecycle.DATASTORE_NAME)
lifecycleDataStore.setObject(key: V4MigrationConstants.Lifecycle.DataStoreKeys.INSTALL_DATE, value: installDate)
lifecycleDataStore.setObject(key: V4MigrationConstants.Lifecycle.DataStoreKeys.INSTALL_DATE, value: installDate as Date?)
lifecycleDataStore.set(key: V4MigrationConstants.Lifecycle.DataStoreKeys.LAST_VERSION, value: lastVersion)
lifecycleDataStore.setObject(key: V4MigrationConstants.Lifecycle.DataStoreKeys.LAST_LAUNCH_DATE, value: lastUsedDate)
lifecycleDataStore.setObject(key: V4MigrationConstants.Lifecycle.DataStoreKeys.LAST_LAUNCH_DATE, value: lastUsedDate as Date?)

let persistedDict = ["launches": launches, "successfulClose": successfulClose] as [String: Any]
let persistedData = try? JSONSerialization.data(withJSONObject: persistedDict)
let persistedData = AnyCodable.from(dictionary: persistedDict)
lifecycleDataStore.setObject(key: V4MigrationConstants.Lifecycle.DataStoreKeys.PERSISTED_CONTEXT, value: persistedData)

v4Defaults.removeObject(forKey: V4MigrationConstants.Lifecycle.V4_INSTALL_DATE)
Expand Down Expand Up @@ -208,7 +208,7 @@ struct V4Migrator {
v4Defaults.removeObject(forKey: V4MigrationConstants.Configuration.V4_PRIVACY_STATUS)
}

/// Migrates the v4 Identity values to v5 Analtyics data store
/// Migrates the v4 Identity values to v5 Analytics data store
private func migrateVisitorIdLocalStorage() {
// TODO: Implement when implementing the Analytics extension
}
Expand Down
4 changes: 2 additions & 2 deletions AEPCore/Sources/migration/V5Migrator.swift
Original file line number Diff line number Diff line change
Expand Up @@ -115,7 +115,7 @@ struct V5Migrator {

// save values
let identityDataStore = NamedCollectionDataStore(name: V5MigrationConstants.Identity.DATASTORE_NAME)
let identityPropsData = AnyCodable.from(dictionary: identityPropsDict as [String: Any])
let identityPropsData = AnyCodable.from(dictionary: identityPropsDict)
identityDataStore.setObject(key: V5MigrationConstants.Identity.DataStoreKeys.IDENTITY_PROPERTIES, value: identityPropsData)
identityDataStore.set(key: V5MigrationConstants.Identity.DataStoreKeys.PUSH_ENABLED, value: pushEnabled)

Expand Down Expand Up @@ -149,7 +149,7 @@ struct V5Migrator {
lifecycleDataStore.setObject(key: V5MigrationConstants.Lifecycle.DataStoreKeys.LAST_LAUNCH_DATE, value: Date(timeIntervalSince1970: lastUsedDateInterval))

let persistedDict = ["launches": launches, "successfulClose": successfulClose, "osVersion": osVersion, "appId": appId] as [String: Any?]
let persistedData = try? JSONSerialization.data(withJSONObject: persistedDict)
let persistedData = AnyCodable.from(dictionary: persistedDict)
lifecycleDataStore.setObject(key: V5MigrationConstants.Lifecycle.DataStoreKeys.PERSISTED_CONTEXT, value: persistedData)

v5Defaults.removeObject(forKey: keyWithPrefix(datastoreName: V5MigrationConstants.Lifecycle.LEGACY_DATASTORE_NAME, key: V5MigrationConstants.Lifecycle.INSTALL_DATE))
Expand Down
10 changes: 5 additions & 5 deletions AEPCore/Tests/MigrationTests/V4MigratorTests.swift
Original file line number Diff line number Diff line change
Expand Up @@ -52,7 +52,7 @@ class V4MigratorTests: XCTestCase {
/// Tests that data from v4 is properly migrated
func testExistingV4Data() {
// setup
let mockDate = Date()
let mockDate = NSDate()
v4Defaults.set(["acqkey": "acqvalue"], forKey: V4MigrationConstants.MobileServices.V4_ACQUISITION_DATA)
v4Defaults.set("identityIds", forKey: V4MigrationConstants.Identity.V4_IDS)
v4Defaults.set("identityECID", forKey: V4MigrationConstants.Identity.V4_ECID)
Expand Down Expand Up @@ -115,15 +115,15 @@ class V4MigratorTests: XCTestCase {
XCTAssertNotNil(mockDataStore.get(collectionName: "", key: V4MigrationConstants.Identity.DataStoreKeys.IDENTITY_PROPERTIES))
XCTAssertTrue(dataStore.getBool(key: V4MigrationConstants.Identity.DataStoreKeys.PUSH_ENABLED) ?? false)
let installDate: Date? = dataStore.getObject(key: V4MigrationConstants.Lifecycle.DataStoreKeys.INSTALL_DATE, fallback: nil)
XCTAssertEqual(mockDate, installDate)
XCTAssertEqual(mockDate as Date?, installDate)
XCTAssertNotNil(mockDataStore.get(collectionName: "", key: V4MigrationConstants.Lifecycle.DataStoreKeys.PERSISTED_CONTEXT))
XCTAssertEqual("version", dataStore.getString(key: V4MigrationConstants.Lifecycle.DataStoreKeys.LAST_VERSION))
let lastUsedDate: Date? = dataStore.getObject(key: V4MigrationConstants.Lifecycle.DataStoreKeys.LAST_LAUNCH_DATE, fallback: nil)
XCTAssertEqual(mockDate, lastUsedDate)
XCTAssertEqual(mockDate as Date?, lastUsedDate)
let msInstallDate: Date? = dataStore.getObject(key: V4MigrationConstants.MobileServices.INSTALL, fallback: nil)
XCTAssertEqual(mockDate, msInstallDate)
XCTAssertEqual(mockDate as Date?, msInstallDate)
let msSeachAdInstallDate: Date? = dataStore.getObject(key: V4MigrationConstants.MobileServices.INSTALL_SEARCH_AD, fallback: nil)
XCTAssertEqual(mockDate, msSeachAdInstallDate)
XCTAssertEqual(mockDate as Date?, msSeachAdInstallDate)
XCTAssertNotNil(mockDataStore.get(collectionName: "", key: V4MigrationConstants.MobileServices.V5_IN_APP_EXCLUDE_LIST))
let storedConfig: [String: AnyCodable]? = dataStore.getObject(key: ConfigurationConstants.DataStoreKeys.PERSISTED_OVERRIDDEN_CONFIG)
XCTAssertEqual("optedout", storedConfig?["global.privacy"]?.stringValue)
Expand Down
21 changes: 12 additions & 9 deletions AEPServices/Sources/utility/AnyCodable.swift
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,11 @@ import Foundation

/// A type erasing struct that can allow for dynamic `Codable` types
public struct AnyCodable: Codable {
public let value: Any?
public var value: Any? {
return _value is NSNull ? nil : _value
}

private let _value: Any

public var stringValue: String? {
return value as? String
Expand Down Expand Up @@ -53,10 +57,10 @@ public struct AnyCodable: Codable {
}

public init(_ value: Any?) {
self.value = value
self._value = value ?? NSNull()
}

public static func from(dictionary: [String: Any]?) -> [String: AnyCodable]? {
public static func from(dictionary: [String: Any?]?) -> [String: AnyCodable]? {
guard let unwrappedDict = dictionary else { return nil }

var newDict: [String: AnyCodable] = [:]
Expand Down Expand Up @@ -109,12 +113,11 @@ public struct AnyCodable: Codable {
public func encode(to encoder: Encoder) throws {
var container = encoder.singleValueContainer()

guard value != nil else {
switch _value {
case is NSNull:
try container.encodeNil()
case is Void:
try container.encodeNil()
return
}

switch value {
case let num as NSNumber:
try encode(nsNumber: num, into: &container)
case let string as String:
Expand All @@ -136,7 +139,7 @@ public struct AnyCodable: Codable {
case let dictionary as [String: Any?]:
try container.encode(dictionary.mapValues { AnyCodable($0) })
default:
print("AnyCodable - encode: Failed to encode \(String(describing: value))")
print("AnyCodable - encode: Failed to encode \(String(describing: _value))")
}
}

Expand Down
10 changes: 9 additions & 1 deletion AEPServices/Tests/utility/AnyCodableTests.swift
Original file line number Diff line number Diff line change
Expand Up @@ -83,6 +83,7 @@ class AnyCodableTests: XCTestCase {
"intKey1": 1,
"intKey2": 0,
"intKey3": AnyCodable(NSNumber(0)),
"nullKey": nil
]

let json = try JSONEncoder().encode(dictionary)
Expand All @@ -96,7 +97,8 @@ class AnyCodableTests: XCTestCase {
"intKey": 123,
"intKey1": 1,
"intKey2": 0,
"intKey3": 0
"intKey3": 0,
"nullKey": null
}
""".data(using: .utf8)!
let expectedJSONObject = try JSONSerialization.jsonObject(with: expected, options: []) as! NSDictionary
Expand Down Expand Up @@ -151,4 +153,10 @@ class AnyCodableTests: XCTestCase {

XCTAssertEqual(encodedJSONObject, expectedJSONObject)
}

func testInitWithNil() {
let nilAny = AnyCodable(nil)

XCTAssertNil(nilAny.value)
}
}

0 comments on commit e3ea968

Please sign in to comment.