Skip to content

Commit bbbcdac

Browse files
committed
lints: Also test main execution
We unit test each lint, but not the main function. As it grows in complexity it'll be useful to unit test. - Change the function to write to a provided output, not always stdout/stderr - Add a `passing_fixture` helper that passes all lints - Fix the baseimage test not to use `??` because that turns the *inner* error into an outer error which is not what we want. Signed-off-by: Colin Walters <[email protected]>
1 parent 2c1ba97 commit bbbcdac

File tree

2 files changed

+47
-31
lines changed

2 files changed

+47
-31
lines changed

lib/src/cli.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1025,7 +1025,7 @@ async fn run_from_opt(opt: Opt) -> Result<()> {
10251025
);
10261026
}
10271027
let root = &Dir::open_ambient_dir(rootfs, cap_std::ambient_authority())?;
1028-
lints::lint(root, fatal_warnings)?;
1028+
lints::lint(root, fatal_warnings, std::io::stdout().lock())?;
10291029
Ok(())
10301030
}
10311031
},

lib/src/lints.rs

Lines changed: 46 additions & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -109,7 +109,11 @@ const LINTS: &[Lint] = &[
109109
/// if it exists we need to check that it links to /run if not error
110110
/// if it does not exist error.
111111
#[context("Linting")]
112-
pub(crate) fn lint(root: &Dir, fatal_warnings: bool) -> Result<()> {
112+
pub(crate) fn lint(
113+
root: &Dir,
114+
fatal_warnings: bool,
115+
mut output: impl std::io::Write,
116+
) -> Result<()> {
113117
let mut fatal = 0usize;
114118
let mut warnings = 0usize;
115119
let mut passed = 0usize;
@@ -123,11 +127,11 @@ pub(crate) fn lint(root: &Dir, fatal_warnings: bool) -> Result<()> {
123127
if let Err(e) = r {
124128
match lint.ty {
125129
LintType::Fatal => {
126-
eprintln!("Failed lint: {name}: {e}");
130+
writeln!(output, "Failed lint: {name}: {e}")?;
127131
fatal += 1;
128132
}
129133
LintType::Warning => {
130-
eprintln!("Lint warning: {name}: {e}");
134+
writeln!(output, "Lint warning: {name}: {e}")?;
131135
warnings += 1;
132136
}
133137
}
@@ -137,14 +141,14 @@ pub(crate) fn lint(root: &Dir, fatal_warnings: bool) -> Result<()> {
137141
passed += 1;
138142
}
139143
}
140-
println!("Checks passed: {passed}");
144+
writeln!(output, "Checks passed: {passed}")?;
141145
let fatal = if fatal_warnings {
142146
fatal + warnings
143147
} else {
144148
fatal
145149
};
146150
if warnings > 0 {
147-
println!("Warnings: {warnings}");
151+
writeln!(output, "Warnings: {warnings}")?;
148152
}
149153
if fatal > 0 {
150154
anyhow::bail!("Checks failed: {fatal}")
@@ -258,11 +262,15 @@ fn check_baseimage_root_norecurse(dir: &Dir) -> LintResult {
258262

259263
/// Check ostree-related base image content.
260264
fn check_baseimage_root(dir: &Dir) -> LintResult {
261-
check_baseimage_root_norecurse(dir)??;
265+
if let Err(e) = check_baseimage_root_norecurse(dir)? {
266+
return Ok(Err(e));
267+
}
262268
// If we have our own documentation with the expected root contents
263269
// embedded, then check that too! Mostly just because recursion is fun.
264270
if let Some(dir) = dir.open_dir_optional(BASEIMAGE_REF)? {
265-
check_baseimage_root_norecurse(&dir)??;
271+
if let Err(e) = check_baseimage_root_norecurse(&dir)? {
272+
return Ok(Err(e));
273+
}
266274
}
267275
lint_ok()
268276
}
@@ -317,6 +325,23 @@ mod tests {
317325
Ok(tempdir)
318326
}
319327

328+
fn passing_fixture() -> Result<cap_std_ext::cap_tempfile::TempDir> {
329+
let root = cap_std_ext::cap_tempfile::tempdir(cap_std::ambient_authority())?;
330+
root.create_dir_all("usr/lib/modules/5.7.2")?;
331+
root.write("usr/lib/modules/5.7.2/vmlinuz", "vmlinuz")?;
332+
333+
root.create_dir("sysroot")?;
334+
root.symlink_contents("sysroot/ostree", "ostree")?;
335+
336+
const PREPAREROOT_PATH: &str = "usr/lib/ostree/prepare-root.conf";
337+
const PREPAREROOT: &str =
338+
include_str!("../../baseimage/base/usr/lib/ostree/prepare-root.conf");
339+
root.create_dir_all(Utf8Path::new(PREPAREROOT_PATH).parent().unwrap())?;
340+
root.atomic_write(PREPAREROOT_PATH, PREPAREROOT)?;
341+
342+
Ok(root)
343+
}
344+
320345
#[test]
321346
fn test_var_run() -> Result<()> {
322347
let root = &fixture()?;
@@ -330,6 +355,17 @@ mod tests {
330355
Ok(())
331356
}
332357

358+
#[test]
359+
fn test_lint_main() -> Result<()> {
360+
let root = &passing_fixture()?;
361+
let mut out = Vec::new();
362+
lint(root, true, &mut out).unwrap();
363+
root.create_dir_all("var/run/foo")?;
364+
let mut out = Vec::new();
365+
assert!(lint(root, true, &mut out).is_err());
366+
Ok(())
367+
}
368+
333369
#[test]
334370
fn test_kernel_lint() -> Result<()> {
335371
let root = &fixture()?;
@@ -476,33 +512,13 @@ mod tests {
476512

477513
#[test]
478514
fn test_baseimage_root() -> Result<()> {
479-
use bootc_utils::CommandRunExt;
480-
use cap_std_ext::cmdext::CapStdExtCommandExt;
481-
use std::path::Path;
482-
483515
let td = fixture()?;
484516

485517
// An empty root should fail our test
486-
assert!(check_baseimage_root(&td).is_err());
518+
assert!(check_baseimage_root(&td).unwrap().is_err());
487519

488-
// Copy our reference base image content from the source dir
489-
let Some(manifest) = std::env::var_os("CARGO_MANIFEST_PATH") else {
490-
// This was only added in relatively recent cargo
491-
return Ok(());
492-
};
493-
let srcdir = Path::new(&manifest)
494-
.parent()
495-
.unwrap()
496-
.join("../baseimage/base");
497-
for ent in std::fs::read_dir(srcdir)? {
498-
let ent = ent?;
499-
std::process::Command::new("cp")
500-
.cwd_dir(td.try_clone()?)
501-
.arg("-pr")
502-
.arg(ent.path())
503-
.arg(".")
504-
.run()?;
505-
}
520+
drop(td);
521+
let td = passing_fixture()?;
506522
check_baseimage_root(&td).unwrap().unwrap();
507523
Ok(())
508524
}

0 commit comments

Comments
 (0)