Skip to content

fix(path-cli): unify test env lock to stop cmd_pathbase racing the cache (red main)#113

Merged
akesling merged 1 commit into
mainfrom
fix/path-cli-test-env-lock-unification
Jun 29, 2026
Merged

fix(path-cli): unify test env lock to stop cmd_pathbase racing the cache (red main)#113
akesling merged 1 commit into
mainfrom
fix/path-cli-test-env-lock-unification

Conversation

@akesling

@akesling akesling commented Jun 29, 2026

Copy link
Copy Markdown
Contributor

Symptom

main is red. The CI run for the #112 merge (run 28177878573) failed one test:

cmd_resume::tests::resolve_input_url_uses_cache_on_hit_without_refetching
  panicked at crates/path-cli/src/cmd_resume.rs:873:
  download of alex/pathstash/fe94b6f9-... failed (500 Internal Server Error): boom

That test seeds the cache and points downloads at a 500 mock to prove resolve_input never hits the network on a cache hit. It reached the network — a cache miss.

Root cause — two locks, one global resource

The failure is a test-isolation race, not a #112 regression (#112 changed only production upload code; it surfaced a latent flake by chance — the parent run passed by luck, and the test passes in isolation).

The process environment was guarded by two independent mutexes:

  • cmd_pathbase's EnvGuard → a private ENV_LOCK
  • cmd_resume / cmd_cache / cmd_export / configconfig::TEST_ENV_LOCK

Both mutate/read TOOLPATH_CONFIG_DIR. Under parallel cargo test, an EnvGuard::set("TOOLPATH_CONFIG_DIR", dirB) can run while the cache-hit test holds TEST_ENV_LOCK with dirA, so config_dir() reads dirB → the seeded cache file isn't there → download → 500. (std::env::set_var/var_os are also not thread-safe, so concurrent access across the two locks is a data race on the environ regardless.) The EnvGuard SAFETY comment claiming "no other tests mutate or read TOOLPATH_CONFIG_DIR" was false.

Fix

EnvGuard now acquires the shared config::TEST_ENV_LOCK; the private ENV_LOCK is deleted. There is now exactly one env lock in the crate, so every env-touching test is mutually exclusive by construction. (The PATH/HOME resume guards already run only inside TEST_ENV_LOCK-holding tests, so they were never part of the race.)

Test-only change; no production code.

Verification

  • 14 full path-cli --lib runs green, including 6 at RUST_TEST_THREADS=32
  • cargo clippy -p path-cli --all-targets -- -D warnings clean
  • Couldn't reproduce the original failure locally (needs CI's parallelism); the fix is a structural single-lock guarantee rather than a timing tweak.

View with Codesmith Autofix with Codesmith
Need help on this PR? Tag /codesmith with what you need. Autofix is disabled.

…ache

`main` went red after #112 with a flaky failure in
`cmd_resume::tests::resolve_input_url_uses_cache_on_hit_without_refetching`
("download ... failed (500): boom") — the cache-hit test reached the
network despite a seeded cache.

Root cause: two independent mutexes guarded the *same* global resource,
the process environment. `cmd_pathbase`'s `EnvGuard` serialized via a
private `ENV_LOCK`, while `cmd_resume`/`cmd_cache`/`cmd_export`/`config`
use `config::TEST_ENV_LOCK`. Both touch `TOOLPATH_CONFIG_DIR`, so under
parallel `cargo test` an `EnvGuard::set("TOOLPATH_CONFIG_DIR", dirB)`
could run while the cache-hit test held `TEST_ENV_LOCK` with `dirA`,
making `config_dir()` read `dirB` → cache miss → download → 500.
(`std::env::set_var`/`var_os` are also not thread-safe, so concurrent
access across the two locks is a data race on the environ regardless.)
The `EnvGuard` SAFETY comment's claim that "no other tests mutate or
read TOOLPATH_CONFIG_DIR" was simply false. #112 only changed
production upload code; it surfaced a latent flake by chance.

Fix: `EnvGuard` now acquires the shared `config::TEST_ENV_LOCK` and the
private `ENV_LOCK` is deleted, leaving exactly one env lock in the crate
so all env-touching tests are mutually exclusive. (The PATH/HOME resume
guards already run only inside `TEST_ENV_LOCK`-holding tests.)

Test-only change. Verified: 14 full-suite runs (incl. 6 at 32 threads)
green; clippy clean.
@github-actions

Copy link
Copy Markdown

🔍 Preview deployed: https://b19868e7.toolpath.pages.dev

@akesling akesling merged commit 3909b3c into main Jun 29, 2026
2 checks passed
@akesling akesling deleted the fix/path-cli-test-env-lock-unification branch June 29, 2026 17:44
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