@@ -24,8 +24,59 @@ import XCTest
24
24
25
25
// MARK: - CustomBuildServer
26
26
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
+
27
76
/// A build server that can be injected into `CustomBuildServerTestProject`.
28
77
package protocol CustomBuildServer : MessageHandler {
78
+ var inProgressRequestsTracker : CustomBuildServerInProgressRequestTracker { get }
79
+
29
80
init ( projectRoot: URL , connectionToSourceKitLSP: any Connection )
30
81
31
82
func initializeBuildRequest( _ request: InitializeBuildRequest ) async throws -> InitializeBuildResponse
@@ -74,13 +125,15 @@ extension CustomBuildServer {
74
125
reply: @Sendable @escaping ( LSPResult < Request . Response > ) -> Void
75
126
) {
76
127
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) }
78
130
do {
79
131
reply ( . success( try await handler ( request) as! Request . Response ) )
80
132
} catch {
81
133
reply ( . failure( ResponseError ( error) ) )
82
134
}
83
135
}
136
+ inProgressRequestsTracker. setInProgressRequest ( id, task: task)
84
137
}
85
138
86
139
switch request {
@@ -174,7 +227,9 @@ package extension CustomBuildServer {
174
227
return VoidResponse ( )
175
228
}
176
229
177
- nonisolated func cancelRequest( _ notification: CancelRequestNotification ) throws { }
230
+ nonisolated func cancelRequest( _ notification: CancelRequestNotification ) throws {
231
+ inProgressRequestsTracker. cancelTask ( notification. id)
232
+ }
178
233
}
179
234
180
235
// MARK: - CustomBuildServerTestProject
0 commit comments