Skip to content

Commit e4577da

Browse files
authored
Merge pull request #517 from stytchauth/jordan/SDK-2810-timer-fix-forward
SDK-2810 Timer fix forward
2 parents 04cd2bb + 06bb776 commit e4577da

24 files changed

+120
-98
lines changed

Sources/StytchCore/Environment.swift

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -127,9 +127,11 @@ struct Environment {
127127
$0.asyncAfter(deadline: $1, execute: $2)
128128
}
129129

130-
var timer: (TimeInterval, RunLoop, @escaping () -> Void) -> Timer = { interval, runloop, task in
131-
let timer = Timer(timeInterval: interval, repeats: true) { _ in task() }
132-
runloop.add(timer, forMode: .common)
130+
var timer: (TimeInterval, DispatchQueue, @escaping () -> Void) -> DispatchSourceTimer = { interval, queue, task in
131+
let timer = DispatchSource.makeTimerSource(queue: queue)
132+
timer.schedule(deadline: .now() + interval, repeating: interval)
133+
timer.setEventHandler { task() }
134+
timer.resume()
133135
return timer
134136
}
135137
}

Sources/StytchCore/PollingClient/PollingClient.swift

Lines changed: 14 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@ final class PollingClient {
66
private let queue: DispatchQueue
77
private let task: Task
88
private var retryClient: RetryClient?
9-
private var timer: Timer?
9+
private var timer: DispatchSourceTimer?
1010

1111
@Dependency(\.timer) private var createTimer
1212

@@ -23,21 +23,24 @@ final class PollingClient {
2323
}
2424

2525
func start() {
26-
timer?.invalidate()
27-
retryClient?.cancel()
28-
retryClient = nil
29-
30-
timer = createTimer(interval, .main) { [weak self] in
26+
queue.async { [weak self] in
3127
guard let self = self else { return }
32-
self.retryClient?.cancel()
33-
self.retryClient = .init(maxRetries: self.maxRetries, queue: self.queue, task: self.task)
34-
self.retryClient?.attempt()
28+
timer?.cancel()
29+
retryClient?.cancel()
30+
retryClient = nil
31+
32+
timer = createTimer(interval, queue) { [weak self] in
33+
guard let self = self else { return }
34+
self.retryClient?.cancel()
35+
self.retryClient = .init(maxRetries: self.maxRetries, queue: self.queue, task: self.task)
36+
self.retryClient?.attempt()
37+
}
3538
}
3639
}
3740

3841
func stop() {
39-
DispatchQueue.main.async { [weak self] in
40-
self?.timer?.invalidate()
42+
queue.async { [weak self] in
43+
self?.timer?.cancel()
4144
self?.timer = nil
4245
self?.retryClient?.cancel()
4346
self?.retryClient = nil

Tests/StytchCoreTests/B2BDiscoveryTestCase.swift

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -41,7 +41,7 @@ final class B2BDiscoveryTestCase: BaseTestCase {
4141

4242
func testExchangeIntermediateSession() async throws {
4343
networkInterceptor.responses { B2BMFAAuthenticateResponse.mock }
44-
Current.timer = { _, _, _ in .init() }
44+
Current.timer = { _, _, _ in Self.mockTimer }
4545

4646
Current.sessionManager.updateSession(intermediateSessionToken: intermediateSessionToken)
4747
XCTAssertTrue(Current.sessionManager.hasValidIntermediateSessionToken)
@@ -62,7 +62,7 @@ final class B2BDiscoveryTestCase: BaseTestCase {
6262

6363
func testCreateOrganization() async throws {
6464
networkInterceptor.responses { B2BMFAAuthenticateResponse.mock }
65-
Current.timer = { _, _, _ in .init() }
65+
Current.timer = { _, _, _ in Self.mockTimer }
6666

6767
Current.sessionManager.updateSession(intermediateSessionToken: intermediateSessionToken)
6868
XCTAssertTrue(Current.sessionManager.hasValidIntermediateSessionToken)

Tests/StytchCoreTests/B2BMagicLinksTestCase.swift

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -110,7 +110,7 @@ final class B2BMagicLinksTestCase: BaseTestCase {
110110

111111
XCTAssertNotNil(try Current.userDefaultsClient.getStringValue(.codeVerifierPKCE))
112112

113-
Current.timer = { _, _, _ in .init() }
113+
Current.timer = { _, _, _ in Self.mockTimer }
114114

115115
Current.sessionManager.updateSession(intermediateSessionToken: intermediateSessionToken)
116116

@@ -167,7 +167,7 @@ final class B2BMagicLinksTestCase: BaseTestCase {
167167

168168
XCTAssertNotNil(try Current.userDefaultsClient.getStringValue(.codeVerifierPKCE))
169169

170-
Current.timer = { _, _, _ in .init() }
170+
Current.timer = { _, _, _ in Self.mockTimer }
171171

172172
_ = try await StytchB2BClient.magicLinks.discoveryAuthenticate(parameters: parameters)
173173

Tests/StytchCoreTests/B2BOAuthTestCase.swift

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@ final class B2BOAuthTestCase: BaseTestCase {
99
StytchB2BClient.OAuth.OAuthAuthenticateResponse.mock
1010
}
1111

12-
Current.timer = { _, _, _ in .init() }
12+
Current.timer = { _, _, _ in Self.mockTimer }
1313

1414
Current.sessionManager.updateSession(intermediateSessionToken: intermediateSessionToken)
1515

@@ -52,7 +52,7 @@ final class B2BOAuthTestCase: BaseTestCase {
5252
)
5353
}
5454

55-
Current.timer = { _, _, _ in .init() }
55+
Current.timer = { _, _, _ in Self.mockTimer }
5656

5757
_ = try Current.pkcePairManager.generateAndReturnPKCECodePair()
5858
XCTAssertNotNil(Current.pkcePairManager.getPKCECodePair())

Tests/StytchCoreTests/B2BOTPTestCase.swift

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -79,7 +79,7 @@ final class B2BOTPTestCase: BaseTestCase {
7979
B2BAuthenticateResponse.mock
8080
}
8181

82-
Current.timer = { _, _, _ in .init() }
82+
Current.timer = { _, _, _ in Self.mockTimer }
8383

8484
let organizationId = "orgid1234"
8585
let memberId = "memberid1234"
@@ -148,7 +148,7 @@ final class B2BOTPTestCase: BaseTestCase {
148148
StytchB2BClient.OTP.Email.AuthenticateResponse.mock
149149
}
150150

151-
Current.timer = { _, _, _ in .init() }
151+
Current.timer = { _, _, _ in Self.mockTimer }
152152

153153
let code = "code1234"
154154
let organizationId = "orgid1234"

Tests/StytchCoreTests/B2BPasswordsTestCase.swift

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,7 @@ final class B2BPasswordsTestCase: BaseTestCase {
1616
locale: .en
1717
)
1818
networkInterceptor.responses { B2BMFAAuthenticateResponse.mock }
19-
Current.timer = { _, _, _ in .init() }
19+
Current.timer = { _, _, _ in Self.mockTimer }
2020

2121
Current.sessionManager.updateSession(intermediateSessionToken: intermediateSessionToken)
2222

@@ -112,7 +112,7 @@ final class B2BPasswordsTestCase: BaseTestCase {
112112
])
113113
)
114114

115-
Current.timer = { _, _, _ in .init() }
115+
Current.timer = { _, _, _ in Self.mockTimer }
116116
XCTAssertNotNil(Current.pkcePairManager.getPKCECodePair())
117117

118118
_ = try await client.resetByEmail(
@@ -143,7 +143,7 @@ final class B2BPasswordsTestCase: BaseTestCase {
143143

144144
func testResetByExistingPassword() async throws {
145145
networkInterceptor.responses { B2BMFAAuthenticateResponse.mock }
146-
Current.timer = { _, _, _ in .init() }
146+
Current.timer = { _, _, _ in Self.mockTimer }
147147

148148
Current.sessionManager.updateSession(intermediateSessionToken: intermediateSessionToken)
149149

@@ -182,7 +182,7 @@ final class B2BPasswordsTestCase: BaseTestCase {
182182
wrapped: .init(memberSession: .mock, member: .mock, organization: .mock)
183183
)
184184
}
185-
Current.timer = { _, _, _ in .init() }
185+
Current.timer = { _, _, _ in Self.mockTimer }
186186

187187
_ = try await client.resetBySession(parameters: .init(organizationId: "org123", password: "hi, i'm Tom.", locale: .en))
188188

@@ -241,7 +241,7 @@ final class B2BPasswordsTestCase: BaseTestCase {
241241
])
242242
)
243243

244-
Current.timer = { _, _, _ in .init() }
244+
Current.timer = { _, _, _ in Self.mockTimer }
245245
XCTAssertNotNil(Current.pkcePairManager.getPKCECodePair())
246246

247247
// Call resetByEmail

Tests/StytchCoreTests/B2BRecoveryCodesTestCase.swift

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -46,7 +46,7 @@ final class B2BRecoveryCodesTestCase: BaseTestCase {
4646
)
4747
}
4848

49-
Current.timer = { _, _, _ in .init() }
49+
Current.timer = { _, _, _ in Self.mockTimer }
5050

5151
let organizationId = "orgid1234"
5252
let memberId = "memberid1234"

Tests/StytchCoreTests/B2BSSOTestCase.swift

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -39,7 +39,7 @@ final class B2BSSOTestCase: BaseTestCase {
3939
networkInterceptor.responses {
4040
B2BMFAAuthenticateResponse.mock
4141
}
42-
Current.timer = { _, _, _ in .init() }
42+
Current.timer = { _, _, _ in Self.mockTimer }
4343

4444
await XCTAssertThrowsErrorAsync(
4545
try await StytchB2BClient.sso.authenticate(parameters: .init(ssoToken: "i-am-token", sessionDurationMinutes: 12, locale: .en)),

Tests/StytchCoreTests/B2BSessionsTestCase.swift

Lines changed: 8 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,7 @@ final class B2BSessionsTestCase: BaseTestCase {
1212
networkInterceptor.responses { B2BAuthenticateResponse.mock }
1313
let parameters: StytchB2BClient.Sessions.AuthenticateParameters = .init(sessionDurationMinutes: 15)
1414

15-
Current.timer = { _, _, _ in .init() }
15+
Current.timer = { _, _, _ in Self.mockTimer }
1616

1717
XCTAssertNil(StytchB2BClient.sessions.memberSession)
1818

@@ -37,6 +37,8 @@ final class B2BSessionsTestCase: BaseTestCase {
3737
func testSessionsAttest() async throws {
3838
networkInterceptor.responses { B2BAuthenticateResponse.mock }
3939

40+
Current.timer = { _, _, _ in Self.mockTimer }
41+
4042
let parameters = StytchB2BClient.Sessions.AttestParameters(
4143
profileId: "profile_123",
4244
token: "attestation_token",
@@ -45,8 +47,6 @@ final class B2BSessionsTestCase: BaseTestCase {
4547
sessionToken: "existing_token"
4648
)
4749

48-
Current.timer = { _, _, _ in .init() }
49-
5050
XCTAssertNil(StytchB2BClient.sessions.memberSession)
5151

5252
_ = try await StytchB2BClient.sessions.attest(parameters: parameters)
@@ -70,7 +70,7 @@ final class B2BSessionsTestCase: BaseTestCase {
7070

7171
func testSessionsRevoke() async throws {
7272
networkInterceptor.responses { BasicResponse(requestId: "request_id", statusCode: 200) }
73-
Current.timer = { _, _, _ in .init() }
73+
Current.timer = { _, _, _ in Self.mockTimer }
7474

7575
Current.sessionManager.updateSession(
7676
sessionType: .member(.mock),
@@ -108,7 +108,7 @@ final class B2BSessionsTestCase: BaseTestCase {
108108
B2BMFAAuthenticateResponse.mock
109109
}
110110

111-
Current.timer = { _, _, _ in .init() }
111+
Current.timer = { _, _, _ in Self.mockTimer }
112112

113113
let organizationID = "org_123"
114114
let parameters = StytchB2BClient.Sessions.ExchangeParameters(organizationID: organizationID)
@@ -141,7 +141,7 @@ final class B2BSessionsTestCase: BaseTestCase {
141141
}
142142
}.store(in: &subscriptions)
143143

144-
Current.timer = { _, _, _ in .init() }
144+
Current.timer = { _, _, _ in Self.mockTimer }
145145
Current.sessionManager.updateSession(
146146
sessionType: .member(.mock),
147147
tokens: SessionTokens(jwt: .jwt("i'm_jwt"), opaque: .opaque("opaque_all_day"))
@@ -164,7 +164,7 @@ final class B2BSessionsTestCase: BaseTestCase {
164164
}
165165
}.store(in: &subscriptions)
166166

167-
Current.timer = { _, _, _ in .init() }
167+
Current.timer = { _, _, _ in Self.mockTimer }
168168
Current.sessionManager.updateSession(
169169
sessionType: nil,
170170
tokens: SessionTokens(jwt: .jwt("i'm_jwt"), opaque: .opaque("opaque_all_day"))
@@ -175,7 +175,7 @@ final class B2BSessionsTestCase: BaseTestCase {
175175
}
176176

177177
func testGetExpiredMemberSessionReturnsNil() throws {
178-
Current.timer = { _, _, _ in .init() }
178+
Current.timer = { _, _, _ in Self.mockTimer }
179179
Current.sessionManager.updateSession(
180180
sessionType: .member(.mockWithExpiredMemberSession),
181181
tokens: SessionTokens(jwt: .jwt("i'm_jwt"), opaque: .opaque("opaque_all_day"))

0 commit comments

Comments
 (0)