Skip to content

Commit

Permalink
CustomerInfoManager: allow disabling post-transaction behavior
Browse files Browse the repository at this point in the history
See #2914 (comment)
This will be used by that PR as a fallback whenever we try to post a transaction that had already been posted.
  • Loading branch information
NachoSoto committed Aug 14, 2023
1 parent 7a23d5b commit 11bfffb
Show file tree
Hide file tree
Showing 3 changed files with 67 additions and 21 deletions.
35 changes: 24 additions & 11 deletions Sources/Identity/CustomerInfoManager.swift
Original file line number Diff line number Diff line change
Expand Up @@ -51,9 +51,11 @@ class CustomerInfoManager {

func fetchAndCacheCustomerInfo(appUserID: String,
isAppBackgrounded: Bool,
postTransactionsIfNeeded: Bool = true,
completion: CustomerInfoCompletion?) {
self.getCustomerInfo(appUserID: appUserID,
isAppBackgrounded: isAppBackgrounded) { result in
self.getCustomerInfoOrPostTransactions(appUserID: appUserID,
isAppBackgrounded: isAppBackgrounded,
postTransactionsIfNeeded: postTransactionsIfNeeded) { result in
switch result {
case let .failure(error):
self.withData { $0.deviceCache.clearCustomerInfoCacheTimestamp(appUserID: appUserID) }
Expand All @@ -78,6 +80,7 @@ class CustomerInfoManager {

func fetchAndCacheCustomerInfoIfStale(appUserID: String,
isAppBackgrounded: Bool,
postTransactionsIfNeeded: Bool = true,
completion: CustomerInfoCompletion?) {
let isCacheStale = self.withData {
$0.deviceCache.isCustomerInfoCacheStale(appUserID: appUserID, isAppBackgrounded: isAppBackgrounded)
Expand All @@ -89,6 +92,7 @@ class CustomerInfoManager {
: Strings.customerInfo.customerinfo_stale_updating_in_foreground)
self.fetchAndCacheCustomerInfo(appUserID: appUserID,
isAppBackgrounded: isAppBackgrounded,
postTransactionsIfNeeded: postTransactionsIfNeeded,
completion: completion)
return
}
Expand All @@ -101,17 +105,16 @@ class CustomerInfoManager {
}

func sendCachedCustomerInfoIfAvailable(appUserID: String) {
guard let info = self.cachedCustomerInfo(appUserID: appUserID) else {
return
if let info = self.cachedCustomerInfo(appUserID: appUserID) {
self.sendUpdateIfChanged(customerInfo: info)
}

self.sendUpdateIfChanged(customerInfo: info)
}

// swiftlint:disable:next function_body_length
func customerInfo(
appUserID: String,
fetchPolicy: CacheFetchPolicy,
postTransactionsIfNeeded: Bool = true,
completion: CustomerInfoCompletion?
) {
switch fetchPolicy {
Expand All @@ -126,6 +129,7 @@ class CustomerInfoManager {
self.systemInfo.isApplicationBackgrounded { isAppBackgrounded in
self.fetchAndCacheCustomerInfo(appUserID: appUserID,
isAppBackgrounded: isAppBackgrounded,
postTransactionsIfNeeded: postTransactionsIfNeeded,
completion: completion)
}

Expand All @@ -149,6 +153,7 @@ class CustomerInfoManager {
self.systemInfo.isApplicationBackgrounded { isAppBackgrounded in
self.fetchAndCacheCustomerInfoIfStale(appUserID: appUserID,
isAppBackgrounded: isAppBackgrounded,
postTransactionsIfNeeded: postTransactionsIfNeeded,
completion: completionIfNotCalledAlready)
}

Expand All @@ -170,6 +175,7 @@ class CustomerInfoManager {
} else {
self.fetchAndCacheCustomerInfo(appUserID: appUserID,
isAppBackgrounded: isAppBackgrounded,
postTransactionsIfNeeded: postTransactionsIfNeeded,
completion: completion)
}
}
Expand Down Expand Up @@ -289,10 +295,15 @@ class CustomerInfoManager {
@available(iOS 13.0, macOS 10.15, tvOS 13.0, watchOS 6.2, *)
extension CustomerInfoManager {

func fetchAndCacheCustomerInfo(appUserID: String, isAppBackgrounded: Bool) async throws -> CustomerInfo {
func fetchAndCacheCustomerInfo(
appUserID: String,
isAppBackgrounded: Bool,
postTransactionsIfNeeded: Bool = true
) async throws -> CustomerInfo {
return try await Async.call { completion in
return self.fetchAndCacheCustomerInfo(appUserID: appUserID,
isAppBackgrounded: isAppBackgrounded,
postTransactionsIfNeeded: postTransactionsIfNeeded,
completion: completion)
}
}
Expand All @@ -314,10 +325,12 @@ extension CustomerInfoManager {

private extension CustomerInfoManager {

func getCustomerInfo(appUserID: String,
isAppBackgrounded: Bool,
completion: @escaping CustomerAPI.CustomerInfoResponseHandler) {
if #available(iOS 15.0, tvOS 15.0, macOS 12.0, watchOS 8.0, *) {
func getCustomerInfoOrPostTransactions(appUserID: String,
isAppBackgrounded: Bool,
postTransactionsIfNeeded: Bool = true,
completion: @escaping CustomerAPI.CustomerInfoResponseHandler) {
if #available(iOS 15.0, tvOS 15.0, macOS 12.0, watchOS 8.0, *),
postTransactionsIfNeeded {
_ = Task<Void, Never> {
let transactions = await self.transactionFetcher.unfinishedVerifiedTransactions

Expand Down
14 changes: 14 additions & 0 deletions Tests/UnitTests/Identity/CustomerInfoManagerPostReceiptTests.swift
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,20 @@ class CustomerInfoManagerPostReceiptTests: BaseCustomerInfoManagerTests {
expect(self.mockTransactionPoster.invokedHandlePurchasedTransaction.value) == false
}

func testDoesNotTryToPostUnfinishedTransactionsIfDisabled() async throws {
self.mockTransationFetcher.stubbedUnfinishedTransactions = [Self.createTransaction()]
self.mockBackend.stubbedGetCustomerInfoResult = .success(self.mockCustomerInfo)

let result = try await self.customerInfoManager.fetchAndCacheCustomerInfo(appUserID: Self.userID,
isAppBackgrounded: false,
postTransactionsIfNeeded: false)
expect(result) === self.mockCustomerInfo

expect(self.mockBackend.invokedGetSubscriberDataCount) == 1
expect(self.mockBackend.invokedGetSubscriberDataParameters?.randomDelay) == false
expect(self.mockTransactionPoster.invokedHandlePurchasedTransaction.value) == false
}

func testReturnsFailureIfPostingReceiptFails() async throws {
self.mockTransationFetcher.stubbedUnfinishedTransactions = [Self.createTransaction()]
self.mockTransactionPoster.stubbedHandlePurchasedTransactionResult.value = .failure(
Expand Down
39 changes: 29 additions & 10 deletions Tests/UnitTests/Mocks/MockCustomerInfoManager.swift
Original file line number Diff line number Diff line change
Expand Up @@ -16,34 +16,50 @@ class MockCustomerInfoManager: CustomerInfoManager {

var invokedFetchAndCacheCustomerInfo = false
var invokedFetchAndCacheCustomerInfoCount = 0
var invokedFetchAndCacheCustomerInfoParameters: (appUserID: String, isAppBackgrounded: Bool, completion: CustomerInfoCompletion?)?
var invokedFetchAndCacheCustomerInfoParameters: (appUserID: String,
isAppBackgrounded: Bool,
postTransactionsIfNeeded: Bool,
completion: CustomerInfoCompletion?)?
var invokedFetchAndCacheCustomerInfoParametersList = [(appUserID: String,
isAppBackgrounded: Bool,
postTransactionsIfNeeded: Bool,
completion: CustomerInfoCompletion?)]()

override func fetchAndCacheCustomerInfo(appUserID: String,
isAppBackgrounded: Bool,
postTransactionsIfNeeded: Bool = true,
completion: CustomerInfoCompletion?) {
invokedFetchAndCacheCustomerInfo = true
invokedFetchAndCacheCustomerInfoCount += 1
invokedFetchAndCacheCustomerInfoParameters = (appUserID, isAppBackgrounded, completion)
invokedFetchAndCacheCustomerInfoParametersList.append((appUserID, isAppBackgrounded, completion))
self.invokedFetchAndCacheCustomerInfo = true
self.invokedFetchAndCacheCustomerInfoCount += 1
self.invokedFetchAndCacheCustomerInfoParameters = (appUserID, isAppBackgrounded, postTransactionsIfNeeded, completion)
self.invokedFetchAndCacheCustomerInfoParametersList.append((appUserID,
isAppBackgrounded,
postTransactionsIfNeeded,
completion))
}

var invokedFetchAndCacheCustomerInfoIfStale = false
var invokedFetchAndCacheCustomerInfoIfStaleCount = 0
var invokedFetchAndCacheCustomerInfoIfStaleParameters: (appUserID: String, isAppBackgrounded: Bool, completion: CustomerInfoCompletion?)?
var invokedFetchAndCacheCustomerInfoIfStaleParameters: (appUserID: String,
isAppBackgrounded: Bool,
postTransactionsIfNeeded: Bool,
completion: CustomerInfoCompletion?)?
var invokedFetchAndCacheCustomerInfoIfStaleParametersList = [(appUserID: String,
isAppBackgrounded: Bool,
postTransactionsIfNeeded: Bool,
completion: CustomerInfoCompletion?)]()

override func fetchAndCacheCustomerInfoIfStale(appUserID: String,
isAppBackgrounded: Bool,
postTransactionsIfNeeded: Bool = true,
completion: CustomerInfoCompletion?) {
self.invokedFetchAndCacheCustomerInfoIfStale = true
self.invokedFetchAndCacheCustomerInfoIfStaleCount += 1
self.invokedFetchAndCacheCustomerInfoIfStaleParameters = (appUserID, isAppBackgrounded, completion)
self.invokedFetchAndCacheCustomerInfoIfStaleParametersList.append((appUserID, isAppBackgrounded, completion))
self.invokedFetchAndCacheCustomerInfoIfStaleParameters = (appUserID,
isAppBackgrounded,
postTransactionsIfNeeded,
completion)
self.invokedFetchAndCacheCustomerInfoIfStaleParametersList.append((appUserID, isAppBackgrounded, postTransactionsIfNeeded, completion))
}

var invokedSendCachedCustomerInfoIfAvailable = false
Expand All @@ -62,20 +78,23 @@ class MockCustomerInfoManager: CustomerInfoManager {
var invokedCustomerInfoCount = 0
var invokedCustomerInfoParameters: (appUserID: String,
fetchPolicy: CacheFetchPolicy,
postTransactionsIfNeeded: Bool,
completion: CustomerInfoCompletion?)?
var invokedCustomerInfoParametersList: [(appUserID: String,
fetchPolicy: CacheFetchPolicy,
postTransactionsIfNeeded: Bool,
completion: CustomerInfoCompletion?)] = []

var stubbedCustomerInfoResult: Result<CustomerInfo, BackendError> = .failure(.missingAppUserID())

override func customerInfo(appUserID: String,
fetchPolicy: CacheFetchPolicy,
postTransactionsIfNeeded: Bool = true,
completion: CustomerInfoCompletion?) {
self.invokedCustomerInfo = true
self.invokedCustomerInfoCount += 1
self.invokedCustomerInfoParameters = (appUserID, fetchPolicy, completion)
self.invokedCustomerInfoParametersList.append((appUserID, fetchPolicy, completion))
self.invokedCustomerInfoParameters = (appUserID, fetchPolicy, postTransactionsIfNeeded, completion)
self.invokedCustomerInfoParametersList.append((appUserID, fetchPolicy, postTransactionsIfNeeded, completion))

OperationDispatcher.dispatchOnMainActor {
completion?(self.stubbedCustomerInfoResult)
Expand Down

0 comments on commit 11bfffb

Please sign in to comment.