Skip to repository content391 lines · 11.9 KB · rust
tenant.openagents/omega
No repository description is available.
OpenAgents Git authority 2026-07-28T05:42:14.996Z Public web read
NIP-34 coordinate
30617:7649603503856e5148d571eac2766b288a8ff1e9e35d380337a1d2b0015b4f92:omegaMaintainersHidden in public view
References2 branches · 1 tag
Read-only clone
git clone https://openagents.com/git/tenant.openagents/omega.gitBrowse files
lsp_store.rs
1use std::{
2 path::Path,
3 sync::Arc,
4 time::{Duration, Instant},
5};
6
7use fs::FakeFs;
8use futures::StreamExt;
9use gpui::TestAppContext;
10use language::{CodeLabel, FakeLspAdapter, HighlightId, rust_lang};
11use lsp::Uri;
12use parking_lot::Mutex;
13use project::{
14 Project,
15 lsp_store::{log_store::TestRpcRequestTracker, *},
16};
17use serde_json::json;
18use util::path;
19
20use crate::init_test;
21
22#[gpui::test]
23async fn test_removing_invisible_worktree_cleans_reused_lsp_bookkeeping(cx: &mut TestAppContext) {
24 init_test(cx);
25 cx.executor().allow_parking();
26
27 let fs = FakeFs::new(cx.executor());
28 fs.insert_tree(path!("/the-root"), json!({ "main.rs": "fn main() {}" }))
29 .await;
30 fs.insert_tree(
31 path!("/the-registry"),
32 json!({ "dep": { "src": { "dep.rs": "pub fn dep() {}" } } }),
33 )
34 .await;
35
36 let project = Project::test(fs, [path!("/the-root").as_ref()], cx).await;
37 let language_registry = project.read_with(cx, |project, _| project.languages().clone());
38 language_registry.add(rust_lang());
39 let mut fake_servers = language_registry.register_fake_lsp("Rust", FakeLspAdapter::default());
40
41 let (_visible_buffer, _visible_handle) = project
42 .update(cx, |project, cx| {
43 project.open_local_buffer_with_lsp(path!("/the-root/main.rs"), cx)
44 })
45 .await
46 .unwrap();
47 fake_servers.next().await.unwrap();
48 cx.run_until_parked();
49
50 let server_id = project.read_with(cx, |project, cx| {
51 project
52 .lsp_store()
53 .read(cx)
54 .language_server_statuses()
55 .next()
56 .unwrap()
57 .0
58 });
59 let external_buffer = project
60 .update(cx, |project, cx| {
61 project.open_local_buffer_via_lsp(
62 Uri::from_file_path(path!("/the-registry/dep/src/dep.rs")).unwrap(),
63 server_id,
64 cx,
65 )
66 })
67 .await
68 .unwrap();
69 cx.run_until_parked();
70
71 let invisible_worktree_id =
72 external_buffer.read_with(cx, |buffer, cx| buffer.file().unwrap().worktree_id(cx));
73 project.read_with(cx, |project, cx| {
74 let worktree = project.worktree_for_id(invisible_worktree_id, cx).unwrap();
75 assert!(!worktree.read(cx).is_visible());
76 assert!(
77 project
78 .lsp_store()
79 .read(cx)
80 .has_language_server_seed_for_worktree(invisible_worktree_id)
81 );
82 });
83
84 project.update(cx, |project, cx| {
85 project.remove_worktree(invisible_worktree_id, cx);
86 });
87 cx.run_until_parked();
88
89 project.read_with(cx, |project, cx| {
90 let lsp_store = project.lsp_store();
91 let lsp_store = lsp_store.read(cx);
92 assert!(
93 lsp_store
94 .language_server_statuses()
95 .any(|(status_server_id, _)| status_server_id == server_id)
96 );
97 assert!(!lsp_store.has_language_server_seed_for_worktree(invisible_worktree_id));
98 });
99}
100
101#[test]
102fn test_rpc_request_tracker_distinguishes_request_directions() {
103 let mut tracker = TestRpcRequestTracker::new();
104 let started_at = Instant::now();
105
106 assert_eq!(
107 tracker.observe(
108 false,
109 r#"{"jsonrpc":"2.0","id":1,"method":"textDocument/hover"}"#,
110 started_at,
111 ),
112 None
113 );
114 assert_eq!(
115 tracker.observe(
116 true,
117 r#"{"jsonrpc":"2.0","id":1,"method":"workspace/configuration"}"#,
118 started_at + Duration::from_millis(10),
119 ),
120 None
121 );
122 assert_eq!(
123 tracker.observe(
124 false,
125 r#"{"jsonrpc":"2.0","id":1,"result":[]}"#,
126 started_at + Duration::from_millis(30),
127 ),
128 Some(Duration::from_millis(20))
129 );
130 assert_eq!(
131 tracker.observe(
132 true,
133 r#"{"jsonrpc":"2.0","id":1,"result":null}"#,
134 started_at + Duration::from_millis(50),
135 ),
136 Some(Duration::from_millis(50))
137 );
138}
139
140#[test]
141fn test_rpc_request_tracker_decodes_ids_and_times_cancelled_requests() {
142 let mut tracker = TestRpcRequestTracker::new();
143 let started_at = Instant::now();
144
145 tracker.observe(
146 true,
147 r#"{"jsonrpc":"2.0","id":"foo\u002fbar","method":"workspace/configuration"}"#,
148 started_at,
149 );
150 assert_eq!(
151 tracker.observe(
152 false,
153 r#"{"jsonrpc":"2.0","id":"foo/bar","result":[]}"#,
154 started_at + Duration::from_millis(25),
155 ),
156 Some(Duration::from_millis(25))
157 );
158
159 tracker.observe(
160 false,
161 r#"{"jsonrpc":"2.0","id":7,"method":"textDocument/hover"}"#,
162 started_at,
163 );
164 tracker.observe(
165 false,
166 r#"{"jsonrpc":"2.0","method":"$/cancelRequest","params":{"id":7}}"#,
167 started_at + Duration::from_millis(1),
168 );
169 assert_eq!(tracker.pending_request_count(), 1);
170 assert_eq!(
171 tracker.observe(
172 true,
173 r#"{"jsonrpc":"2.0","id":7,"error":{"code":-32800,"message":"Request was cancelled"}}"#,
174 started_at + Duration::from_millis(10),
175 ),
176 Some(Duration::from_millis(10))
177 );
178 assert_eq!(tracker.pending_request_count(), 0);
179}
180
181#[test]
182fn test_rpc_request_tracker_bounds_unanswered_requests() {
183 let mut tracker = TestRpcRequestTracker::new();
184 let started_at = Instant::now();
185 let max_pending_requests = TestRpcRequestTracker::max_pending_requests();
186
187 for id in 0..=max_pending_requests {
188 tracker.observe(
189 false,
190 &format!(r#"{{"jsonrpc":"2.0","id":{id},"method":"textDocument/hover"}}"#),
191 started_at + Duration::from_nanos(id as u64),
192 );
193 }
194
195 assert_eq!(tracker.pending_request_count(), max_pending_requests);
196 assert_eq!(
197 tracker.observe(
198 true,
199 r#"{"jsonrpc":"2.0","id":0,"result":null}"#,
200 started_at + Duration::from_secs(1),
201 ),
202 None
203 );
204 assert!(
205 tracker
206 .observe(
207 true,
208 r#"{"jsonrpc":"2.0","id":1,"result":null}"#,
209 started_at + Duration::from_secs(1),
210 )
211 .is_some()
212 );
213}
214
215#[test]
216fn test_rpc_log_duration_proto_roundtrip() {
217 let log_type = LanguageServerLogType::Rpc {
218 received: true,
219 elapsed: Some(Duration::from_micros(1234)),
220 };
221
222 assert_eq!(
223 LanguageServerLogType::from_proto(log_type.to_proto()),
224 log_type
225 );
226}
227
228#[test]
229fn test_glob_literal_prefix() {
230 assert_eq!(glob_literal_prefix(Path::new("**/*.js")), Path::new(""));
231 assert_eq!(
232 glob_literal_prefix(Path::new("node_modules/**/*.js")),
233 Path::new("node_modules")
234 );
235 assert_eq!(
236 glob_literal_prefix(Path::new("foo/{bar,baz}.js")),
237 Path::new("foo")
238 );
239 assert_eq!(
240 glob_literal_prefix(Path::new("foo/bar/baz.js")),
241 Path::new("foo/bar/baz.js")
242 );
243
244 #[cfg(target_os = "windows")]
245 {
246 assert_eq!(glob_literal_prefix(Path::new("**\\*.js")), Path::new(""));
247 assert_eq!(
248 glob_literal_prefix(Path::new("node_modules\\**/*.js")),
249 Path::new("node_modules")
250 );
251 assert_eq!(
252 glob_literal_prefix(Path::new("foo/{bar,baz}.js")),
253 Path::new("foo")
254 );
255 assert_eq!(
256 glob_literal_prefix(Path::new("foo\\bar\\baz.js")),
257 Path::new("foo/bar/baz.js")
258 );
259 }
260}
261
262#[test]
263fn test_multi_len_chars_normalization() {
264 let mut label = CodeLabel::new(
265 "myElˇ (parameter) myElˇ: {\n foo: string;\n}".to_string(),
266 0..6,
267 vec![(0..6, HighlightId::new(1))],
268 );
269 ensure_uniform_list_compatible_label(&mut label);
270 assert_eq!(
271 label,
272 CodeLabel::new(
273 "myElˇ (parameter) myElˇ: { foo: string; }".to_string(),
274 0..6,
275 vec![(0..6, HighlightId::new(1))],
276 )
277 );
278}
279
280#[test]
281fn test_trailing_newline_in_completion_documentation() {
282 let doc =
283 lsp::Documentation::String("Inappropriate argument value (of correct type).\n".to_string());
284 let completion_doc: CompletionDocumentation = doc.into();
285 assert!(
286 matches!(completion_doc, CompletionDocumentation::SingleLine(s) if s == "Inappropriate argument value (of correct type).")
287 );
288
289 let doc = lsp::Documentation::String(" some value \n".to_string());
290 let completion_doc: CompletionDocumentation = doc.into();
291 assert!(matches!(
292 completion_doc,
293 CompletionDocumentation::SingleLine(s) if s == "some value"
294 ));
295}
296
297#[gpui::test]
298async fn test_user_initialization_options_override_adapter_arrays(cx: &mut TestAppContext) {
299 init_test(cx);
300
301 let user_settings = serde_json::json!({
302 "lsp": {
303 "the-fake-language-server": {
304 "initialization_options": {
305 "preview": {
306 "background": {
307 "enabled": true,
308 "args": ["--data-plane-host=127.0.0.1:23635", "--invert-colors=never"],
309 },
310 },
311 "plugins": ["user-plugin"],
312 "userOnly": ["user"],
313 },
314 },
315 },
316 });
317
318 let fs = FakeFs::new(cx.executor());
319 fs.insert_tree(
320 path!("/the-root"),
321 json!({
322 ".zed": {
323 "settings.json": user_settings.to_string(),
324 },
325 "main.rs": "fn main() {}",
326 }),
327 )
328 .await;
329
330 let project = Project::test(fs, [path!("/the-root").as_ref()], cx).await;
331 let language_registry = project.read_with(cx, |project, _| project.languages().clone());
332 language_registry.add(rust_lang());
333
334 let sent_initialization_options = Arc::new(Mutex::new(None));
335 let mut fake_servers = language_registry.register_fake_lsp(
336 "Rust",
337 FakeLspAdapter {
338 name: "the-fake-language-server",
339 initialization_options: Some(json!({
340 "preview": {
341 "background": {
342 "args": ["--data-plane-host=127.0.0.1:23635", "--invert-colors=never"],
343 "partialRendering": true,
344 },
345 },
346 "plugins": ["default-plugin", "user-plugin"],
347 "adapterOnly": [1, 2],
348 })),
349 initializer: Some(Box::new({
350 let sent_initialization_options = sent_initialization_options.clone();
351 move |fake_server| {
352 let sent_initialization_options = sent_initialization_options.clone();
353 fake_server.set_request_handler::<lsp::request::Initialize, _, _>(
354 move |params, _| {
355 *sent_initialization_options.lock() = params.initialization_options;
356 async move { Ok(lsp::InitializeResult::default()) }
357 },
358 );
359 }
360 })),
361 ..FakeLspAdapter::default()
362 },
363 );
364 cx.run_until_parked();
365
366 project
367 .update(cx, |project, cx| {
368 project.open_local_buffer_with_lsp(path!("/the-root/main.rs"), cx)
369 })
370 .await
371 .unwrap();
372 fake_servers.next().await.unwrap();
373 cx.run_until_parked();
374
375 assert_eq!(
376 sent_initialization_options.lock().take(),
377 Some(json!({
378 "preview": {
379 "background": {
380 "enabled": true,
381 "args": ["--data-plane-host=127.0.0.1:23635", "--invert-colors=never"],
382 "partialRendering": true,
383 },
384 },
385 "plugins": ["user-plugin"],
386 "adapterOnly": [1, 2],
387 "userOnly": ["user"],
388 })),
389 );
390}
391