Skip to content

Commit 496dc4d

Browse files
committed
Try to refresh token before each API call
1 parent cb9fed0 commit 496dc4d

File tree

10 files changed

+143
-9
lines changed

10 files changed

+143
-9
lines changed

Sources/DropboxClient/Client.swift

Lines changed: 15 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -29,28 +29,34 @@ extension Client {
2929
dateGenerator: DateGenerator = .live,
3030
pkceUtils: PKCEUtils = .live
3131
) -> Client {
32-
Client(
33-
auth: .live(
34-
config: config,
35-
keychain: keychain,
36-
httpClient: httpClient,
37-
openURL: openURL,
38-
dateGenerator: dateGenerator,
39-
pkceUtils: pkceUtils
40-
),
32+
let auth = Auth.live(
33+
config: config,
34+
keychain: keychain,
35+
httpClient: httpClient,
36+
openURL: openURL,
37+
dateGenerator: dateGenerator,
38+
pkceUtils: pkceUtils
39+
)
40+
41+
return Client(
42+
auth: auth,
4143
listFolder: .live(
44+
auth: auth,
4245
keychain: keychain,
4346
httpClient: httpClient
4447
),
4548
downloadFile: .live(
49+
auth: auth,
4650
keychain: keychain,
4751
httpClient: httpClient
4852
),
4953
deleteFile: .live(
54+
auth: auth,
5055
keychain: keychain,
5156
httpClient: httpClient
5257
),
5358
uploadFile: .live(
59+
auth: auth,
5460
keychain: keychain,
5561
httpClient: httpClient
5662
)

Sources/DropboxClient/DeleteFile.swift

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -41,10 +41,13 @@ public struct DeleteFile: Sendable {
4141

4242
extension DeleteFile {
4343
public static func live(
44+
auth: Auth,
4445
keychain: Keychain,
4546
httpClient: HTTPClient
4647
) -> DeleteFile {
4748
DeleteFile { params in
49+
try await auth.refreshToken()
50+
4851
guard let credentials = await keychain.loadCredentials() else {
4952
throw Error.notAuthorized
5053
}

Sources/DropboxClient/DownloadFile.swift

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -33,10 +33,13 @@ public struct DownloadFile: Sendable {
3333

3434
extension DownloadFile {
3535
public static func live(
36+
auth: Auth,
3637
keychain: Keychain,
3738
httpClient: HTTPClient
3839
) -> DownloadFile {
3940
DownloadFile { params in
41+
try await auth.refreshToken()
42+
4043
guard let credentials = await keychain.loadCredentials() else {
4144
throw Error.notAuthorized
4245
}

Sources/DropboxClient/ListFolder.swift

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -71,10 +71,13 @@ public struct ListFolder: Sendable {
7171

7272
extension ListFolder {
7373
public static func live(
74+
auth: Auth,
7475
keychain: Keychain,
7576
httpClient: HTTPClient
7677
) -> ListFolder {
7778
ListFolder { params in
79+
try await auth.refreshToken()
80+
7881
guard let credentials = await keychain.loadCredentials() else {
7982
throw Error.notAuthorized
8083
}

Sources/DropboxClient/UploadFile.swift

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -58,10 +58,13 @@ public struct UploadFile: Sendable {
5858

5959
extension UploadFile {
6060
public static func live(
61+
auth: Auth,
6162
keychain: Keychain,
6263
httpClient: HTTPClient
6364
) -> UploadFile {
6465
UploadFile { params in
66+
try await auth.refreshToken()
67+
6568
guard let credentials = await keychain.loadCredentials() else {
6669
throw Error.notAuthorized
6770
}

Tests/DropboxClientTests/DeleteFileTests.swift

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,8 +5,16 @@ final class DeleteFileTests: XCTestCase {
55
func testDeleteFile() async throws {
66
let params = DeleteFile.Params(path: "/Prime_Numbers.txt")
77
let credentials = Credentials.test
8+
let didRefreshToken = ActorIsolated(0)
89
let httpRequests = ActorIsolated<[URLRequest]>([])
910
let deleteFile = DeleteFile.live(
11+
auth: {
12+
var auth = Auth.unimplemented()
13+
auth.refreshToken = {
14+
await didRefreshToken.withValue { $0 += 1 }
15+
}
16+
return auth
17+
}(),
1018
keychain: {
1119
var keychain = Keychain.unimplemented()
1220
keychain.loadCredentials = { credentials }
@@ -41,6 +49,9 @@ final class DeleteFileTests: XCTestCase {
4149

4250
let result = try await deleteFile(params)
4351

52+
await didRefreshToken.withValue {
53+
XCTAssertEqual($0, 1)
54+
}
4455
try await httpRequests.withValue {
4556
let url = URL(string: "https://api.dropboxapi.com/2/files/delete_v2")!
4657
var expectedRequest = URLRequest(url: url)
@@ -80,6 +91,11 @@ final class DeleteFileTests: XCTestCase {
8091

8192
func testDeleteFileErrorResponse() async {
8293
let deleteFile = DeleteFile.live(
94+
auth: {
95+
var auth = Auth.unimplemented()
96+
auth.refreshToken = {}
97+
return auth
98+
}(),
8399
keychain: {
84100
var keychain = Keychain.unimplemented()
85101
keychain.loadCredentials = { .test }
@@ -115,6 +131,11 @@ final class DeleteFileTests: XCTestCase {
115131

116132
func testDeleteFileWhenNotAuthorized() async {
117133
let deleteFile = DeleteFile.live(
134+
auth: {
135+
var auth = Auth.unimplemented()
136+
auth.refreshToken = {}
137+
return auth
138+
}(),
118139
keychain: {
119140
var keychain = Keychain.unimplemented()
120141
keychain.loadCredentials = { nil }

Tests/DropboxClientTests/DownloadFileTests.swift

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,8 +4,16 @@ import XCTest
44
final class DownloadFileTests: XCTestCase {
55
func testDownloadFile() async throws {
66
let credentials = Credentials.test
7+
let didRefreshToken = ActorIsolated(0)
78
let httpRequests = ActorIsolated<[URLRequest]>([])
89
let downloadFile = DownloadFile.live(
10+
auth: {
11+
var auth = Auth.unimplemented()
12+
auth.refreshToken = {
13+
await didRefreshToken.withValue { $0 += 1 }
14+
}
15+
return auth
16+
}(),
917
keychain: {
1018
var keychain = Keychain.unimplemented()
1119
keychain.loadCredentials = { credentials }
@@ -28,6 +36,9 @@ final class DownloadFileTests: XCTestCase {
2836

2937
let result = try await downloadFile(params)
3038

39+
await didRefreshToken.withValue {
40+
XCTAssertEqual($0, 1)
41+
}
3142
await httpRequests.withValue {
3243
let expectedRequest: URLRequest = {
3344
let url = URL(string: "https://content.dropboxapi.com/2/files/download")!
@@ -51,6 +62,11 @@ final class DownloadFileTests: XCTestCase {
5162

5263
func testDownloadFileWhenNotAuthorized() async {
5364
let downloadFile = DownloadFile.live(
65+
auth: {
66+
var auth = Auth.unimplemented()
67+
auth.refreshToken = {}
68+
return auth
69+
}(),
5470
keychain: {
5571
var keychain = Keychain.unimplemented()
5672
keychain.loadCredentials = { nil }
@@ -72,6 +88,11 @@ final class DownloadFileTests: XCTestCase {
7288

7389
func testDownloadFileErrorResponse() async {
7490
let downloadFile = DownloadFile.live(
91+
auth: {
92+
var auth = Auth.unimplemented()
93+
auth.refreshToken = {}
94+
return auth
95+
}(),
7596
keychain: {
7697
var keychain = Keychain.unimplemented()
7798
keychain.loadCredentials = { .test }

Tests/DropboxClientTests/ListFolderTests.swift

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,8 +4,16 @@ import XCTest
44
final class ListFolderTests: XCTestCase {
55
func testListFolder() async throws {
66
let credentials = Credentials.test
7+
let didRefreshToken = ActorIsolated(0)
78
let httpRequests = ActorIsolated<[URLRequest]>([])
89
let listFolder = ListFolder.live(
10+
auth: {
11+
var auth = Auth.unimplemented()
12+
auth.refreshToken = {
13+
await didRefreshToken.withValue { $0 += 1 }
14+
}
15+
return auth
16+
}(),
917
keychain: {
1018
var keychain = Keychain.unimplemented()
1119
keychain.loadCredentials = { credentials }
@@ -51,6 +59,9 @@ final class ListFolderTests: XCTestCase {
5159

5260
let result = try await listFolder(params)
5361

62+
await didRefreshToken.withValue {
63+
XCTAssertEqual($0, 1)
64+
}
5465
await httpRequests.withValue {
5566
let expectedRequest: URLRequest = {
5667
let url = URL(string: "https://api.dropboxapi.com/2/files/list_folder")!
@@ -97,6 +108,11 @@ final class ListFolderTests: XCTestCase {
97108

98109
func testListFolderWhenNotAuthorized() async {
99110
let listFolder = ListFolder.live(
111+
auth: {
112+
var auth = Auth.unimplemented()
113+
auth.refreshToken = {}
114+
return auth
115+
}(),
100116
keychain: {
101117
var keychain = Keychain.unimplemented()
102118
keychain.loadCredentials = { nil }
@@ -118,6 +134,11 @@ final class ListFolderTests: XCTestCase {
118134

119135
func testListFolderErrorResponse() async {
120136
let listFolder = ListFolder.live(
137+
auth: {
138+
var auth = Auth.unimplemented()
139+
auth.refreshToken = {}
140+
return auth
141+
}(),
121142
keychain: {
122143
var keychain = Keychain.unimplemented()
123144
keychain.loadCredentials = { .test }

Tests/DropboxClientTests/TestHelpers.swift

Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -96,3 +96,35 @@ extension PKCEUtils {
9696
)
9797
}
9898
}
99+
100+
extension Auth {
101+
static func unimplemented(
102+
file: StaticString = #filePath,
103+
line: UInt = #line
104+
) -> Auth {
105+
Auth(
106+
isSignedIn: {
107+
XCTFail("Unimplemented: \(Self.self).isSignedIn", file: file, line: line)
108+
return false
109+
},
110+
isSignedInStream: {
111+
XCTFail("Unimplemented: \(Self.self).isSignedInStream", file: file, line: line)
112+
return AsyncStream { nil }
113+
},
114+
signIn: {
115+
XCTFail("Unimplemented: \(Self.self).signIn", file: file, line: line)
116+
},
117+
handleRedirect: { _ in
118+
XCTFail("Unimplemented: \(Self.self).handleRedirect", file: file, line: line)
119+
throw UnimplementedError()
120+
},
121+
refreshToken: {
122+
XCTFail("Unimplemented: \(Self.self).refreshToken", file: file, line: line)
123+
throw UnimplementedError()
124+
},
125+
signOut: {
126+
XCTFail("Unimplemented: \(Self.self).signOut", file: file, line: line)
127+
}
128+
)
129+
}
130+
}

Tests/DropboxClientTests/UploadFileTests.swift

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,8 +10,16 @@ final class UploadFileTests: XCTestCase {
1010
autorename: true
1111
)
1212
let credentials = Credentials.test
13+
let didRefreshToken = ActorIsolated(0)
1314
let httpRequests = ActorIsolated<[URLRequest]>([])
1415
let uploadFile = UploadFile.live(
16+
auth: {
17+
var auth = Auth.unimplemented()
18+
auth.refreshToken = {
19+
await didRefreshToken.withValue { $0 += 1 }
20+
}
21+
return auth
22+
}(),
1523
keychain: {
1624
var keychain = Keychain.unimplemented()
1725
keychain.loadCredentials = { credentials }
@@ -43,6 +51,9 @@ final class UploadFileTests: XCTestCase {
4351

4452
let result = try await uploadFile(params)
4553

54+
await didRefreshToken.withValue {
55+
XCTAssertEqual($0, 1)
56+
}
4657
try await httpRequests.withValue {
4758
let url = URL(string: "https://content.dropboxapi.com/2/files/upload")!
4859
var expectedRequest = URLRequest(url: url)
@@ -92,6 +103,11 @@ final class UploadFileTests: XCTestCase {
92103

93104
func testUploadFileErrorResponse() async {
94105
let uploadFile = UploadFile.live(
106+
auth: {
107+
var auth = Auth.unimplemented()
108+
auth.refreshToken = {}
109+
return auth
110+
}(),
95111
keychain: {
96112
var keychain = Keychain.unimplemented()
97113
keychain.loadCredentials = { .test }
@@ -127,6 +143,11 @@ final class UploadFileTests: XCTestCase {
127143

128144
func testUploadFileWhenNotAuthorized() async {
129145
let uploadFile = UploadFile.live(
146+
auth: {
147+
var auth = Auth.unimplemented()
148+
auth.refreshToken = {}
149+
return auth
150+
}(),
130151
keychain: {
131152
var keychain = Keychain.unimplemented()
132153
keychain.loadCredentials = { nil }

0 commit comments

Comments
 (0)