Skip to content

Commit 968b3f2

Browse files
authored
SDK-124 JWT mechanism not engaged via InAppManager (#968)
1 parent f75a324 commit 968b3f2

File tree

10 files changed

+117
-24
lines changed

10 files changed

+117
-24
lines changed

sample-apps/inbox-customization/inbox-customization/Mock Data/DataManager.swift

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -48,7 +48,7 @@ final class DataManager {
4848
}
4949

5050
struct DemoDependencyContainer: DependencyContainerProtocol {
51-
func createInAppFetcher(apiClient _: ApiClientProtocol) -> InAppFetcherProtocol {
51+
func createInAppFetcher(apiClient _: ApiClientProtocol, authManager _: IterableAuthManagerProtocol?) -> InAppFetcherProtocol {
5252
inAppFetcher
5353
}
5454

swift-sdk/Internal/InternalIterableAPI.swift

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -87,7 +87,8 @@ final class InternalIterableAPI: NSObject, PushTrackerProtocol, AuthProvider {
8787
self.dependencyContainer.createInAppManager(config: self.config,
8888
apiClient: self.apiClient,
8989
requestHandler: self.requestHandler,
90-
deviceMetadata: deviceMetadata)
90+
deviceMetadata: deviceMetadata,
91+
authManager: self.authManager)
9192
}()
9293

9394
lazy var authManager: IterableAuthManagerProtocol = {

swift-sdk/Internal/Utilities/DependencyContainer.swift

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -5,8 +5,8 @@
55
import Foundation
66

77
struct DependencyContainer: DependencyContainerProtocol {
8-
func createInAppFetcher(apiClient: ApiClientProtocol) -> InAppFetcherProtocol {
9-
InAppFetcher(apiClient: apiClient)
8+
func createInAppFetcher(apiClient: ApiClientProtocol, authManager: IterableAuthManagerProtocol?) -> InAppFetcherProtocol {
9+
InAppFetcher(apiClient: apiClient, authManager: authManager)
1010
}
1111

1212
let dateProvider: DateProviderProtocol = SystemDateProvider()

swift-sdk/Internal/Utilities/DependencyContainerProtocol.swift

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,7 @@ protocol DependencyContainerProtocol: RedirectNetworkSessionProvider {
1616
var notificationCenter: NotificationCenterProtocol { get }
1717
var apnsTypeChecker: APNSTypeCheckerProtocol { get }
1818

19-
func createInAppFetcher(apiClient: ApiClientProtocol) -> InAppFetcherProtocol
19+
func createInAppFetcher(apiClient: ApiClientProtocol, authManager: IterableAuthManagerProtocol?) -> InAppFetcherProtocol
2020
func createPersistenceContextProvider() -> IterablePersistenceContextProvider?
2121
func createRequestHandler(apiKey: String,
2222
config: IterableConfig,
@@ -32,10 +32,11 @@ extension DependencyContainerProtocol {
3232
func createInAppManager(config: IterableConfig,
3333
apiClient: ApiClientProtocol,
3434
requestHandler: RequestHandlerProtocol,
35-
deviceMetadata: DeviceMetadata) -> IterableInternalInAppManagerProtocol {
35+
deviceMetadata: DeviceMetadata,
36+
authManager: IterableAuthManagerProtocol?) -> IterableInternalInAppManagerProtocol {
3637
InAppManager(requestHandler: requestHandler,
3738
deviceMetadata: deviceMetadata,
38-
fetcher: createInAppFetcher(apiClient: apiClient),
39+
fetcher: createInAppFetcher(apiClient: apiClient, authManager: authManager),
3940
displayer: inAppDisplayer,
4041
persister: inAppPersister,
4142
inAppDelegate: config.inAppDelegate,

swift-sdk/Internal/in-app/InAppHelper.swift

Lines changed: 12 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -8,8 +8,18 @@ import UIKit
88
/// All classes/structs are internal.
99

1010
struct InAppHelper {
11-
static func getInAppMessagesFromServer(apiClient: ApiClientProtocol, number: Int) -> Pending<[IterableInAppMessage], SendRequestError> {
12-
apiClient.getInAppMessages(NSNumber(value: number)).map {
11+
static func getInAppMessagesFromServer(apiClient: ApiClientProtocol,
12+
authManager: IterableAuthManagerProtocol?,
13+
number: Int,
14+
successHandler onSuccess: OnSuccessHandler? = nil,
15+
failureHandler onFailure: OnFailureHandler? = nil) -> Pending<[IterableInAppMessage], SendRequestError> {
16+
17+
RequestProcessorUtil.sendRequest(requestProvider: { apiClient.getInAppMessages(NSNumber(value: number)) },
18+
successHandler: onSuccess,
19+
failureHandler: onFailure,
20+
authManager: authManager,
21+
requestIdentifier: "getInAppMessages")
22+
.map {
1323
InAppMessageParser.parse(payload: $0).compactMap { parseResult in
1424
process(parseResult: parseResult, apiClient: apiClient)
1525
}

swift-sdk/Internal/in-app/InAppInternal.swift

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -26,9 +26,10 @@ struct IterableInAppMessageMetadata {
2626
}
2727

2828
class InAppFetcher: InAppFetcherProtocol {
29-
init(apiClient: ApiClientProtocol) {
29+
init(apiClient: ApiClientProtocol, authManager: IterableAuthManagerProtocol?) {
3030
ITBInfo()
3131
self.apiClient = apiClient
32+
self.authManager = authManager
3233
}
3334

3435
deinit {
@@ -43,12 +44,15 @@ class InAppFetcher: InAppFetcherProtocol {
4344
return Fulfill(error: IterableError.general(description: "Invalid state: expected InternalApi"))
4445
}
4546

46-
return InAppHelper.getInAppMessagesFromServer(apiClient: apiClient, number: numMessages).mapFailure { $0 }
47+
return InAppHelper.getInAppMessagesFromServer(apiClient: apiClient,
48+
authManager: authManager,
49+
number: numMessages).mapFailure { $0 }
4750
}
4851

4952
// MARK: - Private/Internal
5053

5154
private weak var apiClient: ApiClientProtocol?
55+
private let authManager: IterableAuthManagerProtocol?
5256

5357
private let numMessages = 100
5458
}

tests/common/CommonExtensions.swift

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -121,7 +121,7 @@ class MockDependencyContainer: DependencyContainerProtocol {
121121
ITBInfo()
122122
}
123123

124-
func createInAppFetcher(apiClient _: ApiClientProtocol) -> InAppFetcherProtocol {
124+
func createInAppFetcher(apiClient _: ApiClientProtocol, authManager _: IterableAuthManagerProtocol?) -> InAppFetcherProtocol {
125125
inAppFetcher
126126
}
127127

tests/common/MockAuthManager.swift

Lines changed: 21 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -10,11 +10,20 @@ import Foundation
1010

1111
class MockAuthManager: IterableAuthManagerProtocol {
1212

13+
var token = "AuthToken"
14+
1315
var shouldRetry = true
1416
var retryWasRequested = false
17+
var isLastAuthTokenValid = false
18+
var pauseAuthRetries = false
19+
var handleAuthFailureCalled = false
20+
var getNextRetryIntervalCalled = false
21+
var failedAuthCount = 0
1522

1623
func handleAuthFailure(failedAuthToken: String?, reason: IterableSDK.AuthFailureReason) {
17-
24+
failedAuthCount += 1
25+
handleAuthFailureCalled = true
26+
print("AuthManager handleAuthFailure with reason: \(reason.rawValue) and token: \(String(describing: failedAuthToken))")
1827
}
1928

2029
func requestNewAuthToken(hasFailedPriorAuth: Bool, onSuccess: ((String?) -> Void)?, shouldIgnoreRetryPolicy: Bool) {
@@ -31,32 +40,37 @@ class MockAuthManager: IterableAuthManagerProtocol {
3140
}
3241

3342
func scheduleAuthTokenRefreshTimer(interval: TimeInterval, isScheduledRefresh: Bool, successCallback: IterableSDK.AuthTokenRetrievalHandler?) {
34-
requestNewAuthToken(hasFailedPriorAuth: false, onSuccess: successCallback, shouldIgnoreRetryPolicy: true)
43+
requestNewAuthToken(hasFailedPriorAuth: false, onSuccess: { newToken in
44+
guard let newToken else { return }
45+
self.setNewToken(newToken)
46+
successCallback?(newToken)
47+
}, shouldIgnoreRetryPolicy: true)
3548
}
3649

3750
func pauseAuthRetries(_ pauseAuthRetry: Bool) {
38-
51+
pauseAuthRetries = pauseAuthRetry
3952
}
4053

4154
func setIsLastAuthTokenValid(_ isValid: Bool) {
42-
55+
isLastAuthTokenValid = isValid
4356
}
4457

4558
func getNextRetryInterval() -> Double {
59+
getNextRetryIntervalCalled = true
4660
return 0
4761
}
4862

4963

5064
func getAuthToken() -> String? {
51-
return "AuthToken"
65+
token
5266
}
5367

5468
func resetFailedAuthCount() {
55-
69+
failedAuthCount = 0
5670
}
5771

5872
func setNewToken(_ newToken: String) {
59-
73+
token = newToken
6074
}
6175

6276
func logoutUser() {

tests/endpoint-tests/E2EDependencyContainer.swift

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -19,8 +19,8 @@ class E2EDependencyContainer: DependencyContainerProtocol {
1919
let notificationCenter: NotificationCenterProtocol
2020
let apnsTypeChecker: APNSTypeCheckerProtocol
2121

22-
func createInAppFetcher(apiClient: ApiClientProtocol) -> InAppFetcherProtocol {
23-
InAppFetcher(apiClient: apiClient)
22+
func createInAppFetcher(apiClient: ApiClientProtocol, authManager: IterableAuthManagerProtocol?) -> InAppFetcherProtocol {
23+
InAppFetcher(apiClient: apiClient, authManager: authManager)
2424
}
2525

2626
init(dateProvider: DateProviderProtocol = SystemDateProvider(),

tests/unit-tests/InAppHelperTests.swift

Lines changed: 66 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,30 @@ import XCTest
66

77
@testable import IterableSDK
88

9+
private final class RetryingApiClient: BlankApiClient {
10+
var numOfMessages = 3
11+
var callCount = -1
12+
var lastCountRequested: NSNumber?
13+
var failureReason = "jwt token is expired"
14+
weak var authManager: MockAuthManager?
15+
16+
override func getInAppMessages(_ count: NSNumber) -> Pending<SendRequestValue, SendRequestError> {
17+
callCount += 1
18+
lastCountRequested = count
19+
20+
if callCount == 0 {
21+
return Fulfill(value: TestInAppPayloadGenerator.createPayloadWithUrl(numMessages: numOfMessages))
22+
}
23+
24+
if authManager?.retryWasRequested == true {
25+
return Fulfill(value: TestInAppPayloadGenerator.createPayloadWithUrl(numMessages: numOfMessages))
26+
}
27+
return Fulfill(error: SendRequestError(reason: failureReason,
28+
httpStatusCode: 401,
29+
iterableCode: JsonValue.Code.invalidJwtPayload))
30+
}
31+
}
32+
933
class InAppHelperTests: XCTestCase {
1034
func testGetInAppMessagesWithNoError() {
1135
class MyApiClient: BlankApiClient {
@@ -15,7 +39,7 @@ class InAppHelperTests: XCTestCase {
1539
}
1640
}
1741

18-
InAppHelper.getInAppMessagesFromServer(apiClient: MyApiClient(), number: 10).onSuccess { messages in
42+
InAppHelper.getInAppMessagesFromServer(apiClient: MyApiClient(), authManager: nil, number: 10).onSuccess { messages in
1943
XCTAssertEqual(messages.count, 3)
2044
XCTAssertEqual(messages[0].messageId, "message1")
2145
XCTAssertEqual(messages[1].messageId, "message2")
@@ -69,14 +93,53 @@ class InAppHelperTests: XCTestCase {
6993
}
7094
}
7195

72-
InAppHelper.getInAppMessagesFromServer(apiClient: MyApiClient(expectation: expectation1), number: 10).onSuccess { messages in
96+
InAppHelper.getInAppMessagesFromServer(apiClient: MyApiClient(expectation: expectation1), authManager: nil, number: 10).onSuccess { messages in
7397
XCTAssertEqual(messages.count, 1)
7498
XCTAssertEqual(messages[0].messageId, "message1")
7599
}
76100

77101
wait(for: [expectation1], timeout: testExpectationTimeout)
78102
}
79-
103+
104+
func testGetInAppMessagesRetriesAfterJWT401() {
105+
let authManager = MockAuthManager()
106+
authManager.shouldRetry = true
107+
108+
let apiClient = RetryingApiClient()
109+
apiClient.authManager = authManager
110+
111+
InAppHelper.getInAppMessagesFromServer(apiClient: apiClient,
112+
authManager: authManager,
113+
number: apiClient.numOfMessages).onSuccess { messages in
114+
print(messages)
115+
}.onError { error in
116+
XCTFail("expected success, got error: \(error)")
117+
}
118+
119+
InAppHelper.getInAppMessagesFromServer(apiClient: apiClient,
120+
authManager: authManager,
121+
number: apiClient.numOfMessages,
122+
successHandler: { data in
123+
XCTAssertTrue(authManager.handleAuthFailureCalled)
124+
XCTAssertTrue(authManager.getNextRetryIntervalCalled)
125+
126+
XCTAssertTrue(authManager.retryWasRequested)
127+
XCTAssertEqual(authManager.getAuthToken(), "newAuthToken")
128+
}).onSuccess { messages in
129+
print(messages)
130+
}.onError { error in
131+
XCTFail("expected success, got error: \(error)")
132+
}
133+
134+
InAppHelper.getInAppMessagesFromServer(apiClient: apiClient,
135+
authManager: authManager,
136+
number: apiClient.numOfMessages).onSuccess { messages in
137+
XCTAssertTrue(authManager.retryWasRequested)
138+
}.onError { error in
139+
XCTFail("expected success, got error: \(error)")
140+
}
141+
}
142+
80143
func testParseURL() {
81144
let urlWithNoScheme = URL(string: "blah")!
82145
XCTAssertNil(InAppHelper.parse(inAppUrl: urlWithNoScheme))

0 commit comments

Comments
 (0)