Skip to content

Commit 35104f4

Browse files
Added support for rotating through multiple mocked message handlers
1 parent 575953c commit 35104f4

File tree

2 files changed

+67
-18
lines changed

2 files changed

+67
-18
lines changed

Sources/WebPushTesting/WebPushManager+Testing.swift

+46-7
Original file line numberDiff line numberDiff line change
@@ -8,12 +8,21 @@
88

99
import Logging
1010
import WebPush
11+
import Synchronization
1112

1213
extension WebPushManager {
1314
/// A push message in its original form, either ``/Foundation/Data``, ``/Swift/String``, or ``/Foundation/Encodable``.
1415
/// - Warning: Never switch on the message type, as values may be added to it over time.
1516
public typealias Message = _Message
1617

18+
public typealias MessageHandler = @Sendable (
19+
_ message: Message,
20+
_ subscriber: Subscriber,
21+
_ topic: Topic?,
22+
_ expiration: Expiration,
23+
_ urgency: Urgency
24+
) async throws -> Void
25+
1726
/// Create a mocked web push manager.
1827
///
1928
/// The mocked manager will forward all messages as is to its message handler so that you may either verify that a push was sent, or inspect the contents of the message that was sent.
@@ -27,13 +36,7 @@ extension WebPushManager {
2736
vapidConfiguration: VAPID.Configuration = .mockedConfiguration,
2837
// TODO: Add networkConfiguration for proxy, number of simultaneous pushes, etc…
2938
backgroundActivityLogger: Logger? = .defaultWebPushPrintLogger,
30-
messageHandler: @escaping @Sendable (
31-
_ message: Message,
32-
_ subscriber: Subscriber,
33-
_ topic: Topic?,
34-
_ expiration: Expiration,
35-
_ urgency: Urgency
36-
) async throws -> Void
39+
messageHandler: @escaping MessageHandler
3740
) -> WebPushManager {
3841
let backgroundActivityLogger = backgroundActivityLogger ?? .defaultWebPushNoOpLogger
3942

@@ -43,4 +46,40 @@ extension WebPushManager {
4346
executor: .handler(messageHandler)
4447
)
4548
}
49+
50+
/// Create a mocked web push manager.
51+
///
52+
/// The mocked manager will forward all messages as is to its message handlers so that you may either verify that a push was sent, or inspect the contents of the message that was sent. Assign multiple handlers here to have each message that comes in rotate through the handlers, looping when they are exausted.
53+
///
54+
/// - Parameters:
55+
/// - vapidConfiguration: A VAPID configuration, though the mocked manager doesn't make use of it.
56+
/// - logger: An optional logger.
57+
/// - messageHandlers: A list of handlers to receive messages or throw errors.
58+
/// - Returns: A new manager suitable for mocking.
59+
@available(macOS 15.0, iOS 18.0, watchOS 11.0, tvOS 18.0, visionOS 2.0, *)
60+
@_disfavoredOverload
61+
public static func makeMockedManager(
62+
vapidConfiguration: VAPID.Configuration = .mockedConfiguration,
63+
// TODO: Add networkConfiguration for proxy, number of simultaneous pushes, etc…
64+
backgroundActivityLogger: Logger? = .defaultWebPushPrintLogger,
65+
messageHandlers: @escaping MessageHandler,
66+
_ otherHandlers: MessageHandler...
67+
) -> WebPushManager {
68+
let backgroundActivityLogger = backgroundActivityLogger ?? .defaultWebPushNoOpLogger
69+
let index = Mutex(0)
70+
let allHandlers = [messageHandlers] + otherHandlers
71+
72+
return WebPushManager(
73+
vapidConfiguration: vapidConfiguration,
74+
backgroundActivityLogger: backgroundActivityLogger,
75+
executor: .handler({ message, subscriber, topic, expiration, urgency in
76+
let currentIndex = index.withLock { index in
77+
let current = index
78+
index = (index + 1) % allHandlers.count
79+
return current
80+
}
81+
return try await allHandlers[currentIndex](message, subscriber, topic, expiration, urgency)
82+
})
83+
)
84+
}
4685
}

Tests/WebPushTests/WebPushManagerTests.swift

+21-11
Original file line numberDiff line numberDiff line change
@@ -878,18 +878,28 @@ struct WebPushManagerTests {
878878
}
879879
}
880880

881+
@available(macOS 15.0, iOS 18.0, watchOS 11.0, tvOS 18.0, visionOS 2.0, *)
881882
@Test func sendPropagatedMockedFailure() async throws {
882-
await confirmation { requestWasMade in
883-
struct CustomError: Error {}
884-
885-
let manager = WebPushManager.makeMockedManager(backgroundActivityLogger: Logger(label: "WebPushManagerTests", factory: { PrintLogHandler(label: $0, metadataProvider: $1) })) { _, _, _, _, _ in
886-
requestWasMade()
887-
throw CustomError()
888-
}
889-
890-
await #expect(throws: CustomError.self) {
891-
try await manager.send(data: Array(repeating: 0, count: 3994), to: .mockedSubscriber())
892-
}
883+
struct CustomError: Error {}
884+
885+
let manager = WebPushManager.makeMockedManager(
886+
backgroundActivityLogger: nil,
887+
messageHandlers:
888+
{ _, _, _, _, _ in throw BadSubscriberError() },
889+
{ _, _, _, _, _ in throw CustomError() }
890+
)
891+
892+
await #expect(throws: BadSubscriberError.self) {
893+
try await manager.send(string: "test", to: .mockedSubscriber())
894+
}
895+
await #expect(throws: CustomError.self) {
896+
try await manager.send(string: "test", to: .mockedSubscriber())
897+
}
898+
await #expect(throws: BadSubscriberError.self) {
899+
try await manager.send(string: "test", to: .mockedSubscriber())
900+
}
901+
await #expect(throws: CustomError.self) {
902+
try await manager.send(string: "test", to: .mockedSubscriber())
893903
}
894904
}
895905
}

0 commit comments

Comments
 (0)