Skip to content

Commit 7e0385c

Browse files
committed
Polling Confirmations
Preliminary implementation of polling expectations Make Polling into a function along the lines of Confirmation Additionally, make PollingBehavior an implementation detail of polling, instead of exposed publicly Removes any timeouts involved for polling, as they become increasingly unreliable as the system runs more and more tests Take in configuration arguments, add polling interval Add traits for configuring polling Use consistent naming between confirmAlwaysPasses and the related configuration trait Stop unnecessarily waiting after the last polling attempt has finished. Allow for subsequent polling configuration traits which specified nil for a value to fall back to earlier polling configuration traits before falling back to the default. Add requirePassesEventually and requireAlwaysPasses These two mirror their confirm counterparts, only throwing an error (instead of recording an issue) when they fail. Rewrite confirmPassesEventually when returning an optional to remove the PollingRecorder actor. Now, this uses a separate method for evaluating polling to remove that actor. Clean up the duplicate Poller.evaluate/Poller.poll methods Removed the duplicate poll method, and made evaluate-returning-bool into a wrapper for evaluate-returning-optional Configure polling confirmations as timeout & polling interval This is less direct, but much more intuitive for test authors. Also add exit tests confirming that these values are non-negative Rename to actually use the confirmation name Follow more english-sentence-like guidance for function naming Simplify the polling confirmation API down to just 2 public functions, 1 enum, and 1 error type. Always throw an error when polling fails, get rid of the separate issue recording. Use a single polling confirmation configuration trait Instead of mulitple traits per stop condition, just have a single trait per stop condition.
1 parent e4e0b88 commit 7e0385c

File tree

5 files changed

+1091
-0
lines changed

5 files changed

+1091
-0
lines changed

Sources/Testing/Issues/Issue.swift

Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -38,6 +38,15 @@ public struct Issue: Sendable {
3838
/// confirmed too few or too many times.
3939
indirect case confirmationMiscounted(actual: Int, expected: any RangeExpression & Sendable)
4040

41+
/// An issue due to a polling confirmation having failed.
42+
///
43+
/// This issue can occur when calling ``confirmation(_:until:within:pollingEvery:isolation:sourceLocation:_:)-455gr``
44+
/// or
45+
/// ``confirmation(_:until:within:pollingEvery:isolation:sourceLocation:_:)-5tnlk``
46+
/// whenever the polling fails, as described in ``PollingStopCondition``.
47+
@_spi(Experimental)
48+
case pollingConfirmationFailed
49+
4150
/// An issue due to an `Error` being thrown by a test function and caught by
4251
/// the testing library.
4352
///
@@ -295,6 +304,8 @@ extension Issue.Kind: CustomStringConvertible {
295304
}
296305
}
297306
return "Confirmation was confirmed \(actual.counting("time")), but expected to be confirmed \(String(describingForTest: expected)) time(s)"
307+
case .pollingConfirmationFailed:
308+
return "Polling confirmation failed"
298309
case let .errorCaught(error):
299310
return "Caught error: \(error)"
300311
case let .timeLimitExceeded(timeLimitComponents: timeLimitComponents):
@@ -434,6 +445,15 @@ extension Issue.Kind {
434445
/// too few or too many times.
435446
indirect case confirmationMiscounted(actual: Int, expected: Int)
436447

448+
/// An issue due to a polling confirmation having failed.
449+
///
450+
/// This issue can occur when calling ``confirmation(_:until:within:pollingEvery:isolation:sourceLocation:_:)-455gr``
451+
/// or
452+
/// ``confirmation(_:until:within:pollingEvery:isolation:sourceLocation:_:)-5tnlk``
453+
/// whenever the polling fails, as described in ``PollingStopCondition``.
454+
@_spi(Experimental)
455+
case pollingConfirmationFailed
456+
437457
/// An issue due to an `Error` being thrown by a test function and caught by
438458
/// the testing library.
439459
///
@@ -477,6 +497,8 @@ extension Issue.Kind {
477497
.expectationFailed(Expectation.Snapshot(snapshotting: expectation))
478498
case .confirmationMiscounted:
479499
.unconditional
500+
case .pollingConfirmationFailed:
501+
.pollingConfirmationFailed
480502
case let .errorCaught(error), let .valueAttachmentFailed(error):
481503
.errorCaught(ErrorSnapshot(snapshotting: error))
482504
case let .timeLimitExceeded(timeLimitComponents: timeLimitComponents):
@@ -495,6 +517,7 @@ extension Issue.Kind {
495517
case unconditional
496518
case expectationFailed
497519
case confirmationMiscounted
520+
case pollingConfirmationFailed
498521
case errorCaught
499522
case timeLimitExceeded
500523
case knownIssueNotRecorded
@@ -567,6 +590,8 @@ extension Issue.Kind {
567590
forKey: .confirmationMiscounted)
568591
try confirmationMiscountedContainer.encode(actual, forKey: .actual)
569592
try confirmationMiscountedContainer.encode(expected, forKey: .expected)
593+
case .pollingConfirmationFailed:
594+
try container.encode(true, forKey: .pollingConfirmationFailed)
570595
case let .errorCaught(error):
571596
var errorCaughtContainer = container.nestedContainer(keyedBy: _CodingKeys._ErrorCaughtKeys.self, forKey: .errorCaught)
572597
try errorCaughtContainer.encode(error, forKey: .error)
@@ -622,6 +647,8 @@ extension Issue.Kind.Snapshot: CustomStringConvertible {
622647
}
623648
case let .confirmationMiscounted(actual: actual, expected: expected):
624649
"Confirmation was confirmed \(actual.counting("time")), but expected to be confirmed \(expected.counting("time"))"
650+
case .pollingConfirmationFailed:
651+
"Polling confirmation failed"
625652
case let .errorCaught(error):
626653
"Caught error: \(error)"
627654
case let .timeLimitExceeded(timeLimitComponents: timeLimitComponents):

0 commit comments

Comments
 (0)