Skip to content

test(lsp): open test documents under the test's own temp directory - #1513

Merged
HuiJun merged 4 commits into
developfrom
fix/lsp-tests-temp-root
Oct 25, 2026
Merged

HuiJun merged 4 commits into
developfrom
fix/lsp-tests-temp-root

Conversation

@devin-ai-integration

@devin-ai-integration devin-ai-integration Bot commented Oct 25, 2026 •

Copy link
Copy Markdown
Contributor

What and why

A document opened under no workspace folder has its own directory indexed, so its sibling imports resolve (docs/guide/08-editors.md, "What the server indexes"). Several internal/frontend/lsp tests opened their document at /tmp/<name> through textDocument/didOpen, so the server scanned the system temp directory and indexed whatever model tree happened to sit there (DidOpen → indexOpenedDirectory → projectOrDir = filepath.Dir → scanFolder(/tmp, 2000 directories)). Others opened documents named relatively (e2e.sysml, kit.sysml, fleet.sysml), which uri.File resolved into the package directory, or under directories that do not exist (/w/, /ws/). None of those tests set rootUri or workspaceFolders; the server's root discovery (project.EnclosingProjects) never walked up to /tmp — it adopted the file's own directory, as documented. The tests, not the server, pointed it at a shared directory.

With a copy of eight examples/ trees under /tmp (2,920 .sysml/.kerml files in 985 directories) on develop at 111a59a, go test -count=1 -v ./internal/frontend/lsp/... went from ok 12.3s (497 passing) to FAIL 343.9s: seven wire tests timed out at their 30 s pipe deadline while the server walked /tmp (TestWireDidChangeOmittedRangeReplacesDocument, …ZeroRangeInsertsAtStart, …NullRangeReplacesDocument, …MixedBatchAppliesInOrder, …RepublishesDiagnosticsOnBothPaths, TestRunServesSignatureHelpCodeLensAndInlayHints, TestRunServesEveryRequestOverOneStream), and ten more passed late (TestRunServesLibraryDocumentsOverStream 0.00 s → 32.6 s, TestWireRangeFormattingAnswersEditsOnSelectedLines → 29.8 s, TestRunServesSemanticTokensAndCodeAction → 7.0 s, the six sync_test.go TestDidOpen*/TestDidChange* tests → 3.3–4.0 s each).

