Skip to content

Commit

Permalink
Target SDK should attach response tokens in the retrieveLocationConte…
Browse files Browse the repository at this point in the history
…nt data callback (#155) (#156) (#157)

* Target SDK should attach response tokens in the retrieveLocationContent data callback

* Minor fixes

* • reverted dependency updates
 • updated test constants

* revert podfile.lock

* Fixed tests after migration from UserDefaults to file system.

* minor cleanup

* Additional test + doc update

Co-authored-by: Steve Benedick <sbenedic@adobe.com>
  • Loading branch information
swarna04 and sbenedicadb committed Jan 26, 2024
1 parent 7c38e04 commit 0232e6b
Show file tree
Hide file tree
Showing 18 changed files with 129 additions and 103 deletions.
2 changes: 1 addition & 1 deletion AEPTarget.podspec
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
Pod::Spec.new do |s|
s.name = "AEPTarget"
s.version = "4.0.2"
s.version = "4.0.3"
s.summary = "Experience Platform Target extension for Adobe Experience Platform Mobile SDK. Written and maintained by Adobe."
s.description = <<-DESC
The Experience Platform Target extension provides APIs that allow use of the Target product in the Adobe Experience Platform SDK.
Expand Down
8 changes: 6 additions & 2 deletions AEPTarget.xcodeproj/project.pbxproj
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@
091AB3E2288636F400E43F23 /* TargetTntIdFunctionalTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 091AB3E1288636F400E43F23 /* TargetTntIdFunctionalTests.swift */; };
0932CAF228DC5D3800BE99E2 /* Dictionary+Target.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0932CAF128DC5D3800BE99E2 /* Dictionary+Target.swift */; };
0932CAF428DD0D2200BE99E2 /* TargetRawRequestsFunctionalTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0932CAF328DD0D2200BE99E2 /* TargetRawRequestsFunctionalTests.swift */; };
09F5D94B2B60912F00117437 /* NamedCollectionDataStore+clear.swift in Sources */ = {isa = PBXBuildFile; fileRef = 09F5D9492B6090F900117437 /* NamedCollectionDataStore+clear.swift */; };
21BB6EAE22D5AC72C15DB97C /* Pods_AEPTargetTests.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 639B326C68E1444919C98676 /* Pods_AEPTargetTests.framework */; };
54A53C0BFA0D61EF50B9E5C5 /* Pods_AEPTargetDemoApp.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 45A74BEED420E4145D1D72CC /* Pods_AEPTargetDemoApp.framework */; };
780DF565258924B70033F107 /* URL+Target.swift in Sources */ = {isa = PBXBuildFile; fileRef = 780DF564258924B70033F107 /* URL+Target.swift */; };
Expand Down Expand Up @@ -168,6 +169,7 @@
091AB3E1288636F400E43F23 /* TargetTntIdFunctionalTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TargetTntIdFunctionalTests.swift; sourceTree = "<group>"; };
0932CAF128DC5D3800BE99E2 /* Dictionary+Target.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "Dictionary+Target.swift"; sourceTree = "<group>"; };
0932CAF328DD0D2200BE99E2 /* TargetRawRequestsFunctionalTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TargetRawRequestsFunctionalTests.swift; sourceTree = "<group>"; };
09F5D9492B6090F900117437 /* NamedCollectionDataStore+clear.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "NamedCollectionDataStore+clear.swift"; sourceTree = "<group>"; };
1F937F0708662CB013507FEA /* Pods-AEPTarget.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-AEPTarget.debug.xcconfig"; path = "Target Support Files/Pods-AEPTarget/Pods-AEPTarget.debug.xcconfig"; sourceTree = "<group>"; };
22CDBB0E77B419D5D7E526F3 /* Pods-AEPTarget.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-AEPTarget.release.xcconfig"; path = "Target Support Files/Pods-AEPTarget/Pods-AEPTarget.release.xcconfig"; sourceTree = "<group>"; };
2781B11116AD0207B40F67F0 /* Pods_AEPTargetDemoObjCApp.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = Pods_AEPTargetDemoObjCApp.framework; sourceTree = BUILT_PRODUCTS_DIR; };
Expand Down Expand Up @@ -507,6 +509,7 @@
BB8FF11C2602A72C006C80D9 /* UserDefaults+clear.swift */,
BBC428DA26166360006E4A3F /* MockNetworkService.swift */,
786C00E225C35EEB00F26D34 /* TargetTestConstants.swift */,
09F5D9492B6090F900117437 /* NamedCollectionDataStore+clear.swift */,
);
path = TestHelpers;
sourceTree = "<group>";
Expand Down Expand Up @@ -913,6 +916,7 @@
924102A1260C01CA00DA88D2 /* MockPreviewManagerUIDelegate.swift in Sources */,
BB1DBE9025D22C3D00DDBA15 /* Target+PublicAPITests.swift in Sources */,
BB9C86EF255C9C90007AEF8B /* Event+TargetTests.swift in Sources */,
09F5D94B2B60912F00117437 /* NamedCollectionDataStore+clear.swift in Sources */,
BB861104261B663B00A39187 /* TargetFunctionalTests.swift in Sources */,
BB8FF1262602A72C006C80D9 /* MockUIService.swift in Sources */,
BB8FF1252602A72C006C80D9 /* UserDefaults+clear.swift in Sources */,
Expand Down Expand Up @@ -1174,7 +1178,7 @@
"@executable_path/Frameworks",
"@loader_path/Frameworks",
);
MARKETING_VERSION = 4.0.2;
MARKETING_VERSION = 4.0.3;
PRODUCT_BUNDLE_IDENTIFIER = com.adobe.aep.target;
PRODUCT_NAME = "$(TARGET_NAME:c99extidentifier)";
PROVISIONING_PROFILE_SPECIFIER = "";
Expand Down Expand Up @@ -1205,7 +1209,7 @@
"@executable_path/Frameworks",
"@loader_path/Frameworks",
);
MARKETING_VERSION = 4.0.2;
MARKETING_VERSION = 4.0.3;
PRODUCT_BUNDLE_IDENTIFIER = com.adobe.aep.target;
PRODUCT_NAME = "$(TARGET_NAME:c99extidentifier)";
PROVISIONING_PROFILE_SPECIFIER = "";
Expand Down
8 changes: 4 additions & 4 deletions AEPTarget/Sources/Target.swift
Original file line number Diff line number Diff line change
Expand Up @@ -1074,17 +1074,17 @@ public class Target: NSObject, Extension {
/// - Parameters:
/// - mboxJson: `[String: Any]` target response dictionary
/// - Returns: tuple containg `String` mbox content and `Dictionary` containing response tokens, if any.
private func extractMboxContentAndResponseTokens(mboxJson: [String: Any]) -> (content: String?, responseTokens: [String: String]?) {
private func extractMboxContentAndResponseTokens(mboxJson: [String: Any]) -> (content: String?, responseTokens: [String: Any]?) {
guard let optionsArray = mboxJson[TargetConstants.TargetJson.OPTIONS] as? [[String: Any?]?] else {
Log.debug(label: Target.LOG_TAG, "extractMboxContent - unable to extract mbox contents, options array is nil")
return (nil, nil)
}

var contentBuilder = ""
var responseTokens: [String: String]?
var responseTokens: [String: Any]?

for option in optionsArray {
responseTokens = option?[TargetConstants.TargetJson.Option.RESPONSE_TOKENS] as? [String: String]
responseTokens = option?[TargetConstants.TargetJson.Option.RESPONSE_TOKENS] as? [String: Any]

guard let content = option?[TargetConstants.TargetJson.Option.CONTENT] else {
continue
Expand Down Expand Up @@ -1190,7 +1190,7 @@ public class Target: NSObject, Extension {
/// - analyticsPayload: dictionary containing analytics for target (a4t) payload.
/// - metricsAnalyticsPayload: dictionary containing a4t payload for click metric.
/// - Returns: `Dictionary` containing Target payload or nil.
private func packageMboxResponsePayload(responseTokens: [String: String]?,
private func packageMboxResponsePayload(responseTokens: [String: Any]?,
analyticsPayload: [String: String]?,
metricsAnalyticsPayload: [String: String]?)
-> [String: Any]? {
Expand Down
2 changes: 1 addition & 1 deletion AEPTarget/Sources/TargetConstants.swift
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ import Foundation
enum TargetConstants {
static let EXTENSION_NAME = "com.adobe.module.target"
static let FRIENDLY_NAME = "Target"
static let EXTENSION_VERSION = "4.0.2"
static let EXTENSION_VERSION = "4.0.3"
static let DATASTORE_NAME = EXTENSION_NAME
static let DEFAULT_SESSION_TIMEOUT: Int = 30 * 60 // 30 mins
static let DELIVERY_API_URL_BASE = "https://%@/rest/v1/delivery/?client=%@&sessionId=%@"
Expand Down
16 changes: 8 additions & 8 deletions AEPTarget/Tests/FunctionalTests/TargetFunctionalTests.swift
Original file line number Diff line number Diff line change
Expand Up @@ -254,10 +254,10 @@ class TargetFunctionalTests: TargetFunctionalTestsBase {
// MARK: - Session testing

func testIfSessionTimeOut_useNewSessionIdAndDefaultEdgeHostInTargetReqeust() {
cleanUserDefaults()
getUserDefaults().setValue(1_617_825_969, forKey: "Adobe.com.adobe.module.target.session.timestamp")
getUserDefaults().setValue("935CDD24-8FD7-4B30-8508-4BE40C3FC263", forKey: "Adobe.com.adobe.module.target.session.id")
getUserDefaults().setValue("mboxedge35.tt.omtrdc.net", forKey: "Adobe.com.adobe.module.target.edge.host")
NamedCollectionDataStore.clear()
getTargetDataStore().set(key: "session.timestamp", value: 1_617_825_969)
getTargetDataStore().set(key: "session.id", value: "935CDD24-8FD7-4B30-8508-4BE40C3FC263")
getTargetDataStore().set(key: "edge.host", value: "mboxedge35.tt.omtrdc.net")
mockRuntime = TestableExtensionRuntime()
target = Target(runtime: mockRuntime)
target.onRegistered()
Expand Down Expand Up @@ -297,8 +297,8 @@ class TargetFunctionalTests: TargetFunctionalTestsBase {
}

func testIfNotSessionTimeOut_useSameSessionIdAndNewEdgeHostInTargetReqeust() {
cleanUserDefaults()
getUserDefaults().setValue(Date().getUnixTimeInSeconds(), forKey: "Adobe.com.adobe.module.target.session.timestamp")
NamedCollectionDataStore.clear()
getTargetDataStore().set(key: "session.timestamp", value: Date().getUnixTimeInSeconds())
mockRuntime = TestableExtensionRuntime()
target = Target(runtime: mockRuntime)
target.onRegistered()
Expand Down Expand Up @@ -399,9 +399,9 @@ class TargetFunctionalTests: TargetFunctionalTestsBase {
}

func testSessionTimestampIsNotUpdatedWhenSendingRequestFails() {
cleanUserDefaults()
NamedCollectionDataStore.clear()
let sessionTimestamp = Date().getUnixTimeInSeconds()
getUserDefaults().setValue(sessionTimestamp, forKey: "Adobe.com.adobe.module.target.session.timestamp")
getTargetDataStore().set(key: "session.timestamp", value: sessionTimestamp)
mockRuntime = TestableExtensionRuntime()
target = Target(runtime: mockRuntime)
target.onRegistered()
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -57,6 +57,8 @@ class TargetFunctionalTestsBase: XCTestCase {
]

cleanUserDefaults()
NamedCollectionDataStore.clear()

mockRuntime = TestableExtensionRuntime()
target = Target(runtime: mockRuntime)
target.previewManager = mockPreviewManager
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -23,8 +23,9 @@ class TargetMigrationFunctionalTests: TargetFunctionalTestsBase {
}

func testTargetInitWithDataMigrationFromV5() {
let userDefaultsV5 = getUserDefaults()
cleanUserDefaults()
NamedCollectionDataStore.clear()
let userDefaultsV5 = getUserDefaults()

let timestamp = Date().getUnixTimeInSeconds()
userDefaultsV5.set("edge.host.com", forKey: "Adobe.ADOBEMOBILE_TARGET.EDGE_HOST")
Expand All @@ -42,9 +43,11 @@ class TargetMigrationFunctionalTests: TargetFunctionalTestsBase {
}

func testTargetInitWithDataMigrationFromV4() {
cleanUserDefaults()
NamedCollectionDataStore.clear()

let userDefaultsV4 = getUserDefaults()
let targetDataStore = getTargetDataStore()
cleanUserDefaults()

userDefaultsV4.set("id_1", forKey: "ADBMOBILE_TARGET_TNT_ID")
userDefaultsV4.set("id_2", forKey: "ADBMOBILE_TARGET_3RD_PARTY_ID")
Expand Down
27 changes: 18 additions & 9 deletions AEPTarget/Tests/IntegrationTests/TargetIntegrationTests.swift
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,7 @@ class TargetIntegrationTests: XCTestCase {
private let dispatchQueue = DispatchQueue(label: "com.adobe.target.test")
override func setUp() {
FileManager.default.clear()
UserDefaults.clear()
NamedCollectionDataStore.clear()
ServiceProvider.shared.reset()
EventHub.reset()
}
Expand Down Expand Up @@ -715,7 +715,9 @@ class TargetIntegrationTests: XCTestCase {
"content": "someContent",
"type": "html",
"responseTokens":{
"activity.name":"My test activity"
"activity.name":"My test activity",
"profile.categoryAffinities":["shoes"],
"someKey":["someValue", true, 42]
}
}
],
Expand Down Expand Up @@ -766,9 +768,14 @@ class TargetIntegrationTests: XCTestCase {
XCTAssertEqual("tnt", analyticsPayload?["pe"])
XCTAssertEqual("331289:0:0|2|1,331289:0:0|32767|1", analyticsPayload?["tnta"])

let responseTokens = data["responseTokens"] as? [String: String]
XCTAssertEqual(1, responseTokens?.count)
XCTAssertEqual("My test activity", responseTokens?["activity.name"])
let responseTokens = data["responseTokens"] as? [String: Any]
XCTAssertEqual(3, responseTokens?.count)
XCTAssertEqual("My test activity", responseTokens?["activity.name"] as? String)
XCTAssertEqual(["shoes"], responseTokens?["profile.categoryAffinities"] as? [String])
let someArr = responseTokens?["someKey"] as? [Any]
XCTAssertEqual("someValue", someArr?[0] as? String)
XCTAssertEqual(true, someArr?[1] as? Bool)
XCTAssertEqual(42, someArr?[2] as? Int)
targetRequestExpectation.fulfill()
}

Expand Down Expand Up @@ -797,7 +804,8 @@ class TargetIntegrationTests: XCTestCase {
"content": "someContent",
"type": "html",
"responseTokens":{
"activity.name":"My test activity"
"activity.name":"My test activity",
"profile.categoryAffinities":["shoes"]
},
"eventToken": "uR0kIAPO+tZtIPW92S0NnWqipfsIHvVzTQxHolz2IpSCnQ9Y9OaLL2gsdrWQTvE54PwSz67rmXWmSnkXpSSS2Q=="
}
Expand Down Expand Up @@ -862,9 +870,10 @@ class TargetIntegrationTests: XCTestCase {
XCTAssertEqual("tnt", analyticsPayload?["pe"])
XCTAssertEqual("331289:0:0|2|1,331289:0:0|32767|1", analyticsPayload?["tnta"])

let responseTokens = data["responseTokens"] as? [String: String]
XCTAssertEqual(1, responseTokens?.count)
XCTAssertEqual("My test activity", responseTokens?["activity.name"])
let responseTokens = data["responseTokens"] as? [String: Any]
XCTAssertEqual(2, responseTokens?.count)
XCTAssertEqual("My test activity", responseTokens?["activity.name"] as? String)
XCTAssertEqual(["shoes"], responseTokens?["profile.categoryAffinities"] as? [String])
targetRequestExpectation.fulfill()
}
Target.retrieveLocationContent([retrieveRequest])
Expand Down
38 changes: 38 additions & 0 deletions AEPTarget/Tests/TestHelpers/NamedCollectionDataStore+clear.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
/*
Copyright 2024 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

extension NamedCollectionDataStore {
static func clear(appGroup: String? = nil) {
if let appGroup = appGroup, !appGroup.isEmpty {
guard let directory = FileManager.default.containerURL(forSecurityApplicationGroupIdentifier: appGroup)?.appendingPathComponent("com.adobe.aep.datastore", isDirectory: true).path else {
return
}
guard let filePaths = try? FileManager.default.contentsOfDirectory(atPath: directory) else {
return
}
for filePath in filePaths {
try? FileManager.default.removeItem(atPath: directory + "/" + filePath)
}
} else {
let directory = FileManager.default.urls(for: .libraryDirectory, in: .allDomainsMask)[0].appendingPathComponent("com.adobe.aep.datastore", isDirectory: true).path
guard let filePaths = try? FileManager.default.contentsOfDirectory(atPath: directory) else {
return
}
for filePath in filePaths {
try? FileManager.default.removeItem(atPath: directory + "/" + filePath)
}
}
}
}
2 changes: 1 addition & 1 deletion AEPTarget/Tests/TestHelpers/TargetTestConstants.swift
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@
*/

enum TargetTestConstants {
static let EXTENSION_VERSION = "4.0.2"
static let EXTENSION_VERSION = "4.0.3"
// preview parameters
static let PREVIEW_MESSAGE_ID = "target-preview-message-id"
static let PREVIEW_PARAMETERS = "at_preview_params"
Expand Down
18 changes: 14 additions & 4 deletions AEPTarget/Tests/TestHelpers/UserDefaults+clear.swift
Original file line number Diff line number Diff line change
Expand Up @@ -12,10 +12,20 @@
import Foundation

extension UserDefaults {
static func clear() {
for _ in 0 ... 5 {
for key in UserDefaults.standard.dictionaryRepresentation().keys {
UserDefaults.standard.removeObject(forKey: key)
static func clear(appGroup: String? = nil) {
if let appGroup = appGroup,
!appGroup.isEmpty,
let userDefaults = UserDefaults(suiteName: appGroup) {
for _ in 0 ... 5 {
for key in userDefaults.dictionaryRepresentation().keys {
userDefaults.removeObject(forKey: key)
}
}
} else {
for _ in 0 ... 5 {
for key in UserDefaults.standard.dictionaryRepresentation().keys {
UserDefaults.standard.removeObject(forKey: key)
}
}
}
}
Expand Down
2 changes: 1 addition & 1 deletion AEPTarget/Tests/UnitTests/TargetStateTests.swift
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@ import XCTest

class TargetStateTests: XCTestCase {
override func setUpWithError() throws {
UserDefaults.clear()
NamedCollectionDataStore.clear()
ServiceProvider.shared.namedKeyValueService.setAppGroup(nil)
}

Expand Down
26 changes: 0 additions & 26 deletions AEPTarget/Tests/UnitTests/TargetTests.swift
Original file line number Diff line number Diff line change
Expand Up @@ -25,32 +25,6 @@ class TargetTests: XCTestCase {
target.onRegistered()
}

private func cleanUserDefaults() {
for _ in 0 ... 5 {
for key in getUserDefaults().dictionaryRepresentation().keys {
UserDefaults.standard.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 getUserDefaults() -> UserDefaults {
if let appGroup = ServiceProvider.shared.namedKeyValueService.getAppGroup(), !appGroup.isEmpty {
return UserDefaults(suiteName: appGroup) ?? UserDefaults.standard
}

return UserDefaults.standard
}

// MARK: - Unit Tests

func testRegisterExtension() {
Expand Down
17 changes: 5 additions & 12 deletions AEPTarget/Tests/UnitTests/TargetV4MigratorTests.swift
Original file line number Diff line number Diff line change
Expand Up @@ -19,18 +19,11 @@ 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)
}
}
UserDefaults.clear()
UserDefaults.clear(appGroup: appGroup)

NamedCollectionDataStore.clear()
NamedCollectionDataStore.clear(appGroup: appGroup)

ServiceProvider.shared.namedKeyValueService.setAppGroup(nil)
}
Expand Down
17 changes: 5 additions & 12 deletions AEPTarget/Tests/UnitTests/TargetV5MigratorTests.swift
Original file line number Diff line number Diff line change
Expand Up @@ -19,18 +19,11 @@ 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)
}
}
UserDefaults.clear()
UserDefaults.clear(appGroup: appGroup)

NamedCollectionDataStore.clear()
NamedCollectionDataStore.clear(appGroup: appGroup)

ServiceProvider.shared.namedKeyValueService.setAppGroup(nil)
}
Expand Down
Loading

0 comments on commit 0232e6b

Please sign in to comment.