From b0a701910c4d9cd45cf8eb3f2510585b1984491f Mon Sep 17 00:00:00 2001 From: wan9chi Date: Sun, 21 Jun 2026 21:04:44 +0800 Subject: [PATCH] fix: ignore disableCache in client --- .../fixtures/ipc_client_test/snapshots.toml | 25 +++++++++------- ...=> disable_cache_noop_allows_cache_hit.md} | 24 ++++++++------- ...isable_cache_noop_with_explicit_inputs.md} | 23 +++++++++------ .../vite_dev_disable_cache/snapshots.toml | 11 ++++--- ...dev_disable_cache_noop_allows_cache_hit.md | 25 ++++++++++++++++ .../snapshots/vite_dev_disables_cache.md | 19 ------------ crates/vite_task_client/src/lib.rs | 17 +++++++++-- crates/vite_task_server/tests/integration.rs | 29 ++++++++++++++++++- 8 files changed, 116 insertions(+), 57 deletions(-) rename crates/vite_task_bin/tests/e2e_snapshots/fixtures/ipc_client_test/snapshots/{disable_cache_forces_reexecution.md => disable_cache_noop_allows_cache_hit.md} (58%) rename crates/vite_task_bin/tests/e2e_snapshots/fixtures/ipc_client_test/snapshots/{disable_cache_works_with_explicit_inputs.md => disable_cache_noop_with_explicit_inputs.md} (58%) create mode 100644 crates/vite_task_bin/tests/e2e_snapshots/fixtures/vite_dev_disable_cache/snapshots/vite_dev_disable_cache_noop_allows_cache_hit.md delete mode 100644 crates/vite_task_bin/tests/e2e_snapshots/fixtures/vite_dev_disable_cache/snapshots/vite_dev_disables_cache.md diff --git a/crates/vite_task_bin/tests/e2e_snapshots/fixtures/ipc_client_test/snapshots.toml b/crates/vite_task_bin/tests/e2e_snapshots/fixtures/ipc_client_test/snapshots.toml index 852b5ff4f..7d27979ac 100644 --- a/crates/vite_task_bin/tests/e2e_snapshots/fixtures/ipc_client_test/snapshots.toml +++ b/crates/vite_task_bin/tests/e2e_snapshots/fixtures/ipc_client_test/snapshots.toml @@ -225,10 +225,11 @@ steps = [ ] [[e2e]] -name = "disable_cache_forces_reexecution" +name = "disable_cache_noop_allows_cache_hit" comment = """ -Exercises `disableCache`. The tool asks the runner not to cache this run, -so the next invocation re-executes instead of hitting a prior entry. +Exercises the temporary `disableCache` no-op workaround. The tool asks the +runner not to cache this run, but the client ignores that request, so the next +invocation hits the cache. """ ignore = true steps = [ @@ -236,23 +237,25 @@ steps = [ "vt", "run", "disable-cache", - ], comment = "first run — tool calls disableCache" }, + ], comment = "first run — tool calls disableCache, currently ignored by the client" }, { argv = [ "vt", "run", "disable-cache", - ], comment = "cache miss (NotFound) because nothing was cached" }, + ], comment = "cache hit because disableCache is temporarily a no-op" }, { argv = [ "vt", "run", "--last-details", - ], comment = "summary names the opt-out as the not-cached reason" }, + ], comment = "summary reports the replayed cache hit" }, ] [[e2e]] -name = "disable_cache_works_with_explicit_inputs" +name = "disable_cache_noop_with_explicit_inputs" comment = """ -Exercises `disableCache` on a cached task with explicit inputs. The runner must still inject IPC even when fspy auto-input inference is disabled, or the tool's cache opt-out becomes a no-op and the second run incorrectly hits. +Exercises the temporary `disableCache` no-op workaround on a cached task with +explicit inputs. The client ignores the opt-out request, so the second run hits +even when fspy auto-input inference is disabled. """ ignore = true steps = [ @@ -260,17 +263,17 @@ steps = [ "vt", "run", "disable-cache-explicit-input", - ], comment = "first run uses input: [] and asks the runner not to cache" }, + ], comment = "first run uses input: [] and calls disableCache, currently ignored by the client" }, { argv = [ "vt", "run", "disable-cache-explicit-input", - ], comment = "re-executes because the first run was not cached" }, + ], comment = "cache hit because disableCache is temporarily a no-op" }, { argv = [ "vt", "run", "--last-details", - ], comment = "summary names the opt-out as the not-cached reason" }, + ], comment = "summary reports the replayed cache hit" }, ] [[e2e]] diff --git a/crates/vite_task_bin/tests/e2e_snapshots/fixtures/ipc_client_test/snapshots/disable_cache_forces_reexecution.md b/crates/vite_task_bin/tests/e2e_snapshots/fixtures/ipc_client_test/snapshots/disable_cache_noop_allows_cache_hit.md similarity index 58% rename from crates/vite_task_bin/tests/e2e_snapshots/fixtures/ipc_client_test/snapshots/disable_cache_forces_reexecution.md rename to crates/vite_task_bin/tests/e2e_snapshots/fixtures/ipc_client_test/snapshots/disable_cache_noop_allows_cache_hit.md index d2f107587..971a6ed09 100644 --- a/crates/vite_task_bin/tests/e2e_snapshots/fixtures/ipc_client_test/snapshots/disable_cache_forces_reexecution.md +++ b/crates/vite_task_bin/tests/e2e_snapshots/fixtures/ipc_client_test/snapshots/disable_cache_noop_allows_cache_hit.md @@ -1,11 +1,12 @@ -# disable_cache_forces_reexecution +# disable_cache_noop_allows_cache_hit -Exercises `disableCache`. The tool asks the runner not to cache this run, -so the next invocation re-executes instead of hitting a prior entry. +Exercises the temporary `disableCache` no-op workaround. The tool asks the +runner not to cache this run, but the client ignores that request, so the next +invocation hits the cache. ## `vt run disable-cache` -first run — tool calls disableCache +first run — tool calls disableCache, currently ignored by the client ``` $ node scripts/disable_cache.mjs @@ -13,15 +14,18 @@ $ node scripts/disable_cache.mjs ## `vt run disable-cache` -cache miss (NotFound) because nothing was cached +cache hit because disableCache is temporarily a no-op ``` -$ node scripts/disable_cache.mjs +$ node scripts/disable_cache.mjs ◉ cache hit, replaying + +--- +vt run: cache hit. ``` ## `vt run --last-details` -summary names the opt-out as the not-cached reason +summary reports the replayed cache hit ``` @@ -29,12 +33,12 @@ summary names the opt-out as the not-cached reason Vite+ Task Runner • Execution Summary ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ -Statistics: 1 tasks • 0 cache hits • 1 cache misses -Performance: 0% cache hit rate +Statistics: 1 tasks • 1 cache hits • 0 cache misses +Performance: 100% cache hit rate Task Details: ──────────────────────────────────────────────── [1] ipc-client-test#disable-cache: $ node scripts/disable_cache.mjs ✓ - → Not cached: the task opted out of caching + → Cache hit - output replayed - ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ ``` diff --git a/crates/vite_task_bin/tests/e2e_snapshots/fixtures/ipc_client_test/snapshots/disable_cache_works_with_explicit_inputs.md b/crates/vite_task_bin/tests/e2e_snapshots/fixtures/ipc_client_test/snapshots/disable_cache_noop_with_explicit_inputs.md similarity index 58% rename from crates/vite_task_bin/tests/e2e_snapshots/fixtures/ipc_client_test/snapshots/disable_cache_works_with_explicit_inputs.md rename to crates/vite_task_bin/tests/e2e_snapshots/fixtures/ipc_client_test/snapshots/disable_cache_noop_with_explicit_inputs.md index 96e623450..6afee61d5 100644 --- a/crates/vite_task_bin/tests/e2e_snapshots/fixtures/ipc_client_test/snapshots/disable_cache_works_with_explicit_inputs.md +++ b/crates/vite_task_bin/tests/e2e_snapshots/fixtures/ipc_client_test/snapshots/disable_cache_noop_with_explicit_inputs.md @@ -1,10 +1,12 @@ -# disable_cache_works_with_explicit_inputs +# disable_cache_noop_with_explicit_inputs -Exercises `disableCache` on a cached task with explicit inputs. The runner must still inject IPC even when fspy auto-input inference is disabled, or the tool's cache opt-out becomes a no-op and the second run incorrectly hits. +Exercises the temporary `disableCache` no-op workaround on a cached task with +explicit inputs. The client ignores the opt-out request, so the second run hits +even when fspy auto-input inference is disabled. ## `vt run disable-cache-explicit-input` -first run uses input: [] and asks the runner not to cache +first run uses input: [] and calls disableCache, currently ignored by the client ``` $ node scripts/disable_cache.mjs @@ -12,15 +14,18 @@ $ node scripts/disable_cache.mjs ## `vt run disable-cache-explicit-input` -re-executes because the first run was not cached +cache hit because disableCache is temporarily a no-op ``` -$ node scripts/disable_cache.mjs +$ node scripts/disable_cache.mjs ◉ cache hit, replaying + +--- +vt run: cache hit. ``` ## `vt run --last-details` -summary names the opt-out as the not-cached reason +summary reports the replayed cache hit ``` @@ -28,12 +33,12 @@ summary names the opt-out as the not-cached reason Vite+ Task Runner • Execution Summary ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ -Statistics: 1 tasks • 0 cache hits • 1 cache misses -Performance: 0% cache hit rate +Statistics: 1 tasks • 1 cache hits • 0 cache misses +Performance: 100% cache hit rate Task Details: ──────────────────────────────────────────────── [1] ipc-client-test#disable-cache-explicit-input: $ node scripts/disable_cache.mjs ✓ - → Not cached: the task opted out of caching + → Cache hit - output replayed - ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ ``` diff --git a/crates/vite_task_bin/tests/e2e_snapshots/fixtures/vite_dev_disable_cache/snapshots.toml b/crates/vite_task_bin/tests/e2e_snapshots/fixtures/vite_dev_disable_cache/snapshots.toml index efd50410e..5b79f9912 100644 --- a/crates/vite_task_bin/tests/e2e_snapshots/fixtures/vite_dev_disable_cache/snapshots.toml +++ b/crates/vite_task_bin/tests/e2e_snapshots/fixtures/vite_dev_disable_cache/snapshots.toml @@ -1,7 +1,10 @@ [[e2e]] -name = "vite_dev_disables_cache" +name = "vite_dev_disable_cache_noop_allows_cache_hit" comment = """ -`vt run --cache dev` brings up a Vite dev server programmatically on an ephemeral port and closes it immediately. Vite's `_createServer` calls `disableCache()` via `@voidzero-dev/vite-task-client`, so this run is never stored — the next invocation re-executes (cache miss / NotFound). +`vt run --cache dev` brings up a Vite dev server programmatically on an +ephemeral port and closes it immediately. Vite calls `disableCache()` via +`@voidzero-dev/vite-task-client`, but the client temporarily ignores that +request, so the next invocation hits the cache. """ ignore = true steps = [ @@ -10,11 +13,11 @@ steps = [ "run", "--cache", "dev", - ], comment = "first run — Vite dev start calls disableCache" }, + ], comment = "first run — Vite dev calls disableCache, currently ignored by the client" }, { argv = [ "vt", "run", "--cache", "dev", - ], comment = "cache miss (NotFound) because the first run was not stored" }, + ], comment = "cache hit because disableCache is temporarily a no-op" }, ] diff --git a/crates/vite_task_bin/tests/e2e_snapshots/fixtures/vite_dev_disable_cache/snapshots/vite_dev_disable_cache_noop_allows_cache_hit.md b/crates/vite_task_bin/tests/e2e_snapshots/fixtures/vite_dev_disable_cache/snapshots/vite_dev_disable_cache_noop_allows_cache_hit.md new file mode 100644 index 000000000..3eb6ad423 --- /dev/null +++ b/crates/vite_task_bin/tests/e2e_snapshots/fixtures/vite_dev_disable_cache/snapshots/vite_dev_disable_cache_noop_allows_cache_hit.md @@ -0,0 +1,25 @@ +# vite_dev_disable_cache_noop_allows_cache_hit + +`vt run --cache dev` brings up a Vite dev server programmatically on an +ephemeral port and closes it immediately. Vite calls `disableCache()` via +`@voidzero-dev/vite-task-client`, but the client temporarily ignores that +request, so the next invocation hits the cache. + +## `vt run --cache dev` + +first run — Vite dev calls disableCache, currently ignored by the client + +``` +$ node dev.mjs +``` + +## `vt run --cache dev` + +cache hit because disableCache is temporarily a no-op + +``` +$ node dev.mjs ◉ cache hit, replaying + +--- +vt run: cache hit. +``` diff --git a/crates/vite_task_bin/tests/e2e_snapshots/fixtures/vite_dev_disable_cache/snapshots/vite_dev_disables_cache.md b/crates/vite_task_bin/tests/e2e_snapshots/fixtures/vite_dev_disable_cache/snapshots/vite_dev_disables_cache.md deleted file mode 100644 index 9f5e07491..000000000 --- a/crates/vite_task_bin/tests/e2e_snapshots/fixtures/vite_dev_disable_cache/snapshots/vite_dev_disables_cache.md +++ /dev/null @@ -1,19 +0,0 @@ -# vite_dev_disables_cache - -`vt run --cache dev` brings up a Vite dev server programmatically on an ephemeral port and closes it immediately. Vite's `_createServer` calls `disableCache()` via `@voidzero-dev/vite-task-client`, so this run is never stored — the next invocation re-executes (cache miss / NotFound). - -## `vt run --cache dev` - -first run — Vite dev start calls disableCache - -``` -$ node dev.mjs -``` - -## `vt run --cache dev` - -cache miss (NotFound) because the first run was not stored - -``` -$ node dev.mjs -``` diff --git a/crates/vite_task_client/src/lib.rs b/crates/vite_task_client/src/lib.rs index 28740c861..715de5c08 100644 --- a/crates/vite_task_client/src/lib.rs +++ b/crates/vite_task_client/src/lib.rs @@ -84,13 +84,24 @@ impl Client { self.send(&Request::IgnoreOutput(&ns)) } - /// Fire-and-forget — see [`Self::ignore_input`]. + /// Temporary no-op. + /// + /// `disableCache` currently causes too many false opt-outs because tools + /// call it during configuration, before they know whether they will start + /// an uncached operation such as listening on a port or watching the + /// filesystem. /// /// # Errors /// - /// Returns an error if the request fails to send. + /// This temporary no-op does not currently return errors. + #[expect( + clippy::missing_const_for_fn, + clippy::unnecessary_wraps, + clippy::unused_self, + reason = "temporary no-op preserves the public API until disableCache semantics are redesigned" + )] pub fn disable_cache(&self) -> io::Result<()> { - self.send(&Request::DisableCache) + Ok(()) } /// Requests an env value from the runner. Returns `None` if the runner diff --git a/crates/vite_task_server/tests/integration.rs b/crates/vite_task_server/tests/integration.rs index 680a47f8f..e22581812 100644 --- a/crates/vite_task_server/tests/integration.rs +++ b/crates/vite_task_server/tests/integration.rs @@ -14,7 +14,7 @@ type RawStream = std::fs::File; use rustc_hash::FxHashMap; use tokio::runtime::Builder; use vite_task_client::{Client, GetEnvsQuery}; -use vite_task_ipc_shared::Request; +use vite_task_ipc_shared::{GetEnvResponse, Request}; use vite_task_server::{EnvQuery, Error, Recorder, Reports, ServerHandle, serve}; fn env_map(pairs: &[(&str, &str)]) -> FxHashMap, Arc> { @@ -82,6 +82,15 @@ fn send_frame(stream: &mut RawStream, request: &Request<'_>) { stream.flush().expect("flush"); } +fn recv_get_env_response(stream: &mut RawStream) -> GetEnvResponse { + let mut len_bytes = [0u8; 4]; + stream.read_exact(&mut len_bytes).expect("read len"); + let len = u32::from_le_bytes(len_bytes) as usize; + let mut buf = vec![0; len]; + stream.read_exact(&mut buf).expect("read body"); + wincode::deserialize_exact(&buf).expect("deserialize response") +} + #[test] fn single_client_fire_and_forget() { #[cfg(unix)] @@ -93,6 +102,9 @@ fn single_client_fire_and_forget() { let client = connect(&envs); client.ignore_input(OsStr::new(in_path)).unwrap(); client.ignore_output(OsStr::new(out_path)).unwrap(); + // Temporary workaround: the client currently ignores disableCache so + // tools cannot opt out at configuration time before they perform the + // operation that actually makes a task uncacheable. client.disable_cache().unwrap(); flush(&client); }) @@ -102,6 +114,21 @@ fn single_client_fire_and_forget() { let outputs: Vec<_> = reports.ignored_outputs.iter().map(|p| p.as_path().as_os_str()).collect(); assert_eq!(inputs, vec![OsStr::new(in_path)]); assert_eq!(outputs, vec![OsStr::new(out_path)]); + assert!(!reports.cache_disabled); +} + +#[test] +fn raw_disable_cache_request_disables_cache() { + let reports = run_with_server(env_map(&[]), |envs| { + let name = &envs[0].1; + let mut stream = connect_raw(name); + send_frame(&mut stream, &Request::DisableCache); + let flush_name: Box = OsStr::new("__VP_TEST_FLUSH__").into(); + send_frame(&mut stream, &Request::GetEnv { name: &flush_name, tracked: false }); + let _ = recv_get_env_response(&mut stream); + }) + .expect("driver returned error"); + assert!(reports.cache_disabled); }