Skip to content

Commit bfee38e

Browse files
committed
test(package): migrate bump regressions to bundles
1 parent 0cf5563 commit bfee38e

2 files changed

Lines changed: 61 additions & 14 deletions

File tree

‎tests/bump_emit.rs‎

Lines changed: 34 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,13 @@ fn foss(ver: &str) -> Toolchain {
2121
}
2222
}
2323

24+
fn bundle_recipe(out: &std::path::Path, package: &str, filename: &str) -> PathBuf {
25+
out.join("easyconfigs")
26+
.join(package[..1].to_ascii_lowercase())
27+
.join(package)
28+
.join(filename)
29+
}
30+
2431
#[test]
2532
fn library_bumps_fixture_gromacs_toolchain_only() {
2633
let src_path = fixture("foss-2025a/GROMACS-2024.1-foss-2025a.eb");
@@ -98,15 +105,20 @@ fn cli_bump_writes_conventional_file() {
98105
"OpenBLAS=0.3.27",
99106
"--dep",
100107
"OpenMPI=5.0.3",
108+
"--easyconfigs",
109+
fixture("").to_str().unwrap(),
101110
"--out-dir",
102111
out_dir.to_str().unwrap(),
103112
])
104113
.status()
105114
.expect("spawn eb-stack bump");
106115
assert!(status.success(), "eb-stack bump failed: {status}");
107116

108-
let written = out_dir.join("GROMACS-2025.0-foss-2025b.eb");
117+
let written = bundle_recipe(out_dir, "GROMACS", "GROMACS-2025.0-foss-2025b.eb");
109118
assert!(written.is_file(), "missing {}", written.display());
119+
assert!(out_dir.join("package.plan.json").is_file());
120+
assert!(out_dir.join("package.sbom.cdx.json").is_file());
121+
assert!(out_dir.join("locks/default.lock.json").is_file());
110122
let text = std::fs::read_to_string(&written).expect("read written");
111123
assert!(text.contains("version = '2025.0'"));
112124
assert!(text.contains("toolchain = {'name': 'foss', 'version': '2025b'}"));
@@ -116,13 +128,13 @@ fn cli_bump_writes_conventional_file() {
116128
}
117129

