10
10
11
11
@available ( macOS 13 , iOS 17 , watchOS 9 , tvOS 17 , visionOS 1 , * )
12
12
internal let defaultPollingConfiguration = (
13
- maxPollingIterations : 1000 ,
13
+ pollingDuration : Duration . seconds ( 1 ) ,
14
14
pollingInterval: Duration . milliseconds ( 1 )
15
15
)
16
16
@@ -23,12 +23,14 @@ public struct PollingFailedError: Error, Equatable {}
23
23
/// - Parameters:
24
24
/// - comment: An optional comment to apply to any issues generated by this
25
25
/// function.
26
- /// - maxPollingIterations: The maximum amount of times to attempt polling.
26
+ /// - pollingDuration: The expected length of time to continue polling for.
27
+ /// This value may not correspond to the wall-clock time that polling lasts for, especially
28
+ /// on highly-loaded systems with a lot of tests running.
27
29
/// If nil, this uses whatever value is specified under the last
28
30
/// ``ConfirmPassesEventuallyConfigurationTrait`` added to the test or
29
31
/// suite.
30
32
/// If no ``ConfirmPassesEventuallyConfigurationTrait`` has been added, then
31
- /// polling will be attempted 1000 times before recording an issue.
33
+ /// polling will be attempted for about 1 second before recording an issue.
32
34
/// `maxPollingIterations` must be greater than 0.
33
35
/// - pollingInterval: The minimum amount of time to wait between polling
34
36
/// attempts.
@@ -50,18 +52,18 @@ public struct PollingFailedError: Error, Equatable {}
50
52
@available ( macOS 13 , iOS 17 , watchOS 9 , tvOS 17 , visionOS 1 , * )
51
53
public func confirmPassesEventually(
52
54
_ comment: Comment ? = nil ,
53
- maxPollingIterations : Int ? = nil ,
55
+ pollingDuration : Duration ? = nil ,
54
56
pollingInterval: Duration ? = nil ,
55
57
isolation: isolated ( any Actor ) ? = #isolation,
56
58
sourceLocation: SourceLocation = #_sourceLocation,
57
59
_ body: @escaping ( ) async throws -> Bool
58
60
) async {
59
61
let poller = Poller (
60
62
pollingBehavior: . passesOnce,
61
- pollingIterations : getValueFromPollingTrait (
62
- providedValue: maxPollingIterations ,
63
- default: defaultPollingConfiguration. maxPollingIterations ,
64
- \ConfirmPassesEventuallyConfigurationTrait . maxPollingIterations
63
+ pollingDuration : getValueFromPollingTrait (
64
+ providedValue: pollingDuration ,
65
+ default: defaultPollingConfiguration. pollingDuration ,
66
+ \ConfirmPassesEventuallyConfigurationTrait . pollingDuration
65
67
) ,
66
68
pollingInterval: getValueFromPollingTrait (
67
69
providedValue: pollingInterval,
@@ -85,12 +87,14 @@ public func confirmPassesEventually(
85
87
/// - Parameters:
86
88
/// - comment: An optional comment to apply to any issues generated by this
87
89
/// function.
88
- /// - maxPollingIterations: The maximum amount of times to attempt polling.
90
+ /// - pollingDuration: The expected length of time to continue polling for.
91
+ /// This value may not correspond to the wall-clock time that polling lasts for, especially
92
+ /// on highly-loaded systems with a lot of tests running.
89
93
/// If nil, this uses whatever value is specified under the last
90
94
/// ``ConfirmPassesEventuallyConfigurationTrait`` added to the test or
91
95
/// suite.
92
96
/// If no ``ConfirmPassesEventuallyConfigurationTrait`` has been added, then
93
- /// polling will be attempted 1000 times before recording an issue.
97
+ /// polling will be attempted for about 1 second before recording an issue.
94
98
/// `maxPollingIterations` must be greater than 0.
95
99
/// - pollingInterval: The minimum amount of time to wait between polling
96
100
/// attempts.
@@ -115,18 +119,18 @@ public func confirmPassesEventually(
115
119
@available ( macOS 13 , iOS 17 , watchOS 9 , tvOS 17 , visionOS 1 , * )
116
120
public func requirePassesEventually(
117
121
_ comment: Comment ? = nil ,
118
- maxPollingIterations : Int ? = nil ,
122
+ pollingDuration : Duration ? = nil ,
119
123
pollingInterval: Duration ? = nil ,
120
124
isolation: isolated ( any Actor ) ? = #isolation,
121
125
sourceLocation: SourceLocation = #_sourceLocation,
122
126
_ body: @escaping ( ) async throws -> Bool
123
127
) async throws {
124
128
let poller = Poller (
125
129
pollingBehavior: . passesOnce,
126
- pollingIterations : getValueFromPollingTrait (
127
- providedValue: maxPollingIterations ,
128
- default: defaultPollingConfiguration. maxPollingIterations ,
129
- \ConfirmPassesEventuallyConfigurationTrait . maxPollingIterations
130
+ pollingDuration : getValueFromPollingTrait (
131
+ providedValue: pollingDuration ,
132
+ default: defaultPollingConfiguration. pollingDuration ,
133
+ \ConfirmPassesEventuallyConfigurationTrait . pollingDuration
130
134
) ,
131
135
pollingInterval: getValueFromPollingTrait (
132
136
providedValue: pollingInterval,
@@ -153,12 +157,14 @@ public func requirePassesEventually(
153
157
/// - Parameters:
154
158
/// - comment: An optional comment to apply to any issues generated by this
155
159
/// function.
156
- /// - maxPollingIterations: The maximum amount of times to attempt polling.
160
+ /// - pollingDuration: The expected length of time to continue polling for.
161
+ /// This value may not correspond to the wall-clock time that polling lasts for, especially
162
+ /// on highly-loaded systems with a lot of tests running.
157
163
/// If nil, this uses whatever value is specified under the last
158
164
/// ``ConfirmPassesEventuallyConfigurationTrait`` added to the test or
159
165
/// suite.
160
166
/// If no ``ConfirmPassesEventuallyConfigurationTrait`` has been added, then
161
- /// polling will be attempted 1000 times before recording an issue.
167
+ /// polling will be attempted for about 1 second before recording an issue.
162
168
/// `maxPollingIterations` must be greater than 0.
163
169
/// - pollingInterval: The minimum amount of time to wait between polling
164
170
/// attempts.
@@ -186,18 +192,18 @@ public func requirePassesEventually(
186
192
@discardableResult
187
193
public func confirmPassesEventually< R> (
188
194
_ comment: Comment ? = nil ,
189
- maxPollingIterations : Int ? = nil ,
195
+ pollingDuration : Duration ? = nil ,
190
196
pollingInterval: Duration ? = nil ,
191
197
isolation: isolated ( any Actor ) ? = #isolation,
192
198
sourceLocation: SourceLocation = #_sourceLocation,
193
199
_ body: @escaping ( ) async throws -> sending R?
194
200
) async throws -> R {
195
201
let poller = Poller (
196
202
pollingBehavior: . passesOnce,
197
- pollingIterations : getValueFromPollingTrait (
198
- providedValue: maxPollingIterations ,
199
- default: defaultPollingConfiguration. maxPollingIterations ,
200
- \ConfirmPassesEventuallyConfigurationTrait . maxPollingIterations
203
+ pollingDuration : getValueFromPollingTrait (
204
+ providedValue: pollingDuration ,
205
+ default: defaultPollingConfiguration. pollingDuration ,
206
+ \ConfirmPassesEventuallyConfigurationTrait . pollingDuration
201
207
) ,
202
208
pollingInterval: getValueFromPollingTrait (
203
209
providedValue: pollingInterval,
@@ -226,11 +232,13 @@ public func confirmPassesEventually<R>(
226
232
/// - Parameters:
227
233
/// - comment: An optional comment to apply to any issues generated by this
228
234
/// function.
229
- /// - maxPollingIterations: The maximum amount of times to attempt polling.
235
+ /// - pollingDuration: The expected length of time to continue polling for.
236
+ /// This value may not correspond to the wall-clock time that polling lasts for, especially
237
+ /// on highly-loaded systems with a lot of tests running.
230
238
/// If nil, this uses whatever value is specified under the last
231
239
/// ``ConfirmAlwaysPassesConfigurationTrait`` added to the test or suite.
232
240
/// If no ``ConfirmAlwaysPassesConfigurationTrait`` has been added, then
233
- /// polling will be attempted 1000 times before recording an issue.
241
+ /// polling will be attempted for about 1 second before recording an issue.
234
242
/// `maxPollingIterations` must be greater than 0.
235
243
/// - pollingInterval: The minimum amount of time to wait between polling
236
244
/// attempts.
@@ -251,18 +259,18 @@ public func confirmPassesEventually<R>(
251
259
@available ( macOS 13 , iOS 17 , watchOS 9 , tvOS 17 , visionOS 1 , * )
252
260
public func confirmAlwaysPasses(
253
261
_ comment: Comment ? = nil ,
254
- maxPollingIterations : Int ? = nil ,
262
+ pollingDuration : Duration ? = nil ,
255
263
pollingInterval: Duration ? = nil ,
256
264
isolation: isolated ( any Actor ) ? = #isolation,
257
265
sourceLocation: SourceLocation = #_sourceLocation,
258
266
_ body: @escaping ( ) async throws -> Bool
259
267
) async {
260
268
let poller = Poller (
261
269
pollingBehavior: . passesAlways,
262
- pollingIterations : getValueFromPollingTrait (
263
- providedValue: maxPollingIterations ,
264
- default: defaultPollingConfiguration. maxPollingIterations ,
265
- \ConfirmAlwaysPassesConfigurationTrait . maxPollingIterations
270
+ pollingDuration : getValueFromPollingTrait (
271
+ providedValue: pollingDuration ,
272
+ default: defaultPollingConfiguration. pollingDuration ,
273
+ \ConfirmAlwaysPassesConfigurationTrait . pollingDuration
266
274
) ,
267
275
pollingInterval: getValueFromPollingTrait (
268
276
providedValue: pollingInterval,
@@ -286,11 +294,13 @@ public func confirmAlwaysPasses(
286
294
/// - Parameters:
287
295
/// - comment: An optional comment to apply to any issues generated by this
288
296
/// function.
289
- /// - maxPollingIterations: The maximum amount of times to attempt polling.
297
+ /// - pollingDuration: The expected length of time to continue polling for.
298
+ /// This value may not correspond to the wall-clock time that polling lasts for, especially
299
+ /// on highly-loaded systems with a lot of tests running.
290
300
/// If nil, this uses whatever value is specified under the last
291
301
/// ``ConfirmAlwaysPassesConfigurationTrait`` added to the test or suite.
292
302
/// If no ``ConfirmAlwaysPassesConfigurationTrait`` has been added, then
293
- /// polling will be attempted 1000 times before recording an issue.
303
+ /// polling will be attempted for about 1 second before recording an issue.
294
304
/// `maxPollingIterations` must be greater than 0.
295
305
/// - pollingInterval: The minimum amount of time to wait between polling
296
306
/// attempts.
@@ -314,18 +324,18 @@ public func confirmAlwaysPasses(
314
324
@available ( macOS 13 , iOS 17 , watchOS 9 , tvOS 17 , visionOS 1 , * )
315
325
public func requireAlwaysPasses(
316
326
_ comment: Comment ? = nil ,
317
- maxPollingIterations : Int ? = nil ,
327
+ pollingDuration : Duration ? = nil ,
318
328
pollingInterval: Duration ? = nil ,
319
329
isolation: isolated ( any Actor ) ? = #isolation,
320
330
sourceLocation: SourceLocation = #_sourceLocation,
321
331
_ body: @escaping ( ) async throws -> Bool
322
332
) async throws {
323
333
let poller = Poller (
324
334
pollingBehavior: . passesAlways,
325
- pollingIterations : getValueFromPollingTrait (
326
- providedValue: maxPollingIterations ,
327
- default: defaultPollingConfiguration. maxPollingIterations ,
328
- \ConfirmAlwaysPassesConfigurationTrait . maxPollingIterations
335
+ pollingDuration : getValueFromPollingTrait (
336
+ providedValue: pollingDuration ,
337
+ default: defaultPollingConfiguration. pollingDuration ,
338
+ \ConfirmAlwaysPassesConfigurationTrait . pollingDuration
329
339
) ,
330
340
pollingInterval: getValueFromPollingTrait (
331
341
providedValue: pollingInterval,
@@ -466,8 +476,8 @@ private struct Poller {
466
476
/// while the expression continues to pass)
467
477
let pollingBehavior : PollingBehavior
468
478
469
- // How many times to poll
470
- let pollingIterations : Int
479
+ // Approximately how long to poll for
480
+ let pollingDuration : Duration
471
481
// Minimum waiting period between polling
472
482
let pollingInterval : Duration
473
483
@@ -526,9 +536,16 @@ private struct Poller {
526
536
isolation: isolated ( any Actor ) ? ,
527
537
_ body: @escaping ( ) async -> sending R?
528
538
) async -> R ? {
529
- precondition ( pollingIterations > 0 )
539
+ precondition ( pollingDuration > Duration . zero )
530
540
precondition ( pollingInterval > Duration . zero)
541
+ precondition ( pollingDuration > pollingInterval)
542
+ let durationSeconds = Double ( pollingDuration. components. seconds) + Double( pollingDuration. components. attoseconds) * 1e-18
543
+ let intervalSeconds = Double ( pollingInterval. components. seconds) + Double( pollingInterval. components. attoseconds) * 1e-18
544
+
545
+ let pollingIterations = max ( Int ( durationSeconds / intervalSeconds) , 1 )
546
+
531
547
let ( result, value) = await poll (
548
+ pollingIterations: pollingIterations,
532
549
expression: body
533
550
)
534
551
if let issue = result. issue (
@@ -552,12 +569,14 @@ private struct Poller {
552
569
/// `.passesOnce`
553
570
///
554
571
/// - Parameters:
572
+ /// - pollingIterations: The maximum amount of times to continue polling.
555
573
/// - expression: An expression to continuously evaluate
556
574
/// - behavior: The polling behavior to use
557
575
/// - timeout: How long to poll for unitl the timeout triggers.
558
576
/// - Returns: The result of this polling and the most recent value if the
559
577
/// result is .finished, otherwise nil.
560
578
private func poll< R> (
579
+ pollingIterations: Int ,
561
580
isolation: isolated ( any Actor ) ? = #isolation,
562
581
expression: @escaping ( ) async -> sending R?
563
582
) async -> ( PollResult , R ? ) {
0 commit comments