Skip to content

Commit dff72f1

Browse files
committed
In withTaskPriorityChangedHandler execute the task that watches for priority changes with high priority
I saw a nondeterministic test failure of `AsyncUtilsTests.testWithTimeoutEscalatesPriority` and I believe this was the cause. Also refactor a few test helper functions on the way.
1 parent 62271b4 commit dff72f1

File tree

4 files changed

+22
-10
lines changed

4 files changed

+22
-10
lines changed

Sources/SKTestSupport/RepeatUntilExpectedResult.swift

Lines changed: 14 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -10,27 +10,34 @@
1010
//
1111
//===----------------------------------------------------------------------===//
1212

13-
#if compiler(>=6)
14-
package import XCTest
15-
#else
13+
import SKLogging
1614
import XCTest
17-
#endif
1815

1916
/// Runs the body repeatedly once per second until it returns `true`, giving up after `timeout`.
2017
///
2118
/// This is useful to test some request that requires global state to be updated but will eventually converge on the
2219
/// correct result.
20+
///
21+
/// `sleepInterval` is the duration to wait before re-executing the body.
2322
package func repeatUntilExpectedResult(
24-
timeout: TimeInterval = defaultTimeout,
23+
timeout: Duration = .seconds(defaultTimeout),
24+
sleepInterval: Duration = .seconds(1),
2525
_ body: () async throws -> Bool,
2626
file: StaticString = #filePath,
2727
line: UInt = #line
2828
) async throws {
29-
for _ in 0..<Int(timeout) {
29+
logger.info("x: \(Int(timeout.seconds / sleepInterval.seconds))")
30+
for _ in 0..<Int(timeout.seconds / sleepInterval.seconds) {
3031
if try await body() {
3132
return
3233
}
33-
try await Task.sleep(for: .seconds(1))
34+
try await Task.sleep(for: sleepInterval)
3435
}
3536
XCTFail("Failed to get expected result", file: file, line: line)
3637
}
38+
39+
fileprivate extension Duration {
40+
var seconds: Double {
41+
return Double(self.components.attoseconds) / 1_000_000_000_000_000_000 + Double(self.components.seconds)
42+
}
43+
}

Sources/SwiftExtensions/Task+WithPriorityChangedHandler.swift

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -24,7 +24,10 @@ package func withTaskPriorityChangedHandler<T: Sendable>(
2424
) async throws -> T {
2525
let lastPriority = ThreadSafeBox(initialValue: initialPriority)
2626
let result: T? = try await withThrowingTaskGroup(of: Optional<T>.self) { taskGroup in
27-
taskGroup.addTask {
27+
// Run the task priority watcher with high priority instead of inheriting the initial priority. Otherwise a
28+
// `.background` task might not get its priority elevated because the priority watching task also runs at
29+
// `.background` priority and might not actually get executed in time.
30+
taskGroup.addTask(priority: .high) {
2831
while true {
2932
if Task.isCancelled {
3033
break

Tests/BuildSystemIntegrationTests/BuildServerBuildSystemTests.swift

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -299,7 +299,7 @@ final class BuildServerBuildSystemTests: XCTestCase {
299299
XCTAssertEqual(diagnosticsBeforeCrash.fullReport?.items, [])
300300
try FileManager.default.removeItem(at: project.scratchDirectory.appendingPathComponent("should_crash"))
301301

302-
try await repeatUntilExpectedResult(timeout: 20) {
302+
try await repeatUntilExpectedResult(timeout: .seconds(20)) {
303303
let diagnostics = try await project.testClient.send(
304304
DocumentDiagnosticsRequest(textDocument: TextDocumentIdentifier(uri))
305305
)

Tests/SKSupportTests/AsyncUtilsTests.swift

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@
1010
//
1111
//===----------------------------------------------------------------------===//
1212

13+
import SKLogging
1314
import SKSupport
1415
import SKTestSupport
1516
import SwiftExtensions
@@ -46,7 +47,8 @@ final class AsyncUtilsTests: XCTestCase {
4647
// We don't actually hit the timeout. It's just a large value.
4748
try await withTimeout(.seconds(defaultTimeout * 2)) {
4849
expectation.fulfill()
49-
try await repeatUntilExpectedResult {
50+
try await repeatUntilExpectedResult(sleepInterval: .seconds(0.1)) {
51+
logger.debug("Current priority: \(Task.currentPriority.rawValue)")
5052
return Task.currentPriority > .background
5153
}
5254
}

0 commit comments

Comments
 (0)