Skip to content

Commit 3df2f2e

Browse files
committed
Move fetchHTTPStatusCode to HTTPClient
1 parent 2d216b4 commit 3df2f2e

File tree

5 files changed

+58
-62
lines changed

5 files changed

+58
-62
lines changed

Sources/App/Controllers/PackageController+routes.swift

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -407,10 +407,11 @@ extension PackageController {
407407
.query(on: db, owner: owner, repository: repository)
408408
self = .packageAvailable(model, schema)
409409
} catch let error as AbortError where error.status == .notFound {
410+
@Dependency(\.httpClient) var httpClient
410411
// When the package is not in the index, we check if it's available on GitHub.
411412
// We use try? to avoid raising internel server errors from exceptions raised
412413
// from this call.
413-
let status = try? await Current.fetchHTTPStatusCode("https://github.com/\(owner)/\(repository)")
414+
let status = try? await httpClient.fetchHTTPStatusCode("https://github.com/\(owner)/\(repository)")
414415
switch status {
415416
case .some(.notFound):
416417
// GitHub does not have the package

Sources/App/Core/AppEnvironment.swift

Lines changed: 0 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -23,7 +23,6 @@ import FoundationNetworking
2323

2424

2525
struct AppEnvironment: Sendable {
26-
var fetchHTTPStatusCode: @Sendable (_ url: String) async throws -> HTTPStatus
2726
var fetchLicense: @Sendable (_ client: Client, _ owner: String, _ repository: String) async -> Github.License?
2827
var fetchMetadata: @Sendable (_ client: Client, _ owner: String, _ repository: String) async throws(Github.Error) -> Github.Metadata
2928
var fetchReadme: @Sendable (_ client: Client, _ owner: String, _ repository: String) async -> Github.Readme?
@@ -84,7 +83,6 @@ extension AppEnvironment {
8483
nonisolated(unsafe) static var logger: Logger!
8584

8685
static let live = AppEnvironment(
87-
fetchHTTPStatusCode: { url in try await Networking.fetchHTTPStatusCode(url) },
8886
fetchLicense: { client, owner, repo in await Github.fetchLicense(client:client, owner: owner, repository: repo) },
8987
fetchMetadata: { client, owner, repo throws(Github.Error) in try await Github.fetchMetadata(client:client, owner: owner, repository: repo) },
9088
fetchReadme: { client, owner, repo in await Github.fetchReadme(client:client, owner: owner, repository: repo) },
@@ -152,24 +150,6 @@ extension AppEnvironment {
152150
}
153151

154152

155-
private enum Networking {
156-
static func fetchHTTPStatusCode(_ url: String) async throws -> HTTPStatus {
157-
var config = Vapor.HTTPClient.Configuration()
158-
// We're forcing HTTP/1 due to a bug in Github's HEAD request handling
159-
// https://github.com/SwiftPackageIndex/SwiftPackageIndex-Server/issues/1676
160-
config.httpVersion = .http1Only
161-
let client = Vapor.HTTPClient(eventLoopGroupProvider: .singleton, configuration: config)
162-
return try await run {
163-
var req = HTTPClientRequest(url: url)
164-
req.method = .HEAD
165-
return try await client.execute(req, timeout: .seconds(2)).status
166-
} defer: {
167-
try await client.shutdown()
168-
}
169-
}
170-
}
171-
172-
173153
struct FileManager: Sendable {
174154
var attributesOfItem: @Sendable (_ path: String) throws -> [FileAttributeKey : Any]
175155
var contentsOfDirectory: @Sendable (_ path: String) throws -> [String]

Sources/App/Core/Dependencies/HTTPClient.swift

Lines changed: 17 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@
1212
// See the License for the specific language governing permissions and
1313
// limitations under the License.
1414

15+
import AsyncHTTPClient
1516
import Dependencies
1617
import DependenciesMacros
1718
import Vapor
@@ -21,14 +22,29 @@ import Vapor
2122
struct HTTPClient {
2223
typealias Response = Vapor.HTTPClient.Response
2324

24-
var fetchDocumentation: @Sendable (_ url: URI) async throws -> Response
25+
var fetchDocumentation: @Sendable (_ url: URI) async throws -> Response = { _ in XCTFail("fetchDocumentation"); return .ok }
26+
var fetchHTTPStatusCode: @Sendable (_ url: String) async throws -> HTTPStatus = { _ in XCTFail("fetchHTTPStatusCode"); return .ok }
2527
}
2628

2729
extension HTTPClient: DependencyKey {
2830
static var liveValue: HTTPClient {
2931
.init(
3032
fetchDocumentation: { url in
3133
try await Vapor.HTTPClient.shared.get(url: url.string).get()
34+
},
35+
fetchHTTPStatusCode: { url in
36+
var config = Vapor.HTTPClient.Configuration()
37+
// We're forcing HTTP/1 due to a bug in Github's HEAD request handling
38+
// https://github.com/SwiftPackageIndex/SwiftPackageIndex-Server/issues/1676
39+
config.httpVersion = .http1Only
40+
let client = Vapor.HTTPClient(eventLoopGroupProvider: .singleton, configuration: config)
41+
return try await run {
42+
var req = HTTPClientRequest(url: url)
43+
req.method = .HEAD
44+
return try await client.execute(req, timeout: .seconds(2)).status
45+
} defer: {
46+
try await client.shutdown()
47+
}
3248
}
3349
)
3450
}

Tests/AppTests/Mocks/AppEnvironment+mock.swift

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -22,7 +22,6 @@ import Vapor
2222
extension AppEnvironment {
2323
static func mock(eventLoop: EventLoop) -> Self {
2424
.init(
25-
fetchHTTPStatusCode: { _ in .ok },
2625
fetchLicense: { _, _, _ in .init(htmlUrl: "https://github.com/foo/bar/blob/main/LICENSE") },
2726
fetchMetadata: { _, _, _ in .mock },
2827
fetchReadme: { _, _, _ in .init(html: "readme html", htmlUrl: "readme html url", imagesToCache: []) },

Tests/AppTests/PackageController+routesTests.swift

Lines changed: 39 additions & 39 deletions
Original file line numberDiff line numberDiff line change
@@ -44,9 +44,8 @@ class PackageController_routesTests: SnapshotTestCase {
4444
func test_show_checkingGitHubRepository_notFound() throws {
4545
try withDependencies {
4646
$0.environment.dbId = { nil }
47+
$0.httpClient.fetchHTTPStatusCode = { @Sendable _ in .notFound }
4748
} operation: {
48-
Current.fetchHTTPStatusCode = { _ in .notFound }
49-
5049
// MUT
5150
try app.test(.GET, "/unknown/package") {
5251
XCTAssertEqual($0.status, .notFound)
@@ -57,9 +56,8 @@ class PackageController_routesTests: SnapshotTestCase {
5756
func test_show_checkingGitHubRepository_found() throws {
5857
try withDependencies {
5958
$0.environment.dbId = { nil }
59+
$0.httpClient.fetchHTTPStatusCode = { @Sendable _ in .ok }
6060
} operation: {
61-
Current.fetchHTTPStatusCode = { _ in .ok }
62-
6361
// MUT
6462
try app.test(.GET, "/unknown/package") {
6563
XCTAssertEqual($0.status, .notFound)
@@ -72,9 +70,8 @@ class PackageController_routesTests: SnapshotTestCase {
7270
// fetchHTTPStatusCode fails
7371
try withDependencies {
7472
$0.environment.dbId = { nil }
73+
$0.httpClient.fetchHTTPStatusCode = { @Sendable _ in throw FetchError() }
7574
} operation: {
76-
Current.fetchHTTPStatusCode = { _ in throw FetchError() }
77-
7875
// MUT
7976
try app.test(.GET, "/unknown/package") {
8077
XCTAssertEqual($0.status, .notFound)
@@ -103,50 +100,53 @@ class PackageController_routesTests: SnapshotTestCase {
103100
}
104101

105102
func test_ShowModel_packageMissing() async throws {
106-
// setup
107-
Current.fetchHTTPStatusCode = { _ in .ok }
108-
109-
// MUT
110-
let model = try await PackageController.ShowModel(db: app.db, owner: "owner", repository: "package")
103+
try await withDependencies {
104+
$0.httpClient.fetchHTTPStatusCode = { @Sendable _ in .ok }
105+
} operation: {
106+
// MUT
107+
let model = try await PackageController.ShowModel(db: app.db, owner: "owner", repository: "package")
111108

112-
// validate
113-
switch model {
114-
case .packageAvailable, .packageDoesNotExist:
115-
XCTFail("expected package to be missing")
116-
case .packageMissing:
117-
break
109+
// validate
110+
switch model {
111+
case .packageAvailable, .packageDoesNotExist:
112+
XCTFail("expected package to be missing")
113+
case .packageMissing:
114+
break
115+
}
118116
}
119117
}
120118

121119
func test_ShowModel_packageDoesNotExist() async throws {
122-
// setup
123-
Current.fetchHTTPStatusCode = { _ in .notFound }
124-
125-
// MUT
126-
let model = try await PackageController.ShowModel(db: app.db, owner: "owner", repository: "package")
120+
try await withDependencies {
121+
$0.httpClient.fetchHTTPStatusCode = { @Sendable _ in .notFound }
122+
} operation: {
123+
// MUT
124+
let model = try await PackageController.ShowModel(db: app.db, owner: "owner", repository: "package")
127125

128-
// validate
129-
switch model {
130-
case .packageAvailable, .packageMissing:
131-
XCTFail("expected package not to exist")
132-
case .packageDoesNotExist:
133-
break
126+
// validate
127+
switch model {
128+
case .packageAvailable, .packageMissing:
129+
XCTFail("expected package not to exist")
130+
case .packageDoesNotExist:
131+
break
132+
}
134133
}
135134
}
136135

137136
func test_ShowModel_fetchHTTPStatusCode_error() async throws {
138-
// setup
139-
Current.fetchHTTPStatusCode = { _ in throw FetchError() }
140-
141-
// MUT
142-
let model = try await PackageController.ShowModel(db: app.db, owner: "owner", repository: "package")
137+
try await withDependencies {
138+
$0.httpClient.fetchHTTPStatusCode = { @Sendable _ in throw FetchError() }
139+
} operation: {
140+
// MUT
141+
let model = try await PackageController.ShowModel(db: app.db, owner: "owner", repository: "package")
143142

144-
// validate
145-
switch model {
146-
case .packageAvailable, .packageMissing:
147-
XCTFail("expected package not to exist")
148-
case .packageDoesNotExist:
149-
break
143+
// validate
144+
switch model {
145+
case .packageAvailable, .packageMissing:
146+
XCTFail("expected package not to exist")
147+
case .packageDoesNotExist:
148+
break
149+
}
150150
}
151151
}
152152

0 commit comments

Comments
 (0)