Two LSP freshness bugs reported by @tobific (#108882, #108881): - `_current_diags_async()` keyed the client lookup by the enclosing workspace root while `_get_or_spawn()` stores single-root servers under `srv.resolve_root(...)` (a nested package.json project). The lookup returned [] for a live client with diagnostics, so the delta baseline was refreshed from nothing. Use the same resolved-root key. - `open_or_change()` published `_DocState.version` only after awaiting the didChange write. A versionless publishDiagnostics read during that await was credited with the OLD version and judged stale once the send resumed. Bump the version before the send; a failed send (swallowed by `_send_notification`) leaves a version nothing satisfies, i.e. "no verdict", which is the existing contract. The mock server gains a push-only `versionless` script so the race is reproducible without a real language server.
46 lines
1.8 KiB
Python
46 lines
1.8 KiB
Python
"""``_current_diags_async`` must find a single-root client under the root it was spawned with.
|
|
|
|
``_get_or_spawn`` keys single-root servers by ``srv.resolve_root(...)`` (a nested ``package.json``
|
|
project), but the current-diagnostics lookup keyed by the enclosing workspace root, so the delta
|
|
baseline was refreshed from ``[]`` while the live client held diagnostics.
|
|
"""
|
|
from __future__ import annotations
|
|
|
|
import dataclasses
|
|
import sys
|
|
from pathlib import Path
|
|
|
|
from agent.lsp import manager, servers
|
|
|
|
MOCK_SERVER = str(Path(__file__).parent / "_mock_lsp_server.py")
|
|
|
|
|
|
def test_nested_single_root_client_is_found_by_current_lookup(tmp_path, monkeypatch):
|
|
repo = tmp_path / "repo"
|
|
(repo / ".git").mkdir(parents=True)
|
|
nested = repo / "package"
|
|
nested.mkdir()
|
|
(nested / "package.json").write_text("{}", encoding="utf-8")
|
|
src = nested / "x.ts"
|
|
src.write_text("const x = 1;\n", encoding="utf-8")
|
|
monkeypatch.chdir(repo)
|
|
|
|
original = next(s for s in servers.SERVERS if s.server_id == "typescript")
|
|
assert original.resolve_root(str(src), str(repo)) == str(nested) and not original.multi_root
|
|
|
|
def spawn(root, ctx):
|
|
return servers.SpawnSpec(command=[sys.executable, MOCK_SERVER], workspace_root=root, cwd=root,
|
|
env={"MOCK_LSP_SCRIPT": "errors"}, initialization_options={})
|
|
|
|
mocked = dataclasses.replace(original, build_spawn=spawn)
|
|
monkeypatch.setattr(servers, "SERVERS", [mocked if s is original else s for s in servers.SERVERS])
|
|
|
|
svc = manager.LSPService(enabled=True, wait_mode="document", wait_timeout=5, install_strategy="manual")
|
|
try:
|
|
svc.snapshot_baseline(str(src))
|
|
live = svc.get_diagnostics_sync(str(src), delta=False)
|
|
assert live
|
|
assert svc._loop.run(svc._current_diags_async(str(src)), timeout=5) == live
|
|
finally:
|
|
svc.shutdown()
|