Skip to content

Commit 24c771d

Browse files
Added mockable HTTPClient for testing
1 parent ff59e9d commit 24c771d

File tree

4 files changed

+64
-2
lines changed

4 files changed

+64
-2
lines changed

Package.swift

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -34,7 +34,9 @@ let package = Package(
3434
]
3535
),
3636
.testTarget(name: "WebPushTests", dependencies: [
37+
.product(name: "AsyncHTTPClient", package: "async-http-client"),
3738
.product(name: "Logging", package: "swift-log"),
39+
.product(name: "NIOCore", package: "swift-nio"),
3840
.product(name: "ServiceLifecycle", package: "swift-service-lifecycle"),
3941
.target(name: "WebPush"),
4042
]),
Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
1+
//
2+
// HTTPClientProtocol.swift
3+
// swift-webpush
4+
//
5+
// Created by Dimitri Bouniol on 2024-12-11.
6+
// Copyright © 2024 Mochi Development, Inc. All rights reserved.
7+
//
8+
9+
import AsyncHTTPClient
10+
import Logging
11+
import NIOCore
12+
13+
protocol HTTPClientProtocol: Sendable {
14+
func execute(
15+
_ request: HTTPClientRequest,
16+
deadline: NIODeadline,
17+
logger: Logger?
18+
) async throws -> HTTPClientResponse
19+
20+
func syncShutdown() throws
21+
}
22+
23+
extension HTTPClient: HTTPClientProtocol {}

Sources/WebPush/WebPushManager.swift

Lines changed: 9 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -24,7 +24,7 @@ actor WebPushManager: Sendable {
2424
public static let maximumMessageSize = maximumEncryptedPayloadSize - 103
2525

2626
nonisolated let logger: Logger
27-
let httpClient: HTTPClient
27+
var httpClient: any HTTPClientProtocol
2828

2929
let vapidKeyLookup: [VAPID.Key.ID : VAPID.Key]
3030
var vapidAuthorizationCache: [String : (authorization: String, validUntil: Date)] = [:]
@@ -66,6 +66,13 @@ actor WebPushManager: Sendable {
6666
}
6767
}
6868

69+
/// Internal method to install a different HTTP Client for mocking.
70+
///
71+
/// Note that this must be called before ``run()`` is called or the client's syncShutdown won't be called.
72+
func installHTTPClient(_ httpClient: HTTPClientProtocol) {
73+
self.httpClient = httpClient
74+
}
75+
6976
/// Load an up-to-date Authorization header for the specified endpoint and signing key combo.
7077
/// - Parameters:
7178
/// - endpoint: The endpoint we'll be contacting to send push messages for a given subscriber.
@@ -255,7 +262,7 @@ extension WebPushManager: Service {
255262
logger.info("Starting up WebPushManager")
256263
try await withTaskCancellationOrGracefulShutdownHandler {
257264
try await gracefulShutdown()
258-
} onCancelOrGracefulShutdown: { [self] in
265+
} onCancelOrGracefulShutdown: { [logger, httpClient] in
259266
logger.info("Shutting down WebPushManager")
260267
do {
261268
try httpClient.syncShutdown()
Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,30 @@
1+
//
2+
// MockHTTPClient.swift
3+
// swift-webpush
4+
//
5+
// Created by Dimitri Bouniol on 2024-12-11.
6+
// Copyright © 2024 Mochi Development, Inc. All rights reserved.
7+
//
8+
9+
import AsyncHTTPClient
10+
import Logging
11+
import NIOCore
12+
@testable import WebPush
13+
14+
actor MockHTTPClient: HTTPClientProtocol {
15+
var processRequest: (HTTPClientRequest) async throws -> HTTPClientResponse
16+
17+
init(_ processRequest: @escaping (HTTPClientRequest) async throws -> HTTPClientResponse) {
18+
self.processRequest = processRequest
19+
}
20+
21+
func execute(
22+
_ request: HTTPClientRequest,
23+
deadline: NIODeadline,
24+
logger: Logger?
25+
) async throws -> HTTPClientResponse {
26+
try await processRequest(request)
27+
}
28+
29+
nonisolated func syncShutdown() throws {}
30+
}

0 commit comments

Comments
 (0)