From dcbe9a6287a347cc676630dd02b65c3976ef1501 Mon Sep 17 00:00:00 2001 From: Nan Date: Wed, 8 May 2024 23:57:29 -0700 Subject: [PATCH 1/9] [nits] string representation of requests --- .../OneSignalUser/Source/Requests/OSRequestAddAliases.swift | 4 ++-- .../Source/Requests/OSRequestCreateSubscription.swift | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/iOS_SDK/OneSignalSDK/OneSignalUser/Source/Requests/OSRequestAddAliases.swift b/iOS_SDK/OneSignalSDK/OneSignalUser/Source/Requests/OSRequestAddAliases.swift index 3af53122e..ace4ce0bc 100644 --- a/iOS_SDK/OneSignalSDK/OneSignalUser/Source/Requests/OSRequestAddAliases.swift +++ b/iOS_SDK/OneSignalSDK/OneSignalUser/Source/Requests/OSRequestAddAliases.swift @@ -54,7 +54,7 @@ class OSRequestAddAliases: OneSignalRequest, OSUserRequest { init(aliases: [String: String], identityModel: OSIdentityModel) { self.identityModel = identityModel self.aliases = aliases - self.stringDescription = "OSRequestAddAliases with aliases: \(aliases)" + self.stringDescription = "" super.init() self.parameters = ["identity": aliases] self.method = PATCH @@ -82,7 +82,7 @@ class OSRequestAddAliases: OneSignalRequest, OSUserRequest { } self.identityModel = identityModel self.aliases = aliases - self.stringDescription = "OSRequestAddAliases with parameters: \(parameters)" + self.stringDescription = "" super.init() self.parameters = parameters self.method = HTTPMethod(rawValue: rawMethod) diff --git a/iOS_SDK/OneSignalSDK/OneSignalUser/Source/Requests/OSRequestCreateSubscription.swift b/iOS_SDK/OneSignalSDK/OneSignalUser/Source/Requests/OSRequestCreateSubscription.swift index f75adcc31..49986ae36 100644 --- a/iOS_SDK/OneSignalSDK/OneSignalUser/Source/Requests/OSRequestCreateSubscription.swift +++ b/iOS_SDK/OneSignalSDK/OneSignalUser/Source/Requests/OSRequestCreateSubscription.swift @@ -58,7 +58,7 @@ class OSRequestCreateSubscription: OneSignalRequest, OSUserRequest { init(subscriptionModel: OSSubscriptionModel, identityModel: OSIdentityModel) { self.subscriptionModel = subscriptionModel self.identityModel = identityModel - self.stringDescription = "OSRequestCreateSubscription with subscriptionModel: \(subscriptionModel.address ?? "nil")" + self.stringDescription = "" super.init() self.parameters = ["subscription": subscriptionModel.jsonRepresentation()] self.method = POST @@ -86,7 +86,7 @@ class OSRequestCreateSubscription: OneSignalRequest, OSUserRequest { } self.subscriptionModel = subscriptionModel self.identityModel = identityModel - self.stringDescription = "OSRequestCreateSubscription with subscriptionModel: \(subscriptionModel.address ?? "nil")" + self.stringDescription = "" super.init() self.parameters = parameters self.method = HTTPMethod(rawValue: rawMethod) From 42ff86b4106c4f9bcd90ae7d34b01304ee9785d5 Mon Sep 17 00:00:00 2001 From: Nan Date: Wed, 8 May 2024 23:56:19 -0700 Subject: [PATCH 2/9] [tests] client introduce delay to requests * Some requests executed too quickly and need small delay to mimic real server calls * This was motivated by flaky behavior where Identify User will return very quickly and the user in the SDK should have changed by then, but did not. --- .../OneSignalSDK/OneSignalCoreMocks/MockOneSignalClient.swift | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/iOS_SDK/OneSignalSDK/OneSignalCoreMocks/MockOneSignalClient.swift b/iOS_SDK/OneSignalSDK/OneSignalCoreMocks/MockOneSignalClient.swift index 0f8c12365..6536f40a1 100644 --- a/iOS_SDK/OneSignalSDK/OneSignalCoreMocks/MockOneSignalClient.swift +++ b/iOS_SDK/OneSignalSDK/OneSignalCoreMocks/MockOneSignalClient.swift @@ -95,7 +95,7 @@ public class MockOneSignalClient: NSObject, IOneSignalClient { if executeInstantaneously { finishExecutingRequest(request, onSuccess: successBlock, onFailure: failureBlock) } else { - executionQueue.async { + executionQueue.asyncAfter(deadline: .now() + .milliseconds(20)) { self.finishExecutingRequest(request, onSuccess: successBlock, onFailure: failureBlock) } } From 19f79cd5f88822aa7db0c71c1e6ee5e2c6d7e2dd Mon Sep 17 00:00:00 2001 From: Nan Date: Wed, 8 May 2024 23:56:56 -0700 Subject: [PATCH 3/9] [tests] add assert helper to Client --- .../OneSignalCoreMocks/MockOneSignalClient.swift | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/iOS_SDK/OneSignalSDK/OneSignalCoreMocks/MockOneSignalClient.swift b/iOS_SDK/OneSignalSDK/OneSignalCoreMocks/MockOneSignalClient.swift index 6536f40a1..9fd5820fb 100644 --- a/iOS_SDK/OneSignalSDK/OneSignalCoreMocks/MockOneSignalClient.swift +++ b/iOS_SDK/OneSignalSDK/OneSignalCoreMocks/MockOneSignalClient.swift @@ -177,4 +177,10 @@ extension MockOneSignalClient { return found } + + public func hasExecutedRequestOfType(_ type: AnyClass) -> Bool { + executedRequests.contains { request in + request.isKind(of: type) + } + } } From acb59a24d8533f3e48e6f2ea2f6ce487dd455c3b Mon Sep 17 00:00:00 2001 From: Nan Date: Wed, 8 May 2024 23:53:10 -0700 Subject: [PATCH 4/9] [tests] helper to check dicts contain sub-dicts * These changes were motivate by need to check if [subscription: [token: email] is within a fuller subscription payload --- .../Extensions/NSDictionary+UnitTests.swift | 57 +++++++++++++++++-- 1 file changed, 53 insertions(+), 4 deletions(-) diff --git a/iOS_SDK/OneSignalSDK/OneSignalCoreMocks/Extensions/NSDictionary+UnitTests.swift b/iOS_SDK/OneSignalSDK/OneSignalCoreMocks/Extensions/NSDictionary+UnitTests.swift index 44a185e88..9e30d1dbd 100644 --- a/iOS_SDK/OneSignalSDK/OneSignalCoreMocks/Extensions/NSDictionary+UnitTests.swift +++ b/iOS_SDK/OneSignalSDK/OneSignalCoreMocks/Extensions/NSDictionary+UnitTests.swift @@ -1,13 +1,62 @@ extension NSDictionary { - func contains(key: String, value: Any) -> Bool { + /* + This method goes one level deep into dictionaries + */ + private func contains(key: String, value: Any) -> Bool { guard let dictVal = self[key] else { return false } - - return equals(dictVal, value) + if let value = value as? [String: Any], + let dictVal = dictVal as? NSDictionary { + return dictVal.contains(value) + } else { + return equals(dictVal, value) + } } - func contains(_ dict: [String: Any]) -> Bool { + /* + let parent = [ + "apple": [ + "type": "fruit", + "count": 5, + "fresh": true + ], + "orange": [ + "type": "color" + ], + "cactus": "error" + ] + + // 1. Example 1 - + let child1 = [ + "apple": [ + "type": "fruit", + "fresh": true + ] + ] + parent.contains(child1) = true + + // 2. Example 2 - + let child2 = [ + "apple": [ + "type": "fruit" + ], + "orange": [ + "type": "fruit" + ] + ] + parent.contains(child2) = false + + // 3. Example 3 - + let child3 = [ + "orange": [ + "type": "color" + ], + "cactus": "error" + ] + parent.contains(child3) = true + */ + public func contains(_ dict: [String: Any]) -> Bool { for (key, value) in dict { if !contains(key: key, value: value) { return false From edb5f61f950b5da376dd670bebcb639a9879029e Mon Sep 17 00:00:00 2001 From: Nan Date: Wed, 8 May 2024 23:54:01 -0700 Subject: [PATCH 5/9] [tests] add more mocked server responses --- .../OneSignalUserMocks/MockUserRequests.swift | 61 +++++++++++++++++++ 1 file changed, 61 insertions(+) diff --git a/iOS_SDK/OneSignalSDK/OneSignalUserMocks/MockUserRequests.swift b/iOS_SDK/OneSignalSDK/OneSignalUserMocks/MockUserRequests.swift index 474fe9a51..6c39b4ffc 100644 --- a/iOS_SDK/OneSignalSDK/OneSignalUserMocks/MockUserRequests.swift +++ b/iOS_SDK/OneSignalSDK/OneSignalUserMocks/MockUserRequests.swift @@ -125,6 +125,31 @@ extension MockUserRequests { ) } + /** + Returns many user data to mimic pulling remote data. Used to test for hydration. + */ + public static func setDefaultFetchUserResponseForHydration(with client: MockOneSignalClient, externalId: String) { + let osid = getOneSignalId(for: externalId) + + var fetchResponse: [String: Any] = [ + "identity": ["onesignal_id": osid, "external_id": externalId, "remote_alias": "remote_id"], + "properties": [ + "tags": ["remote_tag": "remote_value"], + "language": "remote_language" + ], + "subscriptions": [ + ["type": "Email", + "id": "remote_email_id", + "token": "remote_email@example.com" + ] + ] + ] + client.setMockResponseForRequest( + request: "", + response: fetchResponse + ) + } + public static func setAddTagsResponse(with client: MockOneSignalClient, tags: [String: String]) { let tagsResponse = MockUserRequests.testPropertiesPayload(properties: ["tags": tags]) @@ -133,4 +158,40 @@ extension MockUserRequests { response: tagsResponse ) } + + public static func setSetLanguageResponse(with client: MockOneSignalClient, language: String) { + client.setMockResponseForRequest( + request: "", + response: [:] // The SDK does not use the response in any way + ) + } + + public static func setAddAliasesResponse(with client: MockOneSignalClient, aliases: [String: String]) { + client.setMockResponseForRequest( + request: "", + response: [:] // The SDK does not use the response in any way + ) + } + + /** The real response will either contain a subscription payload or be empty (if already exists on user) */ + public static func setAddEmailResponse(with client: MockOneSignalClient, email: String) { + let response = [ + "subscription": [ + "id": "\(email)_id", + "type": "Email", + "token": email + ] + ] + client.setMockResponseForRequest( + request: "", + response: response + ) + } + + public static func setTransferSubscriptionResponse(with client: MockOneSignalClient, externalId: String) { + client.setMockResponseForRequest( + request: "", + response: [:] // The SDK does not use the response + ) + } } From 7f98f902a6fd80b820830f837402e67fe1e8c5ee Mon Sep 17 00:00:00 2001 From: Nan Date: Wed, 8 May 2024 23:46:03 -0700 Subject: [PATCH 6/9] [tests] Add more user switching tests --- .../OneSignal.xcodeproj/project.pbxproj | 4 + .../OneSignalUserTests/SwitchUserTests.swift | 412 ++++++++++++++++++ 2 files changed, 416 insertions(+) create mode 100644 iOS_SDK/OneSignalSDK/OneSignalUserTests/SwitchUserTests.swift diff --git a/iOS_SDK/OneSignalSDK/OneSignal.xcodeproj/project.pbxproj b/iOS_SDK/OneSignalSDK/OneSignal.xcodeproj/project.pbxproj index 23e19a7c4..c594dcf4a 100644 --- a/iOS_SDK/OneSignalSDK/OneSignal.xcodeproj/project.pbxproj +++ b/iOS_SDK/OneSignalSDK/OneSignal.xcodeproj/project.pbxproj @@ -82,6 +82,7 @@ 3C47A975292642B100312125 /* OneSignalConfigManager.m in Sources */ = {isa = PBXBuildFile; fileRef = 3C47A973292642B100312125 /* OneSignalConfigManager.m */; }; 3C4F9E4428A4466C009F453A /* OSOperationRepo.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3C4F9E4328A4466C009F453A /* OSOperationRepo.swift */; }; 3C5117172B15C31E00563465 /* OSUserState.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3C5117162B15C31E00563465 /* OSUserState.swift */; }; + 3C67F77A2BEB2B710085A0F0 /* SwitchUserTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3C67F7792BEB2B710085A0F0 /* SwitchUserTests.swift */; }; 3C789DBD293C2206004CF83D /* OSFocusInfluenceParam.m in Sources */ = {isa = PBXBuildFile; fileRef = 7A600B432453790700514A53 /* OSFocusInfluenceParam.m */; }; 3C789DBE293D8EAD004CF83D /* OSFocusInfluenceParam.h in Headers */ = {isa = PBXBuildFile; fileRef = 7A600B41245378ED00514A53 /* OSFocusInfluenceParam.h */; settings = {ATTRIBUTES = (Public, ); }; }; 3C7A39C12B7BED900082665E /* OneSignalCoreMocks.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 3CC0639A2B6D7A8C002BB07F /* OneSignalCoreMocks.framework */; }; @@ -1124,6 +1125,7 @@ 3C47A973292642B100312125 /* OneSignalConfigManager.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = OneSignalConfigManager.m; sourceTree = ""; }; 3C4F9E4328A4466C009F453A /* OSOperationRepo.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = OSOperationRepo.swift; sourceTree = ""; }; 3C5117162B15C31E00563465 /* OSUserState.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = OSUserState.swift; sourceTree = ""; }; + 3C67F7792BEB2B710085A0F0 /* SwitchUserTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SwitchUserTests.swift; sourceTree = ""; }; 3C7A39D42B7C18EE0082665E /* XCTest.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = XCTest.framework; path = Platforms/iPhoneOS.platform/Developer/Library/Frameworks/XCTest.framework; sourceTree = DEVELOPER_DIR; }; 3C87066F2BDE0957000D8CD2 /* MockUserRequests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MockUserRequests.swift; sourceTree = ""; }; 3C8706712BDEE076000D8CD2 /* MockUserDefines.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MockUserDefines.swift; sourceTree = ""; }; @@ -1963,6 +1965,7 @@ isa = PBXGroup; children = ( 3CC063ED2B6D7FE8002BB07F /* OneSignalUserTests.swift */, + 3C67F7792BEB2B710085A0F0 /* SwitchUserTests.swift */, ); path = OneSignalUserTests; sourceTree = ""; @@ -3743,6 +3746,7 @@ isa = PBXSourcesBuildPhase; buildActionMask = 2147483647; files = ( + 3C67F77A2BEB2B710085A0F0 /* SwitchUserTests.swift in Sources */, 3CC063EE2B6D7FE8002BB07F /* OneSignalUserTests.swift in Sources */, ); runOnlyForDeploymentPostprocessing = 0; diff --git a/iOS_SDK/OneSignalSDK/OneSignalUserTests/SwitchUserTests.swift b/iOS_SDK/OneSignalSDK/OneSignalUserTests/SwitchUserTests.swift new file mode 100644 index 000000000..03e645c2c --- /dev/null +++ b/iOS_SDK/OneSignalSDK/OneSignalUserTests/SwitchUserTests.swift @@ -0,0 +1,412 @@ +import XCTest +import OneSignalCore +import OneSignalCoreMocks +import OneSignalUserMocks +@testable import OneSignalUser + +final class SwitchUserTests: XCTestCase { + + override func setUpWithError() throws { + // TODO: Something like the existing [UnitTestCommonMethods beforeEachTest:self]; + // App ID is set because User Manager has guards against nil App ID + OneSignalConfigManager.setAppId("test-app-id") + // Temp. logging to help debug during testing + OneSignalLog.setLogLevel(.LL_VERBOSE) + } + + override func tearDownWithError() throws { + // TODO: Need to clear all data between tests for client, user manager, models, etc. + OneSignalCoreMocks.clearUserDefaults() + OneSignalUserMocks.reset() + } + + /* + This test simulates this these calls: + + // Start with Anonymous User + OneSignal.User.addTag(key: "tag_anon", value: "value_anon") + OneSignal.User.setLanguage("lang_anon") + OneSignal.User.addAlias(label: "alias_anon", id: "id_anon") + OneSignal.User.addEmail("email_anon@example.com") + + OneSignal.login() + OneSignal.User.addTag(key: "tag_a", value: "value_a") + OneSignal.User.setLanguage("lang_a") + OneSignal.User.addAlias(label: "alias_a", id: "id_a") + OneSignal.User.addEmail("email_a@example.com") + */ + func testAnonUser_thenIdentifyUserWithConflict_sendsCorrectUpdatesAndFetchesUser() throws { + /* Setup */ + + let client = MockOneSignalClient() + OneSignalCoreImpl.setSharedClient(client) + + // 1. Set up mock responses for the first anonymous user + let tagsUserAnon = ["tag_anon": "value_anon"] + MockUserRequests.setDefaultCreateAnonUserResponses(with: client) + MockUserRequests.setAddTagsResponse(with: client, tags: tagsUserAnon) + MockUserRequests.setSetLanguageResponse(with: client, language: "lang_anon") + MockUserRequests.setAddAliasesResponse(with: client, aliases: ["alias_anon": "id_anon"]) + MockUserRequests.setAddEmailResponse(with: client, email: "email_anon@example.com") + + // 2. Set up mock responses for User A with 409 conflict response + let tagsUserA = ["tag_a": "value_a"] + MockUserRequests.setDefaultIdentifyUserResponses(with: client, externalId: userA_EUID, conflicted: true) + MockUserRequests.setAddTagsResponse(with: client, tags: tagsUserA) + MockUserRequests.setSetLanguageResponse(with: client, language: "lang_a") + MockUserRequests.setAddAliasesResponse(with: client, aliases: ["alias_a": "id_a"]) + MockUserRequests.setAddEmailResponse(with: client, email: "email_a@example.com") + MockUserRequests.setTransferSubscriptionResponse(with: client, externalId: userA_EUID) + // Returns mocked user data to test hydration + MockUserRequests.setDefaultFetchUserResponseForHydration(with: client, externalId: userA_EUID) + + /* When */ + + // 1. Anonymous user + OneSignalUserManagerImpl.sharedInstance.addTag(key: "tag_anon", value: "value_anon") + OneSignalUserManagerImpl.sharedInstance.setLanguage("lang_anon") + OneSignalUserManagerImpl.sharedInstance.addAlias(label: "alias_anon", id: "id_anon") + OneSignalUserManagerImpl.sharedInstance.addEmail("email_anon@example.com") + + // 2. Login to user A (will result in 409 conflict) and add data + OneSignalUserManagerImpl.sharedInstance.login(externalId: userA_EUID, token: nil) + OneSignalUserManagerImpl.sharedInstance.addTag(key: "tag_a", value: "value_a") + OneSignalUserManagerImpl.sharedInstance.setLanguage("lang_a") + OneSignalUserManagerImpl.sharedInstance.addAlias(label: "alias_a", id: "id_a") + OneSignalUserManagerImpl.sharedInstance.addEmail("email_a@example.com") + + // 3. Run background threads + OneSignalCoreMocks.waitForBackgroundThreads(seconds: 0.5) + + /* Then */ + + // 0. Assert that every request SDK makes has a response set, and is handled + XCTAssertTrue(client.allRequestsHandled) + + // 1. Asserts for first Anonymous User + XCTAssertTrue(client.onlyOneRequest( // Tag + contains: "apps/test-app-id/users/by/onesignal_id/\(anonUserOSID)", + contains: ["properties": ["tags": tagsUserAnon]]) + ) + XCTAssertTrue(client.onlyOneRequest( // Language + contains: "apps/test-app-id/users/by/onesignal_id/\(anonUserOSID)", + contains: ["properties": ["language": "lang_anon"]]) + ) + XCTAssertTrue(client.onlyOneRequest( // Alias + contains: "apps/test-app-id/users/by/onesignal_id/\(anonUserOSID)/identity", + contains: ["identity": ["alias_anon": "id_anon"]]) + ) + XCTAssertTrue(client.onlyOneRequest( // Email + contains: "apps/test-app-id/users/by/onesignal_id/\(anonUserOSID)/subscriptions", + contains: ["subscription": ["token": "email_anon@example.com"]]) + ) + + // 2. Asserts for User A - expected requests are sent + XCTAssertTrue(client.onlyOneRequest( // Tag + contains: "apps/test-app-id/users/by/onesignal_id/\(userA_OSID)", + contains: ["properties": ["tags": tagsUserA]]) + ) + XCTAssertTrue(client.onlyOneRequest( // Language + contains: "apps/test-app-id/users/by/onesignal_id/\(userA_OSID)", + contains: ["properties": ["language": "lang_a"]]) + ) + XCTAssertTrue(client.onlyOneRequest( // Alias + contains: "apps/test-app-id/users/by/onesignal_id/\(userA_OSID)/identity", + contains: ["identity": ["alias_a": "id_a"]]) + ) + XCTAssertTrue(client.onlyOneRequest( // Email + contains: "apps/test-app-id/users/by/onesignal_id/\(userA_OSID)/subscriptions", + contains: ["subscription": ["token": "email_a@example.com"]]) + ) + XCTAssertTrue(client.hasExecutedRequestOfType(OSRequestFetchUser.self)) + XCTAssertTrue(client.hasExecutedRequestOfType(OSRequestTransferSubscription.self)) + + // 3. Asserts for User A - local data is updated via hydration + XCTAssertEqual("remote_language", OneSignalUserManagerImpl.sharedInstance.user.propertiesModel.language) + XCTAssertNotNil(OneSignalUserManagerImpl.sharedInstance.getTags()["remote_tag"]) + XCTAssertNotNil(OneSignalUserManagerImpl.sharedInstance.user.identityModel.aliases["remote_alias"]) + XCTAssertNotNil(OneSignalUserManagerImpl.sharedInstance.subscriptionModelStore.getModel(key: "remote_email@example.com")) + } + + /* + This test simulates these calls: + + // Start with Anonymous User + OneSignal.User.addTag(key: "tag_anon", value: "value_anon") + OneSignal.User.setLanguage("lang_anon") + OneSignal.User.addAlias(label: "alias_anon", id: "id_anon") + OneSignal.User.addEmail("email_anon@example.com") + + OneSignal.login() + OneSignal.User.addTag(key: "tag_a", value: "value_a") + OneSignal.User.setLanguage("lang_a") + OneSignal.User.addAlias(label: "alias_a", id: "id_a") + OneSignal.User.addEmail("email_a@example.com") + + OneSignal.logout() + OneSignal.User.addTag(key: "tag_b", value: "value_b") + OneSignal.User.setLanguage("lang_b") + OneSignal.User.addAlias(label: "alias_b", id: "id_b") + OneSignal.User.addEmail("email_b@example.com") + */ + func testAnonUser_thenIdentifyUserWithConflict_thenLogout_sendsCorrectUpdatesWithNoFetch() throws { + /* Setup */ + + let client = MockOneSignalClient() + OneSignalCoreImpl.setSharedClient(client) + + // 1. Set up mock responses for the first anonymous user + let tagsUserAnon = ["tag_anon": "value_anon"] + MockUserRequests.setDefaultCreateAnonUserResponses(with: client) + MockUserRequests.setAddTagsResponse(with: client, tags: tagsUserAnon) + MockUserRequests.setSetLanguageResponse(with: client, language: "lang_anon") + MockUserRequests.setAddAliasesResponse(with: client, aliases: ["alias_anon": "id_anon"]) + MockUserRequests.setAddEmailResponse(with: client, email: "email_anon@example.com") + + // 2. Set up mock responses for User A with 409 conflict response + let tagsUserA = ["tag_a": "value_a"] + MockUserRequests.setDefaultIdentifyUserResponses(with: client, externalId: userA_EUID, conflicted: true) + MockUserRequests.setAddTagsResponse(with: client, tags: tagsUserA) + MockUserRequests.setSetLanguageResponse(with: client, language: "lang_a") + MockUserRequests.setAddAliasesResponse(with: client, aliases: ["alias_a": "id_a"]) + MockUserRequests.setAddEmailResponse(with: client, email: "email_a@example.com") + + // 3. Set up mock responses for second Anonymous User + let tagsUserB = ["tag_b": "value_b"] + MockUserRequests.setAddTagsResponse(with: client, tags: tagsUserB) + MockUserRequests.setSetLanguageResponse(with: client, language: "lang_b") + MockUserRequests.setAddAliasesResponse(with: client, aliases: ["alias_b": "id_b"]) + MockUserRequests.setAddEmailResponse(with: client, email: "email_b@example.com") + + /* When */ + + // 1. Anonymous user starts + OneSignalUserManagerImpl.sharedInstance.addTag(key: "tag_anon", value: "value_anon") + OneSignalUserManagerImpl.sharedInstance.setLanguage("lang_anon") + OneSignalUserManagerImpl.sharedInstance.addAlias(label: "alias_anon", id: "id_anon") + OneSignalUserManagerImpl.sharedInstance.addEmail("email_anon@example.com") + + // 2. Login to user A (will result in 409 conflict) and add data + OneSignalUserManagerImpl.sharedInstance.login(externalId: userA_EUID, token: nil) + OneSignalUserManagerImpl.sharedInstance.addTag(key: "tag_a", value: "value_a") + OneSignalUserManagerImpl.sharedInstance.setLanguage("lang_a") + OneSignalUserManagerImpl.sharedInstance.addAlias(label: "alias_a", id: "id_a") + OneSignalUserManagerImpl.sharedInstance.addEmail("email_a@example.com") + + // 3. Logout and add data + OneSignalUserManagerImpl.sharedInstance.logout() + OneSignalUserManagerImpl.sharedInstance.addTag(key: "tag_b", value: "value_b") + OneSignalUserManagerImpl.sharedInstance.setLanguage("lang_b") + OneSignalUserManagerImpl.sharedInstance.addAlias(label: "alias_b", id: "id_b") + OneSignalUserManagerImpl.sharedInstance.addEmail("email_b@example.com") + + // 4. Run background threads + OneSignalCoreMocks.waitForBackgroundThreads(seconds: 0.5) + + /* Then */ + + // 0. Assert that every request SDK makes has a response set, and is handled + XCTAssertTrue(client.allRequestsHandled) + + // 1. Asserts for first Anonymous User + XCTAssertTrue(client.onlyOneRequest( // Tag + contains: "apps/test-app-id/users/by/onesignal_id/\(anonUserOSID)", + contains: ["properties": ["tags": tagsUserAnon]]) + ) + XCTAssertTrue(client.onlyOneRequest( // Language + contains: "apps/test-app-id/users/by/onesignal_id/\(anonUserOSID)", + contains: ["properties": ["language": "lang_anon"]]) + ) + XCTAssertTrue(client.onlyOneRequest( // Alias + contains: "apps/test-app-id/users/by/onesignal_id/\(anonUserOSID)/identity", + contains: ["identity": ["alias_anon": "id_anon"]]) + ) + XCTAssertTrue(client.onlyOneRequest( // Email + contains: "apps/test-app-id/users/by/onesignal_id/\(anonUserOSID)/subscriptions", + contains: ["subscription": ["token": "email_anon@example.com"]]) + ) + + // 2. Asserts for User A + XCTAssertTrue(client.onlyOneRequest( // Tag + contains: "apps/test-app-id/users/by/external_id/\(userA_EUID)", + contains: ["properties": ["tags": tagsUserA]]) + ) + XCTAssertTrue(client.onlyOneRequest( // Language + contains: "apps/test-app-id/users/by/external_id/\(userA_EUID)", + contains: ["properties": ["language": "lang_a"]]) + ) + XCTAssertTrue(client.onlyOneRequest( // Alias + contains: "apps/test-app-id/users/by/external_id/\(userA_EUID)/identity", + contains: ["identity": ["alias_a": "id_a"]]) + ) + XCTAssertTrue(client.onlyOneRequest( // Email + contains: "apps/test-app-id/users/by/external_id/\(userA_EUID)/subscriptions", + contains: ["subscription": ["token": "email_a@example.com"]]) + ) + + // 3. Asserts for the second Anonymous User + XCTAssertTrue(client.onlyOneRequest( // Tag + contains: "apps/test-app-id/users/by/onesignal_id/\(anonUserOSID)", + contains: ["properties": ["tags": tagsUserB]]) + ) + XCTAssertTrue(client.onlyOneRequest( // Language + contains: "apps/test-app-id/users/by/onesignal_id/\(anonUserOSID)", + contains: ["properties": ["language": "lang_b"]]) + ) + XCTAssertTrue(client.onlyOneRequest( // Alias + contains: "apps/test-app-id/users/by/onesignal_id/\(anonUserOSID)/identity", + contains: ["identity": ["alias_b": "id_b"]]) + ) + XCTAssertTrue(client.onlyOneRequest( // Email + contains: "apps/test-app-id/users/by/onesignal_id/\(anonUserOSID)/subscriptions", + contains: ["subscription": ["token": "email_b@example.com"]]) + ) + + // 4. In this flow with anon users, no Fetch User calls should have happened + XCTAssertFalse(client.hasExecutedRequestOfType(OSRequestFetchUser.self)) + } + + /* + This test simulates this these calls: + + // Start with Anonymous User + OneSignal.User.addTag(key: "tag_anon", value: "value_anon") + OneSignal.User.setLanguage("lang_anon") + OneSignal.User.addAlias(label: "alias_anon", id: "id_anon") + OneSignal.User.addEmail("email_anon@example.com") + + OneSignal.login() + OneSignal.User.addTag(key: "tag_a", value: "value_a") + OneSignal.User.setLanguage("lang_a") + OneSignal.User.addAlias(label: "alias_a", id: "id_a") + OneSignal.User.addEmail("email_a@example.com") + + OneSignal.login(userB_EUID) + OneSignal.User.addTag(key: "tag_b", value: "value_b") + OneSignal.User.setLanguage("lang_b") + OneSignal.User.addAlias(label: "alias_b", id: "id_b") + OneSignal.User.addEmail("email_b@example.com") + */ + func testAnonUser_thenIdentifyUserWithConflict_thenLogin_sendsCorrectUpdatesAndFetchesUser() throws { + /* Setup */ + + let client = MockOneSignalClient() + OneSignalCoreImpl.setSharedClient(client) + + // 1. Set up mock responses for the first anonymous user + let tagsUserAnon = ["tag_anon": "value_anon"] + MockUserRequests.setDefaultCreateAnonUserResponses(with: client) + MockUserRequests.setAddTagsResponse(with: client, tags: tagsUserAnon) + MockUserRequests.setSetLanguageResponse(with: client, language: "lang_anon") + MockUserRequests.setAddAliasesResponse(with: client, aliases: ["alias_anon": "id_anon"]) + MockUserRequests.setAddEmailResponse(with: client, email: "email_anon@example.com") + + // 2. Set up mock responses for User A with 409 conflict response + let tagsUserA = ["tag_a": "value_a"] + MockUserRequests.setDefaultIdentifyUserResponses(with: client, externalId: userA_EUID, conflicted: true) + MockUserRequests.setAddTagsResponse(with: client, tags: tagsUserA) + MockUserRequests.setSetLanguageResponse(with: client, language: "lang_a") + MockUserRequests.setAddAliasesResponse(with: client, aliases: ["alias_a": "id_a"]) + MockUserRequests.setAddEmailResponse(with: client, email: "email_a@example.com") + + // 3. Set up mock responses for for User B + let tagsUserB = ["tag_b": "value_b"] + MockUserRequests.setDefaultCreateUserResponses(with: client, externalId: userB_EUID) + MockUserRequests.setAddTagsResponse(with: client, tags: tagsUserB) + MockUserRequests.setSetLanguageResponse(with: client, language: "lang_b") + MockUserRequests.setAddAliasesResponse(with: client, aliases: ["alias_b": "id_b"]) + MockUserRequests.setAddEmailResponse(with: client, email: "email_b@example.com") + // Returns mocked user data to test hydration + MockUserRequests.setDefaultFetchUserResponseForHydration(with: client, externalId: userB_EUID) + + /* When */ + + // 1. Anonymous user + OneSignalUserManagerImpl.sharedInstance.addTag(key: "tag_anon", value: "value_anon") + OneSignalUserManagerImpl.sharedInstance.setLanguage("lang_anon") + OneSignalUserManagerImpl.sharedInstance.addAlias(label: "alias_anon", id: "id_anon") + OneSignalUserManagerImpl.sharedInstance.addEmail("email_anon@example.com") + + // 1. Login to user A (will result in 409 conflict) and add data + OneSignalUserManagerImpl.sharedInstance.login(externalId: userA_EUID, token: nil) + OneSignalUserManagerImpl.sharedInstance.addTag(key: "tag_a", value: "value_a") + OneSignalUserManagerImpl.sharedInstance.setLanguage("lang_a") + OneSignalUserManagerImpl.sharedInstance.addAlias(label: "alias_a", id: "id_a") + OneSignalUserManagerImpl.sharedInstance.addEmail("email_a@example.com") + + // 2. Login and add data + OneSignalUserManagerImpl.sharedInstance.login(externalId: userB_EUID, token: nil) + OneSignalUserManagerImpl.sharedInstance.addTag(key: "tag_b", value: "value_b") + OneSignalUserManagerImpl.sharedInstance.setLanguage("lang_b") + OneSignalUserManagerImpl.sharedInstance.addAlias(label: "alias_b", id: "id_b") + OneSignalUserManagerImpl.sharedInstance.addEmail("email_b@example.com") + + // 3. Run background threads + OneSignalCoreMocks.waitForBackgroundThreads(seconds: 0.5) + + /* Then */ + + // 0. Assert that every request SDK makes has a response set, and is handled + XCTAssertTrue(client.allRequestsHandled) + + // 1. Asserts for first Anonymous User + XCTAssertTrue(client.onlyOneRequest( // Tag + contains: "apps/test-app-id/users/by/onesignal_id/\(anonUserOSID)", + contains: ["properties": ["tags": tagsUserAnon]]) + ) + XCTAssertTrue(client.onlyOneRequest( // Language + contains: "apps/test-app-id/users/by/onesignal_id/\(anonUserOSID)", + contains: ["properties": ["language": "lang_anon"]]) + ) + XCTAssertTrue(client.onlyOneRequest( // Alias + contains: "apps/test-app-id/users/by/onesignal_id/\(anonUserOSID)/identity", + contains: ["identity": ["alias_anon": "id_anon"]]) + ) + XCTAssertTrue(client.onlyOneRequest( // Email + contains: "apps/test-app-id/users/by/onesignal_id/\(anonUserOSID)/subscriptions", + contains: ["subscription": ["token": "email_anon@example.com"]]) + ) + + // 2. Asserts for User A + XCTAssertTrue(client.onlyOneRequest( // Tag + contains: "apps/test-app-id/users/by/external_id/\(userA_EUID)", + contains: ["properties": ["tags": tagsUserA]]) + ) + XCTAssertTrue(client.onlyOneRequest( // Language + contains: "apps/test-app-id/users/by/external_id/\(userA_EUID)", + contains: ["properties": ["language": "lang_a"]]) + ) + XCTAssertTrue(client.onlyOneRequest( // Alias + contains: "apps/test-app-id/users/by/external_id/\(userA_EUID)/identity", + contains: ["identity": ["alias_a": "id_a"]]) + ) + XCTAssertTrue(client.onlyOneRequest( // Email + contains: "apps/test-app-id/users/by/external_id/\(userA_EUID)/subscriptions", + contains: ["subscription": ["token": "email_a@example.com"]]) + ) + + // 3. Asserts for User B - expected requests sent + XCTAssertTrue(client.onlyOneRequest( // Tag + contains: "apps/test-app-id/users/by/onesignal_id/\(userB_OSID)", + contains: ["properties": ["tags": tagsUserB]]) + ) + XCTAssertTrue(client.onlyOneRequest( // Language + contains: "apps/test-app-id/users/by/onesignal_id/\(userB_OSID)", + contains: ["properties": ["language": "lang_b"]]) + ) + XCTAssertTrue(client.onlyOneRequest( // Alias + contains: "apps/test-app-id/users/by/onesignal_id/\(userB_OSID)/identity", + contains: ["identity": ["alias_b": "id_b"]]) + ) + XCTAssertTrue(client.onlyOneRequest( // Email + contains: "apps/test-app-id/users/by/onesignal_id/\(userB_OSID)/subscriptions", + contains: ["subscription": ["token": "email_b@example.com"]]) + ) + + // 4. Asserts for User B - local data is updated via hydration + XCTAssertEqual("remote_language", OneSignalUserManagerImpl.sharedInstance.user.propertiesModel.language) + XCTAssertNotNil(OneSignalUserManagerImpl.sharedInstance.getTags()["remote_tag"]) + XCTAssertNotNil(OneSignalUserManagerImpl.sharedInstance.user.identityModel.aliases["remote_alias"]) + XCTAssertNotNil(OneSignalUserManagerImpl.sharedInstance.subscriptionModelStore.getModel(key: "remote_email@example.com")) + } +} From 86a12c7489b2f57432c55e2ca88a7e4a3db6b24e Mon Sep 17 00:00:00 2001 From: Nan Date: Thu, 9 May 2024 00:09:51 -0700 Subject: [PATCH 7/9] [nits] move existing switch user test to new file * Move user switching tests to new test class * Remove test `testIdentifyUserWithConflict_whenNotCurrentUser_sendsCorrectTags` as its behavior is already being tested in the new tests --- .../OneSignalUserTests.swift | 103 ------------------ .../OneSignalUserTests/SwitchUserTests.swift | 51 +++++++++ 2 files changed, 51 insertions(+), 103 deletions(-) diff --git a/iOS_SDK/OneSignalSDK/OneSignalUserTests/OneSignalUserTests.swift b/iOS_SDK/OneSignalSDK/OneSignalUserTests/OneSignalUserTests.swift index 6f7e6e3cf..e0dc80c9c 100644 --- a/iOS_SDK/OneSignalSDK/OneSignalUserTests/OneSignalUserTests.swift +++ b/iOS_SDK/OneSignalSDK/OneSignalUserTests/OneSignalUserTests.swift @@ -137,107 +137,4 @@ final class OneSignalUserTests: XCTestCase { identityModel.clearData() } } - - func testSwitchUser_sendsCorrectTags() throws { - /* Setup */ - - let client = MockOneSignalClient() - - // 1. Set up mock responses for the anonymous user - MockUserRequests.setDefaultCreateAnonUserResponses(with: client) - - // 2. Set up mock responses for User A - let tagsUserA = ["tag_a": "value_a"] - MockUserRequests.setDefaultIdentifyUserResponses(with: client, externalId: userA_EUID) - MockUserRequests.setAddTagsResponse(with: client, tags: tagsUserA) - - // 3. Set up mock responses for User B - let tagsUserB = ["tag_b": "value_b"] - MockUserRequests.setDefaultCreateUserResponses(with: client, externalId: userB_EUID) - MockUserRequests.setAddTagsResponse(with: client, tags: tagsUserB) - - OneSignalCoreImpl.setSharedClient(client) - - /* When */ - - // 1. Login to user A and add tag - OneSignalUserManagerImpl.sharedInstance.login(externalId: userA_EUID, token: nil) - OneSignalUserManagerImpl.sharedInstance.addTag(key: "tag_a", value: "value_a") - - // 2. Login to user B and add tag - OneSignalUserManagerImpl.sharedInstance.login(externalId: userB_EUID, token: nil) - OneSignalUserManagerImpl.sharedInstance.addTag(key: "tag_b", value: "value_b") - - // 3. Run background threads - OneSignalCoreMocks.waitForBackgroundThreads(seconds: 0.5) - - /* Then */ - - // Assert that every request SDK makes has a response set, and is handled - XCTAssertTrue(client.allRequestsHandled) - - // Assert there is only one request containing these tags and they are sent to the Anon User - // This is because the Identify User request succeeded, so the user remains the same - XCTAssertTrue(client.onlyOneRequest( - contains: "apps/test-app-id/users/by/onesignal_id/\(anonUserOSID)", - contains: ["properties": ["tags": tagsUserA]]) - ) - // Assert there is only one request containing these tags and they are sent to userB - XCTAssertTrue(client.onlyOneRequest( - contains: "apps/test-app-id/users/by/onesignal_id/\(userB_OSID)", - contains: ["properties": ["tags": tagsUserB]]) - ) - } - - /** - Motivation: We had a bug where we did not hydrate the middle user's OSID, so any pending updates got dropped. - */ - func testIdentifyUserWithConflict_whenNotCurrentUser_sendsCorrectTags() throws { - /* Setup */ - - let client = MockOneSignalClient() - OneSignalCoreImpl.setSharedClient(client) - - // 1. Set up mock responses for the anonymous user - MockUserRequests.setDefaultCreateAnonUserResponses(with: client) - - // 2. Set up mock responses for User A with 409 conflict response - let tagsUserA = ["tag_a": "value_a"] - MockUserRequests.setDefaultIdentifyUserResponses(with: client, externalId: userA_EUID, conflicted: true) - MockUserRequests.setAddTagsResponse(with: client, tags: tagsUserA) - - // 3. Set up mock responses for User B - let tagsUserB = ["tag_b": "value_b"] - MockUserRequests.setDefaultCreateUserResponses(with: client, externalId: userB_EUID) - MockUserRequests.setAddTagsResponse(with: client, tags: tagsUserB) - - /* When */ - - // 1. Login to user A (will result in 409 conflict) and add tag - OneSignalUserManagerImpl.sharedInstance.login(externalId: userA_EUID, token: nil) - OneSignalUserManagerImpl.sharedInstance.addTag(key: "tag_a", value: "value_a") - - // 2. Login to user B and add tag - OneSignalUserManagerImpl.sharedInstance.login(externalId: userB_EUID, token: nil) - OneSignalUserManagerImpl.sharedInstance.addTag(key: "tag_b", value: "value_b") - - // 3. Run background threads - OneSignalCoreMocks.waitForBackgroundThreads(seconds: 0.5) - - /* Then */ - - // Assert that every request SDK makes has a response set, and is handled - XCTAssertTrue(client.allRequestsHandled) - - // Assert only one request containing these tags and they are sent to userA by external_id - XCTAssertTrue(client.onlyOneRequest( - contains: "apps/test-app-id/users/by/external_id/\(userA_EUID)", - contains: ["properties": ["tags": tagsUserA]]) - ) - // Assert there is only one request containing these tags and they are sent to userB - XCTAssertTrue(client.onlyOneRequest( - contains: "apps/test-app-id/users/by/onesignal_id/\(userB_OSID)", - contains: ["properties": ["tags": tagsUserB]]) - ) - } } diff --git a/iOS_SDK/OneSignalSDK/OneSignalUserTests/SwitchUserTests.swift b/iOS_SDK/OneSignalSDK/OneSignalUserTests/SwitchUserTests.swift index 03e645c2c..2242062ae 100644 --- a/iOS_SDK/OneSignalSDK/OneSignalUserTests/SwitchUserTests.swift +++ b/iOS_SDK/OneSignalSDK/OneSignalUserTests/SwitchUserTests.swift @@ -20,6 +20,57 @@ final class SwitchUserTests: XCTestCase { OneSignalUserMocks.reset() } + func testIdentifyUserSuccessfully_thenLogin_sendsCorrectTags() throws { + /* Setup */ + + let client = MockOneSignalClient() + + // 1. Set up mock responses for the anonymous user + MockUserRequests.setDefaultCreateAnonUserResponses(with: client) + + // 2. Set up mock responses for User A + let tagsUserA = ["tag_a": "value_a"] + MockUserRequests.setDefaultIdentifyUserResponses(with: client, externalId: userA_EUID) + MockUserRequests.setAddTagsResponse(with: client, tags: tagsUserA) + + // 3. Set up mock responses for User B + let tagsUserB = ["tag_b": "value_b"] + MockUserRequests.setDefaultCreateUserResponses(with: client, externalId: userB_EUID) + MockUserRequests.setAddTagsResponse(with: client, tags: tagsUserB) + + OneSignalCoreImpl.setSharedClient(client) + + /* When */ + + // 1. Login to user A and add tag + OneSignalUserManagerImpl.sharedInstance.login(externalId: userA_EUID, token: nil) + OneSignalUserManagerImpl.sharedInstance.addTag(key: "tag_a", value: "value_a") + + // 2. Login to user B and add tag + OneSignalUserManagerImpl.sharedInstance.login(externalId: userB_EUID, token: nil) + OneSignalUserManagerImpl.sharedInstance.addTag(key: "tag_b", value: "value_b") + + // 3. Run background threads + OneSignalCoreMocks.waitForBackgroundThreads(seconds: 0.5) + + /* Then */ + + // Assert that every request SDK makes has a response set, and is handled + XCTAssertTrue(client.allRequestsHandled) + + // Assert there is only one request containing these tags and they are sent to the Anon User + // This is because the Identify User request succeeded, so the user remains the same + XCTAssertTrue(client.onlyOneRequest( + contains: "apps/test-app-id/users/by/onesignal_id/\(anonUserOSID)", + contains: ["properties": ["tags": tagsUserA]]) + ) + // Assert there is only one request containing these tags and they are sent to userB + XCTAssertTrue(client.onlyOneRequest( + contains: "apps/test-app-id/users/by/onesignal_id/\(userB_OSID)", + contains: ["properties": ["tags": tagsUserB]]) + ) + } + /* This test simulates this these calls: From 84f312debbf1b59886186f8109a171a72f4859e6 Mon Sep 17 00:00:00 2001 From: Nan Date: Thu, 9 May 2024 10:02:41 -0700 Subject: [PATCH 8/9] [tests] increase time to address flaky tests * Test was failing, increase the time we give to run all threads, and increase the delay in the Client to simulate request making --- .../OneSignalSDK/OneSignalCoreMocks/MockOneSignalClient.swift | 2 +- iOS_SDK/OneSignalSDK/OneSignalUserTests/SwitchUserTests.swift | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/iOS_SDK/OneSignalSDK/OneSignalCoreMocks/MockOneSignalClient.swift b/iOS_SDK/OneSignalSDK/OneSignalCoreMocks/MockOneSignalClient.swift index 9fd5820fb..183df51b8 100644 --- a/iOS_SDK/OneSignalSDK/OneSignalCoreMocks/MockOneSignalClient.swift +++ b/iOS_SDK/OneSignalSDK/OneSignalCoreMocks/MockOneSignalClient.swift @@ -95,7 +95,7 @@ public class MockOneSignalClient: NSObject, IOneSignalClient { if executeInstantaneously { finishExecutingRequest(request, onSuccess: successBlock, onFailure: failureBlock) } else { - executionQueue.asyncAfter(deadline: .now() + .milliseconds(20)) { + executionQueue.asyncAfter(deadline: .now() + .milliseconds(50)) { self.finishExecutingRequest(request, onSuccess: successBlock, onFailure: failureBlock) } } diff --git a/iOS_SDK/OneSignalSDK/OneSignalUserTests/SwitchUserTests.swift b/iOS_SDK/OneSignalSDK/OneSignalUserTests/SwitchUserTests.swift index 2242062ae..9b5f9100b 100644 --- a/iOS_SDK/OneSignalSDK/OneSignalUserTests/SwitchUserTests.swift +++ b/iOS_SDK/OneSignalSDK/OneSignalUserTests/SwitchUserTests.swift @@ -252,7 +252,7 @@ final class SwitchUserTests: XCTestCase { OneSignalUserManagerImpl.sharedInstance.addEmail("email_b@example.com") // 4. Run background threads - OneSignalCoreMocks.waitForBackgroundThreads(seconds: 0.5) + OneSignalCoreMocks.waitForBackgroundThreads(seconds: 1) /* Then */ From 7d60db6183f3807a7e11a61c3ba3772d2095573b Mon Sep 17 00:00:00 2001 From: Nan Date: Thu, 9 May 2024 13:27:18 -0700 Subject: [PATCH 9/9] [tests] rename test class to indicate Integration * SwitchUserTests to SwitchUserIntegrationTests --- iOS_SDK/OneSignalSDK/OneSignal.xcodeproj/project.pbxproj | 8 ++++---- ...chUserTests.swift => SwitchUserIntegrationTests.swift} | 2 +- 2 files changed, 5 insertions(+), 5 deletions(-) rename iOS_SDK/OneSignalSDK/OneSignalUserTests/{SwitchUserTests.swift => SwitchUserIntegrationTests.swift} (99%) diff --git a/iOS_SDK/OneSignalSDK/OneSignal.xcodeproj/project.pbxproj b/iOS_SDK/OneSignalSDK/OneSignal.xcodeproj/project.pbxproj index c594dcf4a..027270223 100644 --- a/iOS_SDK/OneSignalSDK/OneSignal.xcodeproj/project.pbxproj +++ b/iOS_SDK/OneSignalSDK/OneSignal.xcodeproj/project.pbxproj @@ -82,7 +82,7 @@ 3C47A975292642B100312125 /* OneSignalConfigManager.m in Sources */ = {isa = PBXBuildFile; fileRef = 3C47A973292642B100312125 /* OneSignalConfigManager.m */; }; 3C4F9E4428A4466C009F453A /* OSOperationRepo.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3C4F9E4328A4466C009F453A /* OSOperationRepo.swift */; }; 3C5117172B15C31E00563465 /* OSUserState.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3C5117162B15C31E00563465 /* OSUserState.swift */; }; - 3C67F77A2BEB2B710085A0F0 /* SwitchUserTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3C67F7792BEB2B710085A0F0 /* SwitchUserTests.swift */; }; + 3C67F77A2BEB2B710085A0F0 /* SwitchUserIntegrationTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3C67F7792BEB2B710085A0F0 /* SwitchUserIntegrationTests.swift */; }; 3C789DBD293C2206004CF83D /* OSFocusInfluenceParam.m in Sources */ = {isa = PBXBuildFile; fileRef = 7A600B432453790700514A53 /* OSFocusInfluenceParam.m */; }; 3C789DBE293D8EAD004CF83D /* OSFocusInfluenceParam.h in Headers */ = {isa = PBXBuildFile; fileRef = 7A600B41245378ED00514A53 /* OSFocusInfluenceParam.h */; settings = {ATTRIBUTES = (Public, ); }; }; 3C7A39C12B7BED900082665E /* OneSignalCoreMocks.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 3CC0639A2B6D7A8C002BB07F /* OneSignalCoreMocks.framework */; }; @@ -1125,7 +1125,7 @@ 3C47A973292642B100312125 /* OneSignalConfigManager.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = OneSignalConfigManager.m; sourceTree = ""; }; 3C4F9E4328A4466C009F453A /* OSOperationRepo.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = OSOperationRepo.swift; sourceTree = ""; }; 3C5117162B15C31E00563465 /* OSUserState.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = OSUserState.swift; sourceTree = ""; }; - 3C67F7792BEB2B710085A0F0 /* SwitchUserTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SwitchUserTests.swift; sourceTree = ""; }; + 3C67F7792BEB2B710085A0F0 /* SwitchUserIntegrationTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SwitchUserIntegrationTests.swift; sourceTree = ""; }; 3C7A39D42B7C18EE0082665E /* XCTest.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = XCTest.framework; path = Platforms/iPhoneOS.platform/Developer/Library/Frameworks/XCTest.framework; sourceTree = DEVELOPER_DIR; }; 3C87066F2BDE0957000D8CD2 /* MockUserRequests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MockUserRequests.swift; sourceTree = ""; }; 3C8706712BDEE076000D8CD2 /* MockUserDefines.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MockUserDefines.swift; sourceTree = ""; }; @@ -1965,7 +1965,7 @@ isa = PBXGroup; children = ( 3CC063ED2B6D7FE8002BB07F /* OneSignalUserTests.swift */, - 3C67F7792BEB2B710085A0F0 /* SwitchUserTests.swift */, + 3C67F7792BEB2B710085A0F0 /* SwitchUserIntegrationTests.swift */, ); path = OneSignalUserTests; sourceTree = ""; @@ -3746,7 +3746,7 @@ isa = PBXSourcesBuildPhase; buildActionMask = 2147483647; files = ( - 3C67F77A2BEB2B710085A0F0 /* SwitchUserTests.swift in Sources */, + 3C67F77A2BEB2B710085A0F0 /* SwitchUserIntegrationTests.swift in Sources */, 3CC063EE2B6D7FE8002BB07F /* OneSignalUserTests.swift in Sources */, ); runOnlyForDeploymentPostprocessing = 0; diff --git a/iOS_SDK/OneSignalSDK/OneSignalUserTests/SwitchUserTests.swift b/iOS_SDK/OneSignalSDK/OneSignalUserTests/SwitchUserIntegrationTests.swift similarity index 99% rename from iOS_SDK/OneSignalSDK/OneSignalUserTests/SwitchUserTests.swift rename to iOS_SDK/OneSignalSDK/OneSignalUserTests/SwitchUserIntegrationTests.swift index 9b5f9100b..bbf9d19f4 100644 --- a/iOS_SDK/OneSignalSDK/OneSignalUserTests/SwitchUserTests.swift +++ b/iOS_SDK/OneSignalSDK/OneSignalUserTests/SwitchUserIntegrationTests.swift @@ -4,7 +4,7 @@ import OneSignalCoreMocks import OneSignalUserMocks @testable import OneSignalUser -final class SwitchUserTests: XCTestCase { +final class SwitchUserIntegrationTests: XCTestCase { override func setUpWithError() throws { // TODO: Something like the existing [UnitTestCommonMethods beforeEachTest:self];