118130
#[test]
119-
fn cli_bump_toolchain_only_twice_idempotent_content() {
131+
fn cli_bump_resolvo_bundle_is_deterministic() {
120132
let bin = env!("CARGO_BIN_EXE_eb-stack");
121133
let src = fixture("foss-2025a/GROMACS-2024.1-foss-2025a.eb");
122134
let tmp = tempfile::tempdir().expect("tempdir");
123135

124136
for i in 0..2 {
125-
let out = tmp.path().join(format!("run{i}.eb"));
137+
let out = tmp.path().join(format!("run{i}"));
126138
let status = Command::new(bin)
127139
.args([
128140
"package",
@@ -133,17 +145,27 @@ fn cli_bump_toolchain_only_twice_idempotent_content() {
133145
"foss",
134146
"--toolchain-version",
135147
"2025b",
136-
"--out",
148+
"--easyconfigs",
149+
fixture("").to_str().unwrap(),
150+
"--out-dir",
137151
out.to_str().unwrap(),
138152
])
139153
.status()
140154
.expect("spawn");
141155
assert!(status.success(), "run {i} failed");
142-
let text = std::fs::read_to_string(&out).unwrap();
156+
let recipe = bundle_recipe(&out, "GROMACS", "GROMACS-2024.1-foss-2025b.eb");
157+
let text = std::fs::read_to_string(&recipe).unwrap();
143158
assert!(text.contains("toolchain = {'name': 'foss', 'version': '2025b'}"));
144159
assert!(text.contains("version = '2024.1'"));
160+
assert!(out.join("package.sbom.cdx.json").is_file());
161+
assert!(out.join("locks/default.lock.json").is_file());
145162
if i == 1 {
146-
let first = std::fs::read_to_string(tmp.path().join("run0.eb")).unwrap();
163+
let first = std::fs::read_to_string(bundle_recipe(
164+
&tmp.path().join("run0"),
165+
"GROMACS",
166+
"GROMACS-2024.1-foss-2025b.eb",
167+
))
168+
.unwrap();
147169
assert_eq!(first, text, "two CLI runs must produce identical content");
148170
}
149171
}
@@ -199,7 +221,7 @@ fn cli_bump_auto_resolve_from_easyconfigs() {
199221
let src = gromacs_repro_source();
200222
let universe = gromacs_repro_universe();
201223
let tmp = tempfile::tempdir().expect("tempdir");
202-
let out = tmp.path().join("out.eb");
224+
let out = tmp.path().join("bundle");
203225

204226
let status = Command::new(bin)
205227
.args([
@@ -213,13 +235,16 @@ fn cli_bump_auto_resolve_from_easyconfigs() {
213235
"2024a",
214236
"--easyconfigs",
215237
universe.to_str().unwrap(),
216-
"--out",
238+
"--out-dir",
217239
out.to_str().unwrap(),
218240
])
219241
.status()
220242
.expect("spawn eb-stack bump --easyconfigs");
221243
assert!(status.success(), "auto bump failed: {status}");
222-
let text = std::fs::read_to_string(&out).expect("read");
244+
let recipe = bundle_recipe(&out, "GROMACS", "GROMACS-2024.4-foss-2024a.eb");
245+
let text = std::fs::read_to_string(recipe).expect("read");
246+
assert!(out.join("package.sbom.cdx.json").is_file());
247+
assert!(out.join("locks/default.lock.json").is_file());
223248
assert!(text.contains("toolchain = {'name': 'foss', 'version': '2024a'}"));
224249
assert!(text.contains("('Python', '3.12.3')"));
225250
assert!(text.contains("('mpi4py', '4.0.1')"));

‎tests/reproduce_real_prs.rs‎

Lines changed: 27 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -358,15 +358,32 @@ fn reproduces_numba_0_60_0_foss_2023b_to_2024a_auto() {
358358

359359
// ---------------------------------------------------------------------------
360360
// CLI path: the same known bumps an operator or the annual-bump skill runs
361-
// via `eb-stack bump --easyconfigs …`. CI must exercise this surface, not
361+
// via `eb-stack package bump --easyconfigs …`. CI must exercise this surface, not
362362
// only the library API, because flag wiring and exit status are the contract.
363363
// ---------------------------------------------------------------------------
364364

365-
/// Run `eb-stack bump --easyconfigs` and return the written file contents.
365+
fn find_named(directory: &Path, name: &str) -> PathBuf {
366+
for entry in std::fs::read_dir(directory).expect("read bundle directory") {
367+
let path = entry.expect("bundle entry").path();
368+
if path.is_dir() {
369+
let found = find_named(&path, name);
370+
if found.as_os_str().is_empty() {
371+
continue;
372+
}
373+
return found;
374+
}
375+
if path.file_name().and_then(|value| value.to_str()) == Some(name) {
376+
return path;
377+
}
378+
}
379+
PathBuf::new()
380+
}
381+
382+
/// Run `eb-stack package bump --easyconfigs` and return the bundled recipe.
366383
fn cli_auto_bump(source: &Path, out_name: &str) -> String {
367384
let bin = env!("CARGO_BIN_EXE_eb-stack");
368385
let tmp = tempfile::tempdir().expect("tempdir");
369-
let out = tmp.path().join(out_name);
386+
let out = tmp.path().join("bundle");
370387
let status = Command::new(bin)
371388
.args([
372389
"package",
@@ -379,7 +396,7 @@ fn cli_auto_bump(source: &Path, out_name: &str) -> String {
379396
"2024a",
380397
"--easyconfigs",
381398
universe_foss_2024a().to_str().unwrap(),
382-
"--out",
399+
"--out-dir",
383400
out.to_str().unwrap(),
384401
])
385402
.status()
@@ -389,7 +406,12 @@ fn cli_auto_bump(source: &Path, out_name: &str) -> String {
389406
"eb-stack bump failed for {}: {status}",
390407
source.display()
391408
);
392-
std::fs::read_to_string(&out).expect("read CLI output")
409+
assert!(out.join("package.plan.json").is_file());
410+
assert!(out.join("package.sbom.cdx.json").is_file());
411+
assert!(out.join("locks/default.lock.json").is_file());
412+
let recipe = find_named(&out.join("easyconfigs"), out_name);
413+
assert!(!recipe.as_os_str().is_empty(), "missing {out_name}");
414+
std::fs::read_to_string(recipe).expect("read CLI output")
393415
}
394416

395417
/// CLI auto-bump must match library emit (modulo residual additions).

0 commit comments

Comments
 (0)