Fix a race condition leading to out-of-order notifications in tests

`TestSourceKitLSPClient.handle` created a new `Task`. This means that we could swap the order of notifications received from SourceKit-LSP. In most cases this doesn’t matter but `BackgroundIndexingTests.testProduceIndexLogWithTaskID` checks that the notification to start a structured log is received before the first report, which might not be the case because of the `Task` here.

Change `PendingNotifications` to a class with a `ThreadSafeBox` to remove the need for a `Task`.

rdar://147814254
This commit is contained in:
Alex Hoppen
2025-03-27 15:14:28 -07:00
parent 374554bde7
commit a151ca413c

View File

@@ -52,16 +52,16 @@ fileprivate struct NotificationTimeoutError: Error, CustomStringConvertible {
/// We can't use an `AsyncStream` for this because an `AsyncStream` is cancelled if a task that calls
/// `AsyncStream.Iterator.next` is cancelled and we want to be able to wait for new notifications even if waiting for a
/// a previous notification timed out.
actor PendingNotifications {
private var values: [any NotificationType] = []
final class PendingNotifications: Sendable {
private let values = ThreadSafeBox<[any NotificationType]>(initialValue: [])
func add(_ value: any NotificationType) {
values.insert(value, at: 0)
nonisolated func add(_ value: any NotificationType) {
values.value.insert(value, at: 0)
}
func next(timeout: Duration, pollingInterval: Duration = .milliseconds(10)) async throws -> any NotificationType {
for _ in 0..<Int(timeout.seconds / pollingInterval.seconds) {
if let value = values.popLast() {
if let value = values.value.popLast() {
return value
}
try await Task.sleep(for: pollingInterval)
@@ -358,9 +358,7 @@ package final class TestSourceKitLSPClient: MessageHandler, Sendable {
/// - Important: Implementation detail of `TestSourceKitLSPServer`. Do not call from tests.
package func handle(_ notification: some NotificationType) {
Task {
await notifications.add(notification)
}
notifications.add(notification)
}
/// - Important: Implementation detail of `TestSourceKitLSPClient`. Do not call from tests.