What changed, all under internal/frontend/lsp:

  • tempdoc_test.go: tempDocURI(t, name) places a document in a directory from t.TempDir(); testDocURI(t, name) keeps an absolute name as given (the collapsed-ports fixture pins /collapsed-ports.sysml so its origins do not depend on the checkout, and a path at the filesystem root is never indexed) and places a bare one the same way. requireTestOwnedDir fails a test about to open a document in the working directory (where a bare name lands) or in os.TempDir(); openDoc and testDocURI call it, so every document opened through a helper is in a directory the test owns.
  • newWireSession opens wire.sysml in its own directory (wireSession.uri replaces the file:///tmp/wire.sysml constant); sync_test.go, run_test.go, protocol_features_test.go, protocol_editor_facts_test.go, stdlib_test.go (the stream test), integration_test.go, modeledit_test.go, modeledit_cross_document_test.go, render_filter_test.go and the renderServer/debugServer helpers open their documents through the helpers. debug_test.go call sites drop the /w/ prefix; the duplicate-declaration test opens both documents in one directory and asserts on the paths it opened.
  • opened_directory_test.go: TestOpenedDocumentIndexesOnlyItsOwnDirectory opens a document in a subdirectory next to a model file in the parent and checks the sibling is indexed, the parent's file is not, and openDirs holds only the document's directory. TestOpenHelpersStayUnderTheTestRoot writes a stray model file into os.TempDir(), drives every helper (wireSession.open, openDoc, renderServer, debugServer, DidOpen) and fails if the stray file is indexed or any indexed directory lies outside the test's root. With the helpers pointed back at os.TempDir() this test fails (no publishDiagnostics for file:///tmp/wire.sysml within 30s).
  • modeledit_cross_document_test.go: the five documents it opened under bare names (parts.sysml, views.sysml, motor.sysml) go through tempDocURI. uri.File resolves a bare name with filepath.Abs, so those opens indexed the package directory internal/frontend/lsp (go test runs a package's tests in that directory): zero model files and no subdirectories, so nothing from outside the test was indexed and the scan cost one directory listing, but which directory depends on the working directory, so they are now rooted the same way as every other open. The remaining bare names are never opened: depot.sysml is set on disk through ws.SetOnDisk, missing.sysml, gone.sysml and elsewhere.sysml are requests about documents the server does not hold, and lifecycle_test.go's file:///tmp/dropped.sysml goes through lifecycleHandler wrapping a stub, so DidOpen never runs. Pointing one open back at a bare name, or renderServer at /tmp/collapsed-ports.sysml, fails at requireTestOwnedDir (opens in shared directory …; use tempDocURI).
  • The cross-document debug target test moves from debug_test.go to debug_cross_document_test.go, and tests/hygiene/size_test.go records debug_test.go at its smaller size (2127 lines).

No assertion changed. Test-only change: no changelog fragment.

Sibling suites checked with the same tree under /tmp: internal/frontend/repl, internal/frontend/grpc, tests/grpc and cmd/sysml-lsp all pass with and without it (50.5 s vs 31.8 s wall for the four together, CPU contention from the parallel packages; no per-test movement). None of them scans a directory from a request path; cmd/sysml-lsp opens file:///m.sysml, at the filesystem root, which indexOpenedDirectory never indexes, and its /tmp/after-shutdown.sysml is a hover after shutdown, never opened.

How it was verified

go test -count=1 ./internal/frontend/lsp/... on this branch, 499 tests:

/tmp contents before (develop) after
empty ok 12.3s (real 33 s with compile) ok 12.9s (real 13.6 s), 499 passing
2,920 model files in 985 directories FAIL 343.9s, 7 failures ok 12.7s (real 13.4 s), 499 passing, slowest test TestDebugActionFailure 5.2 s as without

Gates:

go build ./...                       OK
go vet ./...                         OK
gofmt -l .                           (empty)
make lint                            ✓ Lint passed
python3 scripts/changelog.py check   OK
python3 scripts/check-doc-ids.py     No internal work-item labels in reader-facing documentation
go test ./internal/frontend/lsp/...  ok   14.246s
go test ./...                        all packages ok

Dry merges of this head: clean with origin/develop (111a59a) and with #1506 (fix/cache-key-build-identity, e956947).

Checklist

  • go test ./... and make lint pass locally (make test, the race suite, is the full CI tier)
  • Tests added or updated for the change
  • Documentation extended where it already covers the surface (no documented surface changes)
  • Changelog entry added as changes/unreleased/<slug>.<section>.md, not as an edit to CHANGELOG.md (test-only change, none needed)
  • baselines regenerated and make docs-counts run if a gate count moved (none moved)
  • No internal work-item labels (waves, slices, F4, K5) in the body, docs, or changelog

devin-ai-integration Bot and others added 2 commits October 25, 2026 11:40
A document opened under no workspace folder has its own directory indexed,
so the tests that opened documents at /tmp/<name> had the server scan the
system temp directory and whatever model tree happened to sit there, and
documents named relatively were placed in the package directory. Every
helper and test now opens its document in a directory of its own from
t.TempDir(); two tests pin that only the document's directory is indexed
and that the helpers stay under the test root.

Co-Authored-By: jason.han <hanhuijun@gmail.com>
debug_test.go is allowlisted at its size in tests/hygiene; the test that
debugs a behavior exposed from another document moves to
debug_cross_document_test.go and the allowlist records the smaller file.

Co-Authored-By: jason.han <hanhuijun@gmail.com>
@devin-ai-integration

Copy link
Copy Markdown
Contributor Author

I'll fix CI failures and address comments from users with write access. I'll skip comments containing "(aside)".

  • Disable automatic comment, CI, and merge conflict monitoring

@devin-ai-integration
devin-ai-integration Bot marked this pull request as ready for review October 25, 2026 12:16
devin-ai-integration[bot]

This comment was marked as resolved.

Co-Authored-By: jason.han <hanhuijun@gmail.com>
@devin-ai-integration

Copy link
Copy Markdown
Contributor Author

fd2159b shortens the doc comments on tempDocURI and TestOpenHelpersStayUnderTheTestRoot to two lines each, as the review asked; no code changes. Gates re-run on this head: go build ./..., go vet ./..., gofmt -l . (empty), make lint, python3 scripts/changelog.py check, python3 scripts/check-doc-ids.py, go test ./internal/frontend/lsp/... (ok, 12.5 s) and go test ./... all pass.

…wn directory

Co-Authored-By: jason.han <hanhuijun@gmail.com>
@devin-ai-integration

Copy link
Copy Markdown
Contributor Author

4d8fdcf routes the five documents modeledit_cross_document_test.go opened under bare names (parts.sysml, views.sysml, motor.sysml) through tempDocURI, and adds requireTestOwnedDir, called by openDoc and by testDocURI for absolute names, which fails a test about to open a document in the working directory or in os.TempDir() — so the isolation now holds for every caller, not only the ones the guard test drives. A bare name resolved through filepath.Abs into the package directory, which holds no model files and no subdirectories, so those opens indexed nothing from outside the test; they are rooted the same way as the rest because the directory they scanned depended on the working directory. The other bare names in the package are never opened (depot.sysml is set on disk, missing.sysml/gone.sysml/elsewhere.sysml are requests about documents the server does not hold, and the lifecycle test's didOpen goes to a stub handler). Re-measured: ok 12.7s (499 passing) with 2,920 model files under /tmp, ok 12.9s without. Gates on this head: go build ./..., go vet ./..., gofmt -l . (empty), make lint, python3 scripts/changelog.py check, python3 scripts/check-doc-ids.py, go test ./internal/frontend/lsp/... and go test ./... all pass.

@HuiJun
HuiJun merged commit 1c8e9e9 into develop Oct 25, 2026
30 checks passed
@HuiJun
HuiJun deleted the fix/lsp-tests-temp-root branch October 25, 2026 16:54
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant