@@ -13,6 +13,7 @@ import Logging
13
13
import ServiceLifecycle
14
14
import Testing
15
15
@testable import WebPush
16
+ import WebPushTesting
16
17
17
18
@Suite ( " WebPush Manager " )
18
19
struct WebPushManagerTests {
@@ -41,6 +42,141 @@ struct WebPushManagerTests {
41
42
group. cancelAll ( )
42
43
}
43
44
}
45
+
46
+ @Test func managerCanCreateThreadPool( ) async throws {
47
+ let manager = WebPushManager ( vapidConfiguration: . makeTesting( ) , eventLoopGroupProvider: . createNew)
48
+ await withThrowingTaskGroup ( of: Void . self) { group in
49
+ group. addTask {
50
+ try await manager. run ( )
51
+ }
52
+ group. cancelAll ( )
53
+ }
54
+ }
55
+
56
+ @Test func managerCanBeMocked( ) async throws {
57
+ let manager = WebPushManager . makeMockedManager { _, _, _, _ in }
58
+ await withThrowingTaskGroup ( of: Void . self) { group in
59
+ group. addTask {
60
+ try await manager. run ( )
61
+ }
62
+ group. cancelAll ( )
63
+ }
64
+ }
65
+
66
+ /// Enable when https://github.com/swiftlang/swift-testing/blob/jgrynspan/exit-tests-proposal/Documentation/Proposals/NNNN-exit-tests.md gets accepted.
67
+ // @Test func managerCatchesIncorrectValidity() async throws {
68
+ // await #expect(exitsWith: .failure) {
69
+ // var configuration = VAPID.Configuration(key: .init(), contactInformation: .email("test@example.com"))
70
+ // configuration.validityDuration = .days(2)
71
+ // let _ = WebPushManager(vapidConfiguration: configuration)
72
+ // }
73
+ // }
74
+
75
+ @Test func managerConstructsAValidKeyLookup( ) async throws {
76
+ let configuration = try VAPID . Configuration ( primaryKey: . mockedKey1, keys: [ . mockedKey2] , deprecatedKeys: [ . mockedKey3] , contactInformation: . email( " test@example.com " ) )
77
+ let manager = WebPushManager ( vapidConfiguration: configuration)
78
+ #expect( await manager. vapidKeyLookup == [
79
+ . mockedKeyID1 : . mockedKey1,
80
+ . mockedKeyID2 : . mockedKey2,
81
+ . mockedKeyID3 : . mockedKey3,
82
+ ] )
83
+ await withThrowingTaskGroup ( of: Void . self) { group in
84
+ group. addTask {
85
+ try await manager. run ( )
86
+ }
87
+ group. cancelAll ( )
88
+ }
89
+ }
90
+
91
+ /// This is needed to cover the `uniquingKeysWith` safety call completely.
92
+ @Test func managerConstructsAValidKeyLookupFromQuestionableConfiguration( ) async throws {
93
+ var configuration = VAPID . Configuration. mocked
94
+ configuration. unsafeUpdateKeys ( primaryKey: . mockedKey1, keys: [ . mockedKey1] , deprecatedKeys: [ . mockedKey1] )
95
+ let manager = WebPushManager ( vapidConfiguration: configuration)
96
+ #expect( await manager. vapidKeyLookup == [ . mockedKeyID1 : . mockedKey1] )
97
+ await withThrowingTaskGroup ( of: Void . self) { group in
98
+ group. addTask {
99
+ try await manager. run ( )
100
+ }
101
+ group. cancelAll ( )
102
+ }
103
+ }
104
+ }
105
+
106
+ @Suite ( " VAPID Key Retrieval " ) struct VAPIDKeyRetrieval {
107
+ @Test func retrievesPrimaryKey( ) async {
108
+ let manager = WebPushManager ( vapidConfiguration: . mocked)
109
+ #expect( manager. nextVAPIDKeyID == . mockedKeyID1)
110
+ await withThrowingTaskGroup ( of: Void . self) { group in
111
+ group. addTask {
112
+ try await manager. run ( )
113
+ }
114
+ group. cancelAll ( )
115
+ }
116
+ }
117
+
118
+ @Test func alwaysRetrievesPrimaryKey( ) async throws {
119
+ var configuration = VAPID . Configuration. mocked
120
+ try configuration. updateKeys ( primaryKey: . mockedKey1, keys: [ . mockedKey2] , deprecatedKeys: [ . mockedKey3] )
121
+ let manager = WebPushManager ( vapidConfiguration: configuration)
122
+ for _ in 0 ..< 100_000 {
123
+ #expect( manager. nextVAPIDKeyID == . mockedKeyID1)
124
+ }
125
+ await withThrowingTaskGroup ( of: Void . self) { group in
126
+ group. addTask {
127
+ try await manager. run ( )
128
+ }
129
+ group. cancelAll ( )
130
+ }
131
+ }
132
+
133
+ @Test func retrievesFallbackKeys( ) async throws {
134
+ var configuration = VAPID . Configuration. mocked
135
+ try configuration. updateKeys ( primaryKey: nil , keys: [ . mockedKey1, . mockedKey2] )
136
+ let manager = WebPushManager ( vapidConfiguration: configuration)
137
+ var keyCounts : [ VAPID . Key . ID : Int ] = [ : ]
138
+ for _ in 0 ..< 100_000 {
139
+ keyCounts [ manager. nextVAPIDKeyID, default: 0 ] += 1
140
+ }
141
+ #expect( abs ( keyCounts [ . mockedKeyID1, default: 0 ] - keyCounts[ . mockedKeyID2, default: 0 ] ) < 1_000 ) /// If this test fails, increase this number accordingly
142
+ await withThrowingTaskGroup ( of: Void . self) { group in
143
+ group. addTask {
144
+ try await manager. run ( )
145
+ }
146
+ group. cancelAll ( )
147
+ }
148
+ }
149
+
150
+ @Test func neverRetrievesDeprecatedKeys( ) async throws {
151
+ var configuration = VAPID . Configuration. mocked
152
+ try configuration. updateKeys ( primaryKey: nil , keys: [ . mockedKey1, . mockedKey2] , deprecatedKeys: [ . mockedKey3] )
153
+ let manager = WebPushManager ( vapidConfiguration: configuration)
154
+ for _ in 0 ..< 100_000 {
155
+ #expect( manager. nextVAPIDKeyID != . mockedKeyID3)
156
+ }
157
+ await withThrowingTaskGroup ( of: Void . self) { group in
158
+ group. addTask {
159
+ try await manager. run ( )
160
+ }
161
+ group. cancelAll ( )
162
+ }
163
+ }
164
+
165
+ @Test func keyStatus( ) async throws {
166
+ var configuration = VAPID . Configuration. mocked
167
+ try configuration. updateKeys ( primaryKey: . mockedKey1, keys: [ . mockedKey2] , deprecatedKeys: [ . mockedKey3] )
168
+ let manager = WebPushManager ( vapidConfiguration: configuration)
169
+ #expect( manager. keyStatus ( for: . mockedKeyID1) == . valid)
170
+ #expect( manager. keyStatus ( for: . mockedKeyID2) == . valid)
171
+ #expect( manager. keyStatus ( for: . mockedKeyID3) == . deprecated)
172
+ #expect( manager. keyStatus ( for: . mockedKeyID4) == . unknown)
173
+ await withThrowingTaskGroup ( of: Void . self) { group in
174
+ group. addTask {
175
+ try await manager. run ( )
176
+ }
177
+ group. cancelAll ( )
178
+ }
179
+ }
44
180
}
45
181
46
182
@Suite ( " Sending Messages " )
0 commit comments