@@ -89,19 +89,17 @@ class GitHubPackageMetadataProviderTests: XCTestCase {
89
89
func testRepoNotFound( ) throws {
90
90
let repoURL = " https://github.com/octocat/Hello-World.git "
91
91
92
- fixture ( name: " Collections " ) { _ in
93
- let handler = { ( _: HTTPClient . Request , callback: @escaping ( Result < HTTPClient . Response , Error > ) -> Void ) in
94
- callback ( . success( . init( statusCode: 404 ) ) )
95
- }
92
+ let handler = { ( _: HTTPClient . Request , callback: @escaping ( Result < HTTPClient . Response , Error > ) -> Void ) in
93
+ callback ( . success( . init( statusCode: 404 ) ) )
94
+ }
96
95
97
- var httpClient = HTTPClient ( handler: handler)
98
- httpClient. configuration. circuitBreakerStrategy = . none
99
- httpClient. configuration. retryStrategy = . none
100
- let provider = GitHubPackageMetadataProvider ( httpClient: httpClient)
101
- let reference = PackageReference ( repository: RepositorySpecifier ( url: repoURL) )
102
- XCTAssertThrowsError ( try tsc_await { callback in provider. get ( reference, callback: callback) } , " should throw error " ) { error in
103
- XCTAssert ( error is NotFoundError , " \( error) " )
104
- }
96
+ var httpClient = HTTPClient ( handler: handler)
97
+ httpClient. configuration. circuitBreakerStrategy = . none
98
+ httpClient. configuration. retryStrategy = . none
99
+ let provider = GitHubPackageMetadataProvider ( httpClient: httpClient)
100
+ let reference = PackageReference ( repository: RepositorySpecifier ( url: repoURL) )
101
+ XCTAssertThrowsError ( try tsc_await { callback in provider. get ( reference, callback: callback) } , " should throw error " ) { error in
102
+ XCTAssert ( error is NotFoundError , " \( error) " )
105
103
}
106
104
}
107
105
@@ -110,11 +108,11 @@ class GitHubPackageMetadataProviderTests: XCTestCase {
110
108
let apiURL = URL ( string: " https://api.github.com/repos/octocat/Hello-World " ) !
111
109
112
110
fixture ( name: " Collections " ) { directoryPath in
111
+ let path = directoryPath. appending ( components: " GitHub " , " metadata.json " )
112
+ let data = try Data ( localFileSystem. readFileContents ( path) . contents)
113
113
let handler = { ( request: HTTPClient . Request , callback: @escaping ( Result < HTTPClient . Response , Error > ) -> Void ) in
114
114
switch ( request. method, request. url) {
115
115
case ( . get, apiURL) :
116
- let path = directoryPath. appending ( components: " GitHub " , " metadata.json " )
117
- let data = Data ( try ! localFileSystem. readFileContents ( path) . contents)
118
116
callback ( . success( . init( statusCode: 200 ,
119
117
headers: . init( [ . init( name: " Content-Length " , value: " \( data. count) " ) ] ) ,
120
118
body: data) ) )
@@ -138,6 +136,93 @@ class GitHubPackageMetadataProviderTests: XCTestCase {
138
136
}
139
137
}
140
138
139
+ func testPermissionDenied( ) throws {
140
+ let repoURL = " https://github.com/octocat/Hello-World.git "
141
+ let apiURL = URL ( string: " https://api.github.com/repos/octocat/Hello-World " ) !
142
+
143
+ let handler = { ( _: HTTPClient . Request , callback: @escaping ( Result < HTTPClient . Response , Error > ) -> Void ) in
144
+ callback ( . success( . init( statusCode: 401 ) ) )
145
+ }
146
+
147
+ var httpClient = HTTPClient ( handler: handler)
148
+ httpClient. configuration. circuitBreakerStrategy = . none
149
+ httpClient. configuration. retryStrategy = . none
150
+ let provider = GitHubPackageMetadataProvider ( httpClient: httpClient)
151
+ let reference = PackageReference ( repository: RepositorySpecifier ( url: repoURL) )
152
+ XCTAssertThrowsError ( try tsc_await { callback in provider. get ( reference, callback: callback) } , " should throw error " ) { error in
153
+ XCTAssertEqual ( error as? GitHubPackageMetadataProvider . Errors , . permissionDenied( apiURL) )
154
+ }
155
+ }
156
+
157
+ func testInvalidAuthToken( ) throws {
158
+ let repoURL = " https://github.com/octocat/Hello-World.git "
159
+ let apiURL = URL ( string: " https://api.github.com/repos/octocat/Hello-World " ) !
160
+ let authTokens = [ AuthTokenType . github ( " api.github.com " ) : " foo " ]
161
+
162
+ let handler = { ( request: HTTPClient . Request , callback: @escaping ( Result < HTTPClient . Response , Error > ) -> Void ) in
163
+ if request. headers. get ( " Authorization " ) . first == " token \( authTokens. first!. value) " {
164
+ callback ( . success( . init( statusCode: 401 ) ) )
165
+ } else {
166
+ XCTFail ( " expected correct authorization header " )
167
+ callback ( . success( . init( statusCode: 500 ) ) )
168
+ }
169
+ }
170
+
171
+ var httpClient = HTTPClient ( handler: handler)
172
+ httpClient. configuration. circuitBreakerStrategy = . none
173
+ httpClient. configuration. retryStrategy = . none
174
+ var provider = GitHubPackageMetadataProvider ( httpClient: httpClient)
175
+ provider. configuration. authTokens = authTokens
176
+ let reference = PackageReference ( repository: RepositorySpecifier ( url: repoURL) )
177
+ XCTAssertThrowsError ( try tsc_await { callback in provider. get ( reference, callback: callback) } , " should throw error " ) { error in
178
+ XCTAssertEqual ( error as? GitHubPackageMetadataProvider . Errors , . invalidAuthToken( apiURL) )
179
+ }
180
+ }
181
+
182
+ func testAPILimit( ) throws {
183
+ let repoURL = " https://github.com/octocat/Hello-World.git "
184
+ let apiURL = URL ( string: " https://api.github.com/repos/octocat/Hello-World " ) !
185
+
186
+ let total = 5
187
+ var remaining = total
188
+
189
+ fixture ( name: " Collections " ) { directoryPath in
190
+ let path = directoryPath. appending ( components: " GitHub " , " metadata.json " )
191
+ let data = try Data ( localFileSystem. readFileContents ( path) . contents)
192
+ let handler = { ( request: HTTPClient . Request , callback: @escaping ( Result < HTTPClient . Response , Error > ) -> Void ) in
193
+ var headers = HTTPClientHeaders ( )
194
+ headers. add ( name: " X-RateLimit-Limit " , value: " \( total) " )
195
+ headers. add ( name: " X-RateLimit-Remaining " , value: " \( remaining) " )
196
+ if remaining == 0 {
197
+ callback ( . success( . init( statusCode: 403 , headers: headers) ) )
198
+ } else if request. url == apiURL {
199
+ remaining = remaining - 1
200
+ headers. add ( name: " Content-Length " , value: " \( data. count) " )
201
+ callback ( . success( . init( statusCode: 200 ,
202
+ headers: headers,
203
+ body: data) ) )
204
+ } else {
205
+ callback ( . success( . init( statusCode: 500 ) ) )
206
+ }
207
+ }
208
+
209
+ var httpClient = HTTPClient ( handler: handler)
210
+ httpClient. configuration. circuitBreakerStrategy = . none
211
+ httpClient. configuration. retryStrategy = . none
212
+ let provider = GitHubPackageMetadataProvider ( httpClient: httpClient)
213
+ let reference = PackageReference ( repository: RepositorySpecifier ( url: repoURL) )
214
+ for index in 0 ... total * 2 {
215
+ if index >= total {
216
+ XCTAssertThrowsError ( try tsc_await { callback in provider. get ( reference, callback: callback) } , " should throw error " ) { error in
217
+ XCTAssertEqual ( error as? GitHubPackageMetadataProvider . Errors , . apiLimitsExceeded( apiURL, total) )
218
+ }
219
+ } else {
220
+ XCTAssertNoThrow ( try tsc_await { callback in provider. get ( reference, callback: callback) } )
221
+ }
222
+ }
223
+ }
224
+ }
225
+
141
226
func testInvalidURL( ) throws {
142
227
fixture ( name: " Collections " ) { _ in
143
228
let provider = GitHubPackageMetadataProvider ( )
@@ -169,13 +254,21 @@ class GitHubPackageMetadataProviderTests: XCTestCase {
169
254
var httpClient = HTTPClient ( )
170
255
httpClient. configuration. circuitBreakerStrategy = . none
171
256
httpClient. configuration. retryStrategy = . none
172
- let provider = GitHubPackageMetadataProvider ( httpClient: httpClient)
257
+ httpClient. configuration. requestHeaders = . init( )
258
+ httpClient. configuration. requestHeaders!. add ( name: " Cache-Control " , value: " no-cache " )
259
+ var configuration = GitHubPackageMetadataProvider . Configuration ( )
260
+ if let token = ProcessEnv . vars [ " GITHUB_API_TOKEN " ] {
261
+ configuration. authTokens = [ . github( " api.github.com " ) : token]
262
+ }
263
+ configuration. apiLimitWarningThreshold = 50
264
+ let provider = GitHubPackageMetadataProvider ( configuration: configuration, httpClient: httpClient)
173
265
let reference = PackageReference ( repository: RepositorySpecifier ( url: repoURL) )
174
- let metadata = try tsc_await { callback in provider. get ( reference, callback: callback) }
175
-
176
- XCTAssertNotNil ( metadata)
177
- XCTAssert ( metadata. versions. count > 0 )
178
- XCTAssert ( metadata. keywords!. count > 0 )
179
- XCTAssert ( metadata. authors!. count > 0 )
266
+ for _ in 0 ... 60 {
267
+ let metadata = try tsc_await { callback in provider. get ( reference, callback: callback) }
268
+ XCTAssertNotNil ( metadata)
269
+ XCTAssert ( metadata. versions. count > 0 )
270
+ XCTAssert ( metadata. keywords!. count > 0 )
271
+ XCTAssert ( metadata. authors!. count > 0 )
272
+ }
180
273
}
181
274
}
0 commit comments