diff --git a/ci/platform_boundary_research.tsv b/ci/platform_boundary_research.tsv index 37b4383e..bf666dc4 100644 --- a/ci/platform_boundary_research.tsv +++ b/ci/platform_boundary_research.tsv @@ -67,7 +67,7 @@ crates/fbuild-core/src/platform/windows/usb_pnp.rs 40 native_path windows_sys:: crates/fbuild-daemon/src/handlers/emulator/tests_npm_cache.rs 146 attr_cfg #[cfg(windows)] host_executable host_artifact_policy crates/fbuild-daemon/src/handlers/emulator/tests_process.rs 9 attr_cfg #[cfg(windows)] host_executable host_artifact_policy crates/fbuild-daemon/src/handlers/emulator/tests_process.rs 21 attr_cfg #[cfg(not(windows))] host_executable host_artifact_policy -crates/fbuild-paths/src/dev_daemon_namespace.rs 83 native_path std::env::current_exe host_executable host_mechanic +crates/fbuild-paths/src/dev_daemon_namespace.rs 91 native_path std::env::current_exe host_executable host_mechanic crates/fbuild-toolchain/src/toolchain/esp_qemu.rs 528 attr_cfg #[cfg(windows)] host_executable host_mechanic crates/fbuild-toolchain/src/toolchain/esp_qemu.rs 534 attr_cfg #[cfg(windows)] host_executable host_mechanic crates/fbuild-toolchain/src/toolchain/esp_qemu.rs 565 attr_cfg #[cfg(not(windows))] host_executable host_mechanic diff --git a/crates/fbuild-build-engine/tests/README.md b/crates/fbuild-build-engine/tests/README.md new file mode 100644 index 00000000..59510eeb --- /dev/null +++ b/crates/fbuild-build-engine/tests/README.md @@ -0,0 +1,12 @@ +# `fbuild-build-engine` integration tests + +Tests that need a separate final executable, or that exercise a contract +spanning this crate and one of its external dependencies. + +- **`dev_daemon_namespace_isolation.rs`** — proves the dev daemon-identity + stamp `fbuild-paths` exports actually changes the zccache IPC endpoint + (FastLED/fbuild#1285). It lives here because this is the crate that depends + on both sides: `fbuild-paths` produces the stamp but cannot see zccache, and + zccache consumes it but is a pinned external dependency. A repin that + dropped endpoint namespacing would otherwise pass every other test in the + tree while quietly restoring the `displace-stale` daemon war. diff --git a/crates/fbuild-build-engine/tests/dev_daemon_namespace_isolation.rs b/crates/fbuild-build-engine/tests/dev_daemon_namespace_isolation.rs new file mode 100644 index 00000000..449d573b --- /dev/null +++ b/crates/fbuild-build-engine/tests/dev_daemon_namespace_isolation.rs @@ -0,0 +1,68 @@ +//! The dev daemon-identity stamp actually isolates the compile daemon +//! (FastLED/fbuild#1285). +//! +//! `fbuild-paths` derives a per-checkout stamp and exports it as +//! `ZCCACHE_DAEMON_NAMESPACE`; zccache folds that value into the IPC endpoint +//! its daemons rendezvous on. Neither half can prove the other works — the +//! producer lives in a crate that does not depend on zccache, and the +//! consumer is a pinned external dependency — so the contract *between* them +//! was asserted only in prose, and the prose was wrong: both #1285's tracking +//! comment and `fbuild_paths::dev_daemon_namespace`'s module doc claimed the +//! export was inert until fbuild repinned zccache. It is not; it has been +//! live since the stamp landed. +//! +//! This test is the place that can tell. It lives in `fbuild-build-engine` +//! because that is the crate depending on both sides. A zccache repin that +//! silently dropped endpoint namespacing would take the `displace-stale` war +//! from zackees/soldr#2352 with it, and nothing else in the tree would +//! notice. + +use fbuild_paths::dev_daemon_namespace::ZCCACHE_DAEMON_NAMESPACE_ENV; + +/// One test, not three: the variable is process-global, so parallel cases +/// would race each other's `set_var`. +#[test] +fn the_exported_stamp_changes_the_zccache_daemon_endpoint() { + // SAFETY: this test binary contains one test, so no peer thread can + // observe the process-wide environment change. + unsafe { std::env::remove_var(ZCCACHE_DAEMON_NAMESPACE_ENV) }; + let bare = zccache::ipc::default_endpoint(); + + unsafe { std::env::set_var(ZCCACHE_DAEMON_NAMESPACE_ENV, "2.5.0-aaaaaaaaaaaaaaaa") }; + let first = zccache::ipc::default_endpoint(); + + unsafe { std::env::set_var(ZCCACHE_DAEMON_NAMESPACE_ENV, "2.5.0-bbbbbbbbbbbbbbbb") }; + let second = zccache::ipc::default_endpoint(); + + unsafe { std::env::remove_var(ZCCACHE_DAEMON_NAMESPACE_ENV) }; + let bare_again = zccache::ipc::default_endpoint(); + + // The property that matters: two checkouts with different stamps do not + // meet on one pipe. Without this, each displaces the other as + // "stale-version" on every invocation and the compile daemon wedges. + assert_ne!( + first, second, + "two stamps must rendezvous on two different endpoints" + ); + assert_ne!( + first, bare, + "a stamped endpoint must differ from the unstamped one" + ); + + // An unset stamp must keep the historical endpoint, or release builds + // would silently move off the daemon they share on upgrade — the + // single-daemon-on-upgrade semantics #1285 deliberately preserves for + // non-dev invocations. + assert_eq!( + bare, bare_again, + "clearing the stamp must restore the original endpoint exactly" + ); + + // The stamp is expected to appear in the endpoint rather than merely + // perturb a hash of it: an operator reading `\\.\pipe\...` or a socket + // path should be able to see which checkout owns the daemon. + assert!( + second.contains("bbbbbbbbbbbbbbbb"), + "the stamp should be legible in the endpoint, got {second}" + ); +} diff --git a/crates/fbuild-paths/src/dev_daemon_namespace.rs b/crates/fbuild-paths/src/dev_daemon_namespace.rs index 4fc60e01..932c7f73 100644 --- a/crates/fbuild-paths/src/dev_daemon_namespace.rs +++ b/crates/fbuild-paths/src/dev_daemon_namespace.rs @@ -8,10 +8,18 @@ //! invocation (the `displace-stale` war, root-caused in zackees/soldr#2352). //! //! The fix is a per-checkout namespace stamp exported as -//! `ZCCACHE_DAEMON_NAMESPACE` (the variable zccache honors once its own -//! adoption lands — zccache#1362; an inherited value always wins there, so -//! this export is inert, and harmless, until fbuild repins a zccache -//! release containing it): +//! `ZCCACHE_DAEMON_NAMESPACE`, which the pinned zccache folds into the IPC +//! endpoint its daemons rendezvous on — so two stamps mean two pipes, and +//! neither checkout can see the other as stale. +//! +//! This module previously claimed the export was "inert until fbuild repins +//! a zccache release containing it". That was wrong: endpoint namespacing is +//! already present at the pinned rev, and the isolation has worked since the +//! stamp landed. `crates/fbuild-build-engine/tests/ +//! dev_daemon_namespace_isolation.rs` pins the contract so a future repin +//! cannot drop it silently. What remains zccache-side (zccache#1362) is +//! zccache *deriving its own* stamp when nothing exported one — which fbuild +//! does not need, because fbuild exports one: //! //! ```text //! stamp = "-"