Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[PLATIR-35300] Add array replace token support #988

Merged
merged 10 commits into from
Jan 18, 2024
4 changes: 4 additions & 0 deletions AEPCore.xcodeproj/project.pbxproj
Original file line number Diff line number Diff line change
Expand Up @@ -362,6 +362,7 @@
75550A3F2A9930A500747BB7 /* NamedCollectionDataStoreFunctionalTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 75550A3E2A9930A500747BB7 /* NamedCollectionDataStoreFunctionalTests.swift */; };
75C0D9052A9D545100EF74BC /* DatastoreUtilities.swift in Sources */ = {isa = PBXBuildFile; fileRef = 75C0D9042A9D545100EF74BC /* DatastoreUtilities.swift */; };
75C0D9062AA1287B00EF74BC /* AEPServicesMocks.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 3FE6DDA924C62C090065EA05 /* AEPServicesMocks.framework */; };
75ED44D12B56F0B400F2CEB1 /* rules_testAttachDataArray.json in Resources */ = {isa = PBXBuildFile; fileRef = 75ED44D02B56F0B300F2CEB1 /* rules_testAttachDataArray.json */; };
7814B23325CB455200841429 /* URL+Validator.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7814B23225CB455200841429 /* URL+Validator.swift */; };
786C000525B8EE2100F26D34 /* DefaultHeadersFormatter.swift in Sources */ = {isa = PBXBuildFile; fileRef = 786C000425B8EE2100F26D34 /* DefaultHeadersFormatter.swift */; };
786C001525B8EE6200F26D34 /* HttpConnectionConstants.swift in Sources */ = {isa = PBXBuildFile; fileRef = 786C001425B8EE6200F26D34 /* HttpConnectionConstants.swift */; };
Expand Down Expand Up @@ -1058,6 +1059,7 @@
75408CF62948EA0A00C44CE1 /* AtomicCounterTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AtomicCounterTests.swift; sourceTree = "<group>"; };
75550A3E2A9930A500747BB7 /* NamedCollectionDataStoreFunctionalTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = NamedCollectionDataStoreFunctionalTests.swift; sourceTree = "<group>"; };
75C0D9042A9D545100EF74BC /* DatastoreUtilities.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = DatastoreUtilities.swift; sourceTree = "<group>"; };
75ED44D02B56F0B300F2CEB1 /* rules_testAttachDataArray.json */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.json; path = rules_testAttachDataArray.json; sourceTree = "<group>"; };
7814B23225CB455200841429 /* URL+Validator.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "URL+Validator.swift"; sourceTree = "<group>"; };
786C000425B8EE2100F26D34 /* DefaultHeadersFormatter.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = DefaultHeadersFormatter.swift; sourceTree = "<group>"; };
786C001425B8EE6200F26D34 /* HttpConnectionConstants.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = HttpConnectionConstants.swift; sourceTree = "<group>"; };
Expand Down Expand Up @@ -1854,6 +1856,7 @@
3F08FF9A24DA0DA100D34DE3 /* rules_functional_1.zip */,
BBA512B624F6C4D90030DAD1 /* rules_testAttachData_invalidJson.json */,
BBA512B124F5CF380030DAD1 /* rules_testAttachData.json */,
75ED44D02B56F0B300F2CEB1 /* rules_testAttachDataArray.json */,
BF4A6EB726BB3B9D00612434 /* rules_testDispatchEventCopy.json */,
BF4A6F2326BB4A1A00612434 /* rules_testDispatchEventInvalidAction.json */,
BF4A6F8C26BBAE6500612434 /* rules_testDispatchEventChain.json */,
Expand Down Expand Up @@ -2664,6 +2667,7 @@
BB3E86E224F975E000E39C53 /* rules_testMatcherWithDifferentTypesOfParameters.json in Resources */,
3F39520D24CA096100F7325B /* ADBMobileConfig.json in Resources */,
24A1FCE72704CE6000D28D26 /* rules_testHistory.json in Resources */,
75ED44D12B56F0B400F2CEB1 /* rules_testAttachDataArray.json in Resources */,
BBA5129D24F4899B0030DAD1 /* rules_testMatcherGt.json in Resources */,
BF4A6F0526BB48A200612434 /* rules_testDispatchEventNewNoData.json in Resources */,
BF4A6F2826BB4A1B00612434 /* rules_testDispatchEventNoSource.json in Resources */,
Expand Down
6 changes: 3 additions & 3 deletions AEPCore/Sources/migration/UserDefaultMigrationConstants.swift
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@
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 Foundation

