@@ -24,8 +24,59 @@ import XCTest
2424
2525// MARK: - CustomBuildServer
2626
27+ package actor CustomBuildServerInProgressRequestTracker {
28+ private var inProgressRequests : [ RequestID : Task < Void , Never > ] = [ : ]
29+ private let queue = AsyncQueue < Serial > ( )
30+
31+ package init ( ) { }
32+
33+ private func setInProgressRequestImpl( _ id: RequestID , task: Task < Void , Never > ) {
34+ guard inProgressRequests [ id] == nil else {
35+ logger. fault ( " Received duplicate request for id: \( id, privacy: . public) " )
36+ return
37+ }
38+ inProgressRequests [ id] = task
39+ }
40+
41+ fileprivate nonisolated func setInProgressRequest( _ id: RequestID , task: Task < Void , Never > ) {
42+ queue. async {
43+ await self . setInProgressRequestImpl ( id, task: task)
44+ }
45+ }
46+
47+ private func markTaskAsFinishedImpl( _ id: RequestID ) {
48+ guard inProgressRequests [ id] != nil else {
49+ logger. fault ( " Cannot mark request \( id, privacy: . public) as finished because it is not being tracked. " )
50+ return
51+ }
52+ inProgressRequests [ id] = nil
53+ }
54+
55+ fileprivate nonisolated func markTaskAsFinished( _ id: RequestID ) {
56+ queue. async {
57+ await self . markTaskAsFinishedImpl ( id)
58+ }
59+ }
60+
61+ private func cancelTaskImpl( _ id: RequestID ) {
62+ guard let task = inProgressRequests [ id] else {
63+ logger. fault ( " Cannot cancel task \( id, privacy: . public) because it isn't tracked " )
64+ return
65+ }
66+ task. cancel ( )
67+ }
68+
69+ fileprivate nonisolated func cancelTask( _ id: RequestID ) {
70+ queue. async {
71+ await self . cancelTaskImpl ( id)
72+ }
73+ }
74+ }
75+
2776/// A build server that can be injected into `CustomBuildServerTestProject`.
2877package protocol CustomBuildServer : MessageHandler {
78+ var inProgressRequestsTracker : CustomBuildServerInProgressRequestTracker { get }
79+
2980 init ( projectRoot: URL , connectionToSourceKitLSP: any Connection )
3081
3182 func initializeBuildRequest( _ request: InitializeBuildRequest ) async throws -> InitializeBuildResponse
@@ -74,13 +125,15 @@ extension CustomBuildServer {
74125 reply: @Sendable @escaping ( LSPResult < Request . Response > ) -> Void
75126 ) {
76127 func handle< R: RequestType > ( _ request: R , using handler: @Sendable @escaping ( R) async throws -> R . Response ) {
77- Task {
128+ let task = Task {
129+ defer { inProgressRequestsTracker. markTaskAsFinished ( id) }
78130 do {
79131 reply ( . success( try await handler ( request) as! Request . Response ) )
80132 } catch {
81133 reply ( . failure( ResponseError ( error) ) )
82134 }
83135 }
136+ inProgressRequestsTracker. setInProgressRequest ( id, task: task)
84137 }
85138
86139 switch request {
@@ -174,7 +227,9 @@ package extension CustomBuildServer {
174227 return VoidResponse ( )
175228 }
176229
177- nonisolated func cancelRequest( _ notification: CancelRequestNotification ) throws { }
230+ nonisolated func cancelRequest( _ notification: CancelRequestNotification ) throws {
231+ inProgressRequestsTracker. cancelTask ( notification. id)
232+ }
178233}
179234
180235// MARK: - CustomBuildServerTestProject
0 commit comments