mirror of
https://github.com/RevenueCat/purchases-ios
synced 2026-11-09 22:35:56 +05:45
Handle re-login as the same user (#8100)
In the case where `Purchases.shared.logIn` is called with the current app user id, skip invoking the internal auth delegate, because nothing critical has changed. This means that existing caches will remain. This continues to call through to the identityManager to performLogIn, so that existing logic around syncing subscriber attributes etc is preserved.
This commit is contained in:
1 parent
949a10492c
commit
20ed8107b5
3 files changed
+85
-3
No files matched your search
@@ -136,6 +136,7 @@ public final class Authentication: NSObject {
|
||||
return
|
||||
}
|
||||
|
||||
let originalAppUserID = self.identityManager.currentAppUserID
|
||||
let normalizedAppUserID = appUserID.trimmingWhitespacesAndNewLines
|
||||
|
||||
self.ongoingUserInitiatedRequestCount.increment()
|
||||
@@ -145,7 +146,7 @@ public final class Authentication: NSObject {
|
||||
self.operationDispatcher.dispatchOnMainThread {
|
||||
switch result {
|
||||
case .success(let values):
|
||||
if let delegate = self.internalDelegate {
|
||||
if let delegate = self.internalDelegate, normalizedAppUserID != originalAppUserID {
|
||||
delegate.authenticatorDidChangeIdentity(reason: .identified) { _ in
|
||||
completion(values.info, values.created, nil)
|
||||
}
|
||||
|
||||
@@ -19,6 +19,7 @@ import XCTest
|
||||
class AuthenticationTests: TestCase {
|
||||
|
||||
private static let appUserID = "test-app-user-id"
|
||||
private static let newAppUserID = "new-app-user-id"
|
||||
|
||||
private var backend: MockBackend!
|
||||
private var identityManager: MockIdentityManager!
|
||||
@@ -80,7 +81,7 @@ class AuthenticationTests: TestCase {
|
||||
var receivedCreated: Bool?
|
||||
var receivedError: PublicError?
|
||||
|
||||
authentication.identifyCurrentUser(as: Self.appUserID) { info, created, error in
|
||||
authentication.identifyCurrentUser(as: Self.newAppUserID) { info, created, error in
|
||||
receivedInfo = info
|
||||
receivedCreated = created
|
||||
receivedError = error
|
||||
@@ -89,11 +90,47 @@ class AuthenticationTests: TestCase {
|
||||
expect(receivedInfo) == expectedInfo
|
||||
expect(receivedCreated) == true
|
||||
expect(receivedError).to(beNil())
|
||||
expect(self.identityManager.invokedLogInParametersList) == [Self.appUserID]
|
||||
expect(self.identityManager.invokedLogInParametersList) == [Self.newAppUserID]
|
||||
expect(self.internalDelegate.invokedAuthenticatorDidChangeIdentity) == true
|
||||
expect(self.internalDelegate.invokedAuthenticatorDidChangeIdentityParametersList.last) == .identified
|
||||
}
|
||||
|
||||
func testIdentifyCurrentUserWithCurrentAppUserIDDoesNotNotifyInternalDelegate() throws {
|
||||
let authentication = self.makeAuthentication()
|
||||
let expectedInfo = try CustomerInfo(data: Self.customerInfoData(originalAppUserId: Self.appUserID))
|
||||
self.identityManager.mockLogInResult = .success((expectedInfo, false))
|
||||
|
||||
var receivedInfo: CustomerInfo?
|
||||
var receivedCreated: Bool?
|
||||
var receivedError: PublicError?
|
||||
|
||||
authentication.identifyCurrentUser(as: Self.appUserID) { info, created, error in
|
||||
receivedInfo = info
|
||||
receivedCreated = created
|
||||
receivedError = error
|
||||
}
|
||||
|
||||
expect(receivedInfo) == expectedInfo
|
||||
expect(receivedCreated) == false
|
||||
expect(receivedError).to(beNil())
|
||||
expect(self.identityManager.invokedLogInParametersList) == [Self.appUserID]
|
||||
expect(self.internalDelegate.invokedAuthenticatorDidChangeIdentity) == false
|
||||
}
|
||||
|
||||
func testIdentifyCurrentUserWithUntrimmedCurrentAppUserIDDoesNotNotifyInternalDelegate() throws {
|
||||
let authentication = self.makeAuthentication()
|
||||
let expectedInfo = try CustomerInfo(data: Self.customerInfoData(originalAppUserId: Self.appUserID))
|
||||
self.identityManager.mockLogInResult = .success((expectedInfo, false))
|
||||
|
||||
var receivedInfo: CustomerInfo?
|
||||
authentication.identifyCurrentUser(as: " \(Self.appUserID)\n") { info, _, _ in
|
||||
receivedInfo = info
|
||||
}
|
||||
|
||||
expect(receivedInfo) == expectedInfo
|
||||
expect(self.internalDelegate.invokedAuthenticatorDidChangeIdentity) == false
|
||||
}
|
||||
|
||||
func testIdentifyCurrentUserWithStringFailureDoesNotNotifyInternalDelegate() {
|
||||
let authentication = self.makeAuthentication()
|
||||
let backendError = BackendError.networkError(.offlineConnection())
|
||||
|
||||
@@ -62,6 +62,50 @@ class PurchasesLogInTests: BasePurchasesLogInTests {
|
||||
expect(self.mockRemoteConfigManager.invokedRefreshRemoteConfigCount) == baselineRefreshCount + 1
|
||||
}
|
||||
|
||||
func testLogInWithCurrentAppUserIDDoesNotUpdateCaches() {
|
||||
expect(self.backend.getCustomerInfoCallCount).toEventually(equal(1))
|
||||
// the mock now reports `appUserID` as the current user
|
||||
self.identityManager.mockIsAnonymous = false
|
||||
self.identityManager.mockLogInResult = .success((Self.mockLoggedInInfo, false))
|
||||
|
||||
let baselineOfferingsCount = self.mockOfferingsManager.invokedUpdateOfferingsCacheCount
|
||||
let baselineRemoteConfigCount = self.mockRemoteConfigManager.invokedRefreshRemoteConfigCount
|
||||
|
||||
let result = waitUntilValue { completed in
|
||||
self.purchases.logIn(Self.appUserID) { customerInfo, created, error in
|
||||
completed(Self.logInResult(customerInfo, created, error))
|
||||
}
|
||||
}
|
||||
|
||||
expect(result).to(beSuccess())
|
||||
expect(result?.value) == (Self.mockLoggedInInfo, false)
|
||||
expect(self.identityManager.invokedLogInParametersList) == [Self.appUserID]
|
||||
expect(self.backend.getCustomerInfoCallCount) == 1
|
||||
expect(self.mockOfferingsManager.invokedUpdateOfferingsCacheCount) == baselineOfferingsCount
|
||||
expect(self.mockRemoteConfigManager.invokedRefreshRemoteConfigCount) == baselineRemoteConfigCount
|
||||
}
|
||||
|
||||
func testLogInWithUntrimmedCurrentAppUserIDDoesNotUpdateCaches() {
|
||||
expect(self.backend.getCustomerInfoCallCount).toEventually(equal(1))
|
||||
// the mock now reports `appUserID` as the current user
|
||||
self.identityManager.mockIsAnonymous = false
|
||||
self.identityManager.mockLogInResult = .success((Self.mockLoggedInInfo, false))
|
||||
|
||||
let baselineOfferingsCount = self.mockOfferingsManager.invokedUpdateOfferingsCacheCount
|
||||
let baselineRemoteConfigCount = self.mockRemoteConfigManager.invokedRefreshRemoteConfigCount
|
||||
|
||||
waitUntil { completed in
|
||||
self.purchases.logIn(" \(Self.appUserID) ") { _, _, _ in
|
||||
completed()
|
||||
}
|
||||
}
|
||||
|
||||
expect(self.identityManager.invokedLogInParametersList) == [Self.appUserID]
|
||||
expect(self.backend.getCustomerInfoCallCount) == 1
|
||||
expect(self.mockOfferingsManager.invokedUpdateOfferingsCacheCount) == baselineOfferingsCount
|
||||
expect(self.mockRemoteConfigManager.invokedRefreshRemoteConfigCount) == baselineRemoteConfigCount
|
||||
}
|
||||
|
||||
func testLogInWithFailure() {
|
||||
let error: BackendError = .networkError(.offlineConnection())
|
||||
self.identityManager.mockLogInResult = .failure(error)
|
||||
|
||||
Reference in new issue
Block a user