mirror of
https://github.com/permissionlesstech/bitchat.git
synced 2026-07-27 11:45:21 +00:00
Raise two more starvation-prone test deadlines
Both surfaced on the CI runs for this PR and #1487, both in tests neither PR touches, both the same shape as the two already fixed here: a deadline sized for the work rather than for a runner executing many suites at once. VoiceNotePlaybackControllerTests waited 5s for a @MainActor Task that playback schedules for the session acquire and its failure path. When that Task is not scheduled in time the helper reports *two* failures — the wait, and the `!isPlaying` the un-run failure path has not reset yet — which reads like a playback bug rather than a starved scheduler. That is exactly what CI showed. GeoRelayDirectoryTests waited 10s for work the directory runs in Task.detached(priority: .utility); utility priority competes with every other suite. The retry-scheduling case timed out at exactly 10.06s with the retry never scheduled, reading like a missing retry rather than a starved background task. Raised to 30s each with the reasoning recorded at the helper. Both helpers return as soon as their condition holds, so nothing slows down when tests pass — only the genuine-failure case takes longer to report. Verified 3x with all cores saturated: both suites clean. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This commit is contained in:
@@ -580,8 +580,16 @@ final class GeoRelayDirectoryTests: XCTestCase {
|
||||
/// constrained CI runners (2-core, serialized testing) can starve the
|
||||
/// detached utility-priority fetch task for seconds before it runs, and
|
||||
/// a successful wait returns as soon as the condition becomes true.
|
||||
/// Default deliberately far larger than the work being awaited.
|
||||
///
|
||||
/// The directory performs its fetch in a `Task.detached(priority: .utility)`,
|
||||
/// and utility priority competes with every other suite on a CI runner. At
|
||||
/// ten seconds the retry-scheduling test timed out at exactly 10.06s with
|
||||
/// the retry never scheduled — which reads like a missing retry rather than
|
||||
/// a starved background task. Returning as soon as the condition holds means
|
||||
/// a longer deadline only extends the genuine-failure case.
|
||||
private func waitUntil(
|
||||
timeout: TimeInterval = 10.0,
|
||||
timeout: TimeInterval = 30.0,
|
||||
condition: @escaping @MainActor () async -> Bool
|
||||
) async -> Bool {
|
||||
let deadline = Date().addingTimeInterval(timeout)
|
||||
|
||||
@@ -59,11 +59,24 @@ struct VoiceNotePlaybackControllerTests {
|
||||
return url
|
||||
}
|
||||
|
||||
/// Waits for an async settle, then asserts.
|
||||
///
|
||||
/// The deadline is deliberately far larger than the work it waits on. Every
|
||||
/// condition here depends on a `@MainActor` Task that playback schedules
|
||||
/// (the session acquire and its failure path), and on a CI runner executing
|
||||
/// many suites in parallel that Task can simply not be scheduled for
|
||||
/// seconds. At five seconds this timed out on CI and reported *two*
|
||||
/// failures — the wait itself, and the `!isPlaying` that the un-run failure
|
||||
/// path had not yet reset — which reads like a playback bug rather than a
|
||||
/// starved scheduler.
|
||||
///
|
||||
/// A generous deadline costs nothing when the condition holds, since this
|
||||
/// returns as soon as it does; it only extends the genuine-failure case.
|
||||
private func waitUntil(
|
||||
_ condition: () -> Bool,
|
||||
sourceLocation: SourceLocation = #_sourceLocation
|
||||
) async {
|
||||
let deadline = ContinuousClock.now.advanced(by: .seconds(5))
|
||||
let deadline = ContinuousClock.now.advanced(by: .seconds(30))
|
||||
while !condition(), ContinuousClock.now < deadline {
|
||||
await Task.yield()
|
||||
try? await Task.sleep(nanoseconds: 1_000_000)
|
||||
|
||||
Reference in New Issue
Block a user