Expand Down Expand Up @@ -177,15 +177,15 @@ enum UserDefaultMigratorConstants {
static let DATASTORE_NAME = "com.adobe.edge.identity"

enum DataStoreKeys: String, CaseIterable {
case IDENTITY_PROPERTIES = "identity.properties"
case IDENTITY_PROPERTIES = "identity.properties"
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Did we commit unformatted files earlier, or is there any change in Swift format version that we're using?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm not too sure how this happened. I just ran swiftformat locally and committed.

}
}

enum EdgeConsent {
static let DATASTORE_NAME = "com.adobe.edge.consent"

enum DataStoreKeys: String, CaseIterable {
case CONSENT_PREFERENCES = "consent.preferences"
case CONSENT_PREFERENCES = "consent.preferences"
}
}
}
2 changes: 1 addition & 1 deletion AEPCore/Sources/migration/UserDefaultsMigrator.swift
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@
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 Foundation
import AEPServices
Expand Down
27 changes: 19 additions & 8 deletions AEPCore/Sources/rules/LaunchRulesEngine.swift
Original file line number Diff line number Diff line change
Expand Up @@ -284,22 +284,33 @@ public class LaunchRulesEngine {
return RuleConsequence(id: consequence.id, type: consequence.type, details: dict)
}

private func replaceToken(in value: Any, data: Traversable) -> Any {
switch value {
case let valString as String:
return replaceToken(for: valString, data: data)
case let nestedDict as [String: Any?]:
return replaceToken(in: nestedDict, data: data)
case let nestedArray as [Any]:
return replaceToken(in: nestedArray, data: data)
default:
return value
}
}

