test: skip symlink tests instead of erroring when the platform can't create symlinks - #2648
Conversation
There was a problem hiding this comment.
Graphify reviewed this change.
Looks safe to merge — no coupling regressions and no blocking issues, checked against the code graph (not a self-assessment).
Graphify review — findings
This PR adds two new pytest fixtures to tests/conftest.py: a session-scoped _can_symlink that probes whether the machine can actually create symlinks, and a requires_symlinks fixture that skips a test when it can't. It then adds requires_symlinks as a parameter to the various existing tests across test_atomic_writes.py, test_detect.py, test_extract.py, and test_image_vision.py that create symlinks. The stated intent is to make symlink-dependent tests skip cleanly (e.g., on non-elevated Windows) rather than fail. The change is confined to test files and fixtures; no non-test code is touched.
No blocking issues surfaced.
Analysis details — impact, health, verification
Impact & health
Graphify review
Impact — 715 functions depend on the 715 functions this change touches.
Health — grade A; no new coupling hotspots.
Verification — 715 functions in the blast radius were not formally verified this run (proofs are advisory here).
Gate & verification
graphify gate
PASS — objectively clean (no health regressions, tests not run — proofs not run this pass (advisory)). Grounded, not self-assessed.
Advisory (not blocking):
- verification_scope: 715 function(s) in the blast radius were not formally verified this run
Fixes #2642.
The bug
Creating a symlink on Windows needs an elevated process or Developer Mode. Fifteen tests call
Path.symlink_to()/os.symlink()unguarded, so on a default Windows developer machine theyraise
OSError: [WinError 1314] A required privilege is not held by the clientand arereported as failures.
At 15 of 42 failures on a clean checkout, this was the single largest block of noise in the
suite — enough that a Windows run isn't usable as a signal.
Fix
The capability-probing fixture pair from the issue, in
tests/conftest.py: a session-scoped_can_symlinkprobe plus arequires_symlinksgate, taken as a parameter by the 15 tests.Probed rather than inferred from
sys.platform, as the issue specifies — an elevated shell orDeveloper Mode can create symlinks on Windows, and those runs must keep the coverage.
Results
The failure-set diff is exact: the 15 converted are precisely the reported ones, and zero new
failures.
Verifying the gate opens as well as closes
A guard that always skips would "fix" the count while silently deleting the coverage — the more
expensive failure of the two. Exercising the fixture functions directly:
Scope
There are 17 unguarded symlink call sites, not 15. The extra two are already
skipif-decoratedfor unrelated reasons and were left alone:
test_build_merge_hyperedges_and_prune.py::test_prune_matches_across_symlinked_roottest_watch.py::test_rebuild_code_incremental_rename_preserves_symlink_source_pathThree further tests (
test_cache.py, two intest_detect.py) already use the repo's existingtry/except +
pytest.skipidiom. Left as-is rather than churn working code, thoughrequires_symlinksis the better pattern for anyone touching them later.Design note
requires_symlinksis a parameter rather than a try/except wrapper around each call on purpose:the guard stays visible in the signature, and an
OSErrorraised by the code under teststays a real failure instead of being swallowed into a skip. The probe creates one file symlink
— Windows gates file and directory symlinks behind the same
SeCreateSymbolicLinkPrivilege, soa separate directory probe would add nothing.
Test infrastructure only; no product code touched. #2478 remains the tracker for the genuine
junction/symlink scan-root defect.