Skip to content

Commit 404bcd9

Browse files
committed
test(e2e): verify old output archive is removed on re-run
Adds `vtt list-dir <dir> [--ext <suffix>]` for inspecting cache state from e2e tests, plus a UUID redactor so archive filenames (which are random per run) stay stable across snapshot regenerations. The new `output_globs___old_archive_removed_on_rewrite` fixture asserts that after two cache-missing runs of the same task, the cache directory contains exactly one `.tar.zst` archive — proving the cleanup path in `ExecutionCache::update` actually runs.
1 parent f646282 commit 404bcd9

5 files changed

Lines changed: 108 additions & 1 deletion

File tree

Lines changed: 44 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,44 @@
1+
/// List entries in a directory, sorted by name, one per line.
2+
///
3+
/// Usage: `vtt list-dir <dir> [--ext <suffix>]`
4+
///
5+
/// With `--ext`, only entries whose filename ends with the given suffix are
6+
/// printed (the leading `.` is part of the suffix you pass, e.g. `.tar.zst`).
7+
///
8+
/// Used by e2e tests to assert on cache directory contents (e.g. exactly one
9+
/// `.tar.zst` archive after a re-run that should have cleaned up the prior
10+
/// archive).
11+
pub fn run(args: &[String]) -> Result<(), Box<dyn std::error::Error>> {
12+
let mut dir: Option<&str> = None;
13+
let mut ext: Option<&str> = None;
14+
let mut i = 0;
15+
while i < args.len() {
16+
match args[i].as_str() {
17+
"--ext" => {
18+
i += 1;
19+
ext = Some(args.get(i).ok_or("--ext requires a value")?.as_str());
20+
}
21+
other if dir.is_none() => dir = Some(other),
22+
other => return Err(format!("unexpected argument: {other}").into()),
23+
}
24+
i += 1;
25+
}
26+
let dir = dir.ok_or("Usage: vtt list-dir <dir> [--ext <suffix>]")?;
27+
28+
let mut names: Vec<String> = Vec::new();
29+
for entry in std::fs::read_dir(dir)? {
30+
let entry = entry?;
31+
let name = entry.file_name().to_string_lossy().into_owned();
32+
if let Some(suffix) = ext
33+
&& !name.ends_with(suffix)
34+
{
35+
continue;
36+
}
37+
names.push(name);
38+
}
39+
names.sort();
40+
for name in names {
41+
println!("{name}");
42+
}
43+
Ok(())
44+
}

crates/vite_task_bin/src/vtt/main.rs

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@ mod check_tty;
1111
mod cp;
1212
mod exit;
1313
mod exit_on_ctrlc;
14+
mod list_dir;
1415
mod mkdir;
1516
mod pipe_stdin;
1617
mod print;
@@ -28,7 +29,7 @@ fn main() {
2829
if args.len() < 2 {
2930
eprintln!("Usage: vtt <subcommand> [args...]");
3031
eprintln!(
31-
"Subcommands: barrier, check-tty, cp, exit, exit-on-ctrlc, mkdir, pipe-stdin, print, print-cwd, print-env, print-file, read-stdin, replace-file-content, rm, touch-file, write-file"
32+
"Subcommands: barrier, check-tty, cp, exit, exit-on-ctrlc, list-dir, mkdir, pipe-stdin, print, print-cwd, print-env, print-file, read-stdin, replace-file-content, rm, touch-file, write-file"
3233
);
3334
std::process::exit(1);
3435
}
@@ -42,6 +43,7 @@ fn main() {
4243
"cp" => cp::run(&args[2..]),
4344
"exit" => exit::run(&args[2..]),
4445
"exit-on-ctrlc" => exit_on_ctrlc::run(),
46+
"list-dir" => list_dir::run(&args[2..]),
4547
"mkdir" => mkdir::run(&args[2..]),
4648
"pipe-stdin" => pipe_stdin::run(&args[2..]),
4749
"print" => {

crates/vite_task_bin/tests/e2e_snapshots/fixtures/output_cache_test/snapshots.toml

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,27 @@ steps = [
1818
["vtt", "print-file", "dist/output.txt"],
1919
]
2020

21+
[[e2e]]
22+
name = "output_globs___old_archive_removed_on_rewrite"
23+
comment = """
24+
When a cached task re-runs (cache miss because an input changed), it
25+
writes a new archive and the previous archive file is cleaned up. After
26+
two runs of the same task the cache directory still contains only one
27+
\\\".tar.zst\\\" file.
28+
"""
29+
steps = [
30+
# First run - cache miss, produces archive A
31+
["vt", "run", "build"],
32+
# Exactly one archive on disk
33+
["vtt", "list-dir", "node_modules/.vite/task-cache", "--ext", ".tar.zst"],
34+
# Modify the input so the next run is a cache miss
35+
["vtt", "write-file", "src/main.ts", "changed"],
36+
# Second run - cache miss, produces archive B; archive A is deleted
37+
["vt", "run", "build"],
38+
# Still only one archive on disk (A removed, B written)
39+
["vtt", "list-dir", "node_modules/.vite/task-cache", "--ext", ".tar.zst"],
40+
]
41+
2142
[[e2e]]
2243
name = "output_globs___negative_excludes_files_from_archive"
2344
comment = """
Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,35 @@
1+
# output_globs___old_archive_removed_on_rewrite
2+
3+
When a cached task re-runs (cache miss because an input changed), it
4+
writes a new archive and the previous archive file is cleaned up. After
5+
two runs of the same task the cache directory still contains only one
6+
\".tar.zst\" file.
7+
8+
## `vt run build`
9+
10+
```
11+
$ vtt write-file dist/output.txt built
12+
```
13+
14+
## `vtt list-dir node_modules/.vite/task-cache --ext .tar.zst`
15+
16+
```
17+
<uuid>.tar.zst
18+
```
19+
20+
## `vtt write-file src/main.ts changed`
21+
22+
```
23+
```
24+
25+
## `vt run build`
26+
27+
```
28+
$ vtt write-file dist/output.txt built ○ cache miss: 'src/main.ts' modified, executing
29+
```
30+
31+
## `vtt list-dir node_modules/.vite/task-cache --ext .tar.zst`
32+
33+
```
34+
<uuid>.tar.zst
35+
```

crates/vite_task_bin/tests/e2e_snapshots/redact.rs

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -64,6 +64,11 @@ pub fn redact_e2e_output(mut output: String, workspace_root: &str) -> String {
6464

6565
redact_string(&mut output, &redactions);
6666

67+
// Redact UUIDs (e.g. cache archive filenames `<uuid>.tar.zst`) to "<uuid>"
68+
let uuid_regex =
69+
regex::Regex::new(r"[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}").unwrap();
70+
output = uuid_regex.replace_all(&output, "<uuid>").into_owned();
71+
6772
// Redact durations like "0ns", "123ms" or "1.23s" to "<duration>"
6873
let duration_regex = regex::Regex::new(r"\d+(\.\d+)?(ns|ms|s)").unwrap();
6974
output = duration_regex.replace_all(&output, "<duration>").into_owned();

0 commit comments

Comments
 (0)