private func replaceToken(in dict: [String: Any?], data: Traversable) -> [String: Any?] {
var mutableDict = dict
for (key, value) in mutableDict {
switch value {
case is String:
mutableDict[key] = replaceToken(for: value as! String, data: data)
case is [String: Any]:
let valueDict = mutableDict[key] as! [String: Any]
mutableDict[key] = replaceToken(in: valueDict, data: data)
default:
break
if let value = value {
mutableDict[key] = replaceToken(in: value, data: data)
}
}
return mutableDict
}

private func replaceToken(in array: [Any], data: Traversable) -> [Any] {
return array.map { replaceToken(in: $0, data: data) }
}

private func replaceToken(for value: String, data: Traversable) -> String {
let template = Template(templateString: value, tagDelimiterPair: (LaunchRulesEngine.LAUNCH_RULE_TOKEN_LEFT_DELIMITER, LaunchRulesEngine.LAUNCH_RULE_TOKEN_RIGHT_DELIMITER))
return template.render(data: data, transformers: transformer)
Expand Down
56 changes: 56 additions & 0 deletions AEPCore/Tests/FunctionalTests/RulesEngineFunctionalTests.swift
Original file line number Diff line number Diff line change
Expand Up @@ -508,6 +508,62 @@ class RulesEngineFunctionalTests: XCTestCase {
XCTAssertEqual("", attachedData["launches"] as? String)
}

func testAttachDataArray() {
/// Given: a launch rule to attach data to event

// ---------- attach data rule ----------
// "eventdata": {
// "attached_data_array": [
// "{%~state.com.adobe.module.lifecycle/lifecyclecontextdata.carriername%}",
// "testStringTopLevel",
// {
// "testDictKey": "testVal",
// "osversionNested": "{%~state.com.adobe.module.lifecycle/lifecyclecontextdata.osversion%}"
//
// }, [
// "{%~state.com.adobe.module.lifecycle/lifecyclecontextdata.osversion%}",
// "testStringInsideNestedArray"
// ]
// ]
// }
// --------------------------------------

resetRulesEngine(withNewRules: "rules_testAttachDataArray")

/// When: evaluating a launch event

// ------------ launch event ------------
// "eventdata": {
// "lifecyclecontextdata": {
// "launchevent": "LaunchEvent"
// }
// }
// --------------------------------------


mockRuntime.simulateSharedState(for: "com.adobe.module.lifecycle", data: (value: ["lifecyclecontextdata": ["carriername": "AT&T", "osversion": "17.0"]], status: .set))
let processedEvent = rulesEngine.process(event: defaultEvent)

/// Then: no consequence event will be dispatched
XCTAssertEqual(0, mockRuntime.dispatchedEvents.count)
guard let attachedData = processedEvent.data?["attached_data_array"] as? [Any] else {
XCTFail()
return
}
// Token replaces values
XCTAssertEqual(attachedData[0] as? String, "AT&T")
// non token replaced string
XCTAssertEqual(attachedData[1] as? String, "testStringTopLevel")
// Dict with token replaced string, and non token replaced string
let dict = attachedData[2] as? [String: Any?]
XCTAssertEqual(dict?["testDictKey"] as? String, "testVal")
XCTAssertEqual(dict?["osversionNested"] as? String, "17.0")
let arr = attachedData[3] as? [Any]
XCTAssertEqual(arr?[0] as? String, "17.0")
XCTAssertEqual(arr?[1] as? String, "testStringInsideNestedArray")

}

func testAttachData_invalidJson() {
/// Given: a launch rule to attach data to event

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@
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 XCTest
@testable import AEPCore
Expand Down
101 changes: 101 additions & 0 deletions AEPCore/Tests/TestResources/rules_testAttachDataArray.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,101 @@
{
"version": 1,
"rules": [
{
"condition": {
"type": "group",
"definition": {
"logic": "and",
"conditions": [
{
"type": "group",
"definition": {
"logic": "or",
"conditions": [
{
"type": "group",
"definition": {
"logic": "and",
"conditions": [
{
"type": "matcher",
"definition": {
"key": "~type",
"matcher": "eq",
"values": [
"com.adobe.eventType.lifecycle"
]
}
},
{
"type": "matcher",
"definition": {
"key": "~source",
"matcher": "eq",
"values": [
"com.adobe.eventSource.responseContent"
]
}
},
{
"type": "matcher",
"definition": {
"key": "lifecyclecontextdata.launchevent",
"matcher": "ex",
"values": []
}
}
]
}
}
]
}
},
{
"type": "group",
"definition": {
"logic": "and",
"conditions": [
{
"type": "matcher",
"definition": {
"key": "~state.com.adobe.module.lifecycle/lifecyclecontextdata.carriername",
"matcher": "eq",
"values": [
"AT&T"
]
}
}
]
}
}
]
}
},
"consequences": [
{
"id": "RCa839e401f54a459a9049328f9b609a07",
"type": "add",
"detail": {
"eventdata": {
"attached_data_array": [
"{%~state.com.adobe.module.lifecycle/lifecyclecontextdata.carriername%}",
"testStringTopLevel",
{
"testDictKey": "testVal",
"osversionNested": "{%~state.com.adobe.module.lifecycle/lifecyclecontextdata.osversion%}"

}, [
"{%~state.com.adobe.module.lifecycle/lifecyclecontextdata.osversion%}",
"testStringInsideNestedArray",
null
],
null
]
}
}
}
]
}
]
}
6 changes: 3 additions & 3 deletions AEPIntegrationTests/IdentityIntegrationTests.swift
Original file line number Diff line number Diff line change
Expand Up @@ -359,17 +359,17 @@ class IdentityIntegrationTests: XCTestCase {
MobileCore.resetIdentities()

wait(for: [resetHitExpectation], timeout: 2)

// Wait for 500ms so that the new ECID gets persisted and to avoid race conditions
usleep(500)

// assert new ECID on last hit
props.loadFromPersistence()
guard let newEcid = props.ecid else {
XCTFail("New ECID is not generated")
return
}

XCTAssertNotEqual(firstEcid.ecidString, newEcid.ecidString)
XCTAssertTrue(mockNetworkService.requests[0].url.absoluteString.contains(newEcid.ecidString))
XCTAssertFalse(mockNetworkService.requests[0].url.absoluteString.contains(firstEcid.ecidString))
Expand Down
4 changes: 2 additions & 2 deletions AEPServices/Sources/cache/DiskCacheService.swift
Original file line number Diff line number Diff line change
Expand Up @@ -28,12 +28,12 @@ class DiskCacheService: Caching {
try createDirectoryIfNeeded(cacheName: cacheName)
let path = filePath(for: cacheName, with: key)
_ = fileManager.createFile(atPath: path, contents: entry.data, attributes: nil)

var newMetadata = [METADATA_KEY_PATH: path]
if let meta = entry.metadata, !meta.isEmpty {
newMetadata.merge(meta) { current, _ in current }
}

var attributes: [String: Any] = [
EXPIRY_DATE: entry.expiry.date.timeIntervalSince1970,
METADATA: newMetadata
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -104,7 +104,7 @@ class FileSystemNamedCollection: NamedCollectionProcessing {
Log.warning(label: LOG_TAG, "Failed to read dictionary from collection '\(collectionName)'")
return nil
}

return jsonResult
}

Expand Down
4 changes: 2 additions & 2 deletions AEPServices/Tests/services/DiskCacheServiceTests.swift
Original file line number Diff line number Diff line change
Expand Up @@ -83,7 +83,7 @@ class DiskCacheServiceTests: XCTestCase {
let storedEntry = diskCache.get(cacheName: CACHE_NAME, key: ENTRY_KEY)
XCTAssertTrue(originalEntry(entry, equals: storedEntry!))
}

func testSetGetMissingAttributes() {
// setup
let data = "Test".data(using: .utf8)!
Expand All @@ -97,7 +97,7 @@ class DiskCacheServiceTests: XCTestCase {
// verify
XCTAssertNil(diskCache.get(cacheName: CACHE_NAME, key: ENTRY_KEY))
}

func testSetGetMissingExpiryDate() {
// setup
let data = "Test".data(using: .utf8)!
Expand Down
6 changes: 3 additions & 3 deletions TestApps/TestApp_Swift/AppDelegate.swift
Original file line number Diff line number Diff line change
Expand Up @@ -38,7 +38,7 @@ class AppDelegate: UIResponder, UIApplicationDelegate {
MobileCore.lifecycleStart(additionalContextData: nil)
}
})

// If testing background, edit test app scheme -> options -> background fetch -> Check "launch app due to background fetch event"
BGTaskScheduler.shared.register(forTaskWithIdentifier: "testBackground", using: nil) { task in
// Check if we can retrieve from file from background
Expand All @@ -48,11 +48,11 @@ class AppDelegate: UIResponder, UIApplicationDelegate {
}
return true
}

func backgroundTask() {
// Provide the task you want to test in the background here
}

func scheduleAppRefresh() {
let request = BGAppRefreshTaskRequest(identifier: "testBackground")

Expand Down
2 changes: 1 addition & 1 deletion TestApps/TestApp_Swift/SceneDelegate.swift
Original file line number Diff line number Diff line change
Expand Up @@ -67,7 +67,7 @@ class SceneDelegate: UIResponder, UIWindowSceneDelegate {
// e -l objc -- (void)[[BGTaskScheduler sharedScheduler] _simulateLaunchForTaskWithIdentifier:@"testBackground"]
(UIApplication.shared.delegate as! AppDelegate).scheduleAppRefresh()
}



}
Expand Down