Skip to content

Commit

Permalink
[antlir2][image_test] print path to booted console file on test failure
Browse files Browse the repository at this point in the history
Summary:
Instead of just letting it be logged to the artifact file / tpx ui, print the
path to stderr so that it's obvious how to find it for local debugging

Test Plan:
```
❯ buck2 test fbcode//antlir/antlir2/testing/tests:booted-image-test-that-should-fail
Buck UI: https://www.internalfb.com/buck2/a4e85cd6-40e8-4d20-b5aa-b40ff78ec902
Test UI: https://www.internalfb.com/intern/testinfra/testrun/844425330324771
Tests finished: Pass 1. Fail 0. Fatal 0. Skip 0. Build failure 0
```

Reviewed By: naveedgol

Differential Revision: D68965428

fbshipit-source-id: e2f6046b76f741881a6c661b1d9a32614e0766a6
  • Loading branch information
vmagro authored and facebook-github-bot committed Feb 3, 2025
1 parent 0e2ccab commit db0970f
Show file tree
Hide file tree
Showing 3 changed files with 41 additions and 9 deletions.
36 changes: 31 additions & 5 deletions antlir/antlir2/testing/image_test/src/spawn_common.rs
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@ use std::os::fd::FromRawFd;
use std::os::unix::fs::PermissionsExt;
use std::os::unix::process::CommandExt;
use std::path::Path;
use std::path::PathBuf;
use std::process::Command;

use antlir2_isolate::nspawn;
Expand Down Expand Up @@ -236,8 +237,8 @@ pub(crate) fn run(
let mut child = isol
// the stdout/err of the systemd inside the container is a pipe
// so that we can print it IFF the test fails
.stdout(container_stdout.try_clone()?)
.stderr(container_stdout.try_clone()?)
.stdout(container_stdout.as_file()?)
.stderr(container_stdout.as_file()?)
.spawn()
.context("while spawning systemd-nspawn")?;
let res = child.wait().context("while waiting for systemd-nspawn")?;
Expand All @@ -246,6 +247,15 @@ pub(crate) fn run(
std::io::copy(&mut test_stderr, &mut std::io::stderr())?;

if !res.success() {
// if the container stdout is not already being dumped to
// stdout/err, then print out the path where it can be found
if let ContainerConsoleOutput::File { path, .. } = &container_stdout {
eprintln!(
"full container console output can be found at: '{}'",
path.display()
);
eprintln!("{}", path.display());
}
std::process::exit(res.code().unwrap_or(255))
} else {
Ok(())
Expand All @@ -268,10 +278,24 @@ pub(crate) fn run(
}
}

enum ContainerConsoleOutput {
File { path: PathBuf, file: File },
Stderr,
}

impl ContainerConsoleOutput {
fn as_file(&self) -> Result<File> {
match self {
Self::File { file, .. } => file.try_clone().context("while cloning file fd"),
Self::Stderr => Ok(unsafe { File::from_raw_fd(std::io::stderr().as_raw_fd()) }),
}
}
}

/// Create a file to record container stdout into. When invoked under tpx, this
/// will be uploaded as an artifact. The artifact metadata is set up before
/// running the test so that it still gets uploaded even in case of a timeout
fn container_stdout_file() -> Result<File> {
fn container_stdout_file() -> Result<ContainerConsoleOutput> {
// if tpx has provided this artifacts dir, put the logs there so they get
// uploaded along with the test results
if let Some(artifacts_dir) = std::env::var_os("TEST_RESULT_ARTIFACTS_DIR") {
Expand All @@ -284,9 +308,11 @@ fn container_stdout_file() -> Result<File> {
r#"{"type": {"generic_text_log": {}}, "description": "systemd logs"}"#,
)?;
}
File::create(&dst).with_context(|| format!("while creating {}", dst.display()))
File::create(&dst)
.with_context(|| format!("while creating {}", dst.display()))
.map(|file| ContainerConsoleOutput::File { path: dst, file })
} else {
// otherwise, have it go right to stderr
Ok(unsafe { File::from_raw_fd(std::io::stderr().as_raw_fd()) })
Ok(ContainerConsoleOutput::Stderr)
}
}
12 changes: 9 additions & 3 deletions antlir/antlir2/testing/test_that_should_fail/src/main.rs
Original file line number Diff line number Diff line change
Expand Up @@ -40,11 +40,17 @@ fn main() -> Result<()> {
);
if let Some(re) = args.stdout_re {
let stdout = std::str::from_utf8(&res.stdout).context("stdout not utf8")?;
ensure!(re.is_match(stdout), "stdout did not match {re}:\n{stdout}");
ensure!(
re.is_match(stdout),
"stdout did not match {re}:\n'{stdout}'"
);
}
if let Some(re) = args.stderr_re {
let stderr = std::str::from_utf8(&res.stderr).context("stdout not utf8")?;
ensure!(re.is_match(stderr), "stderr did not match {re}:\n{stderr}");
let stderr = std::str::from_utf8(&res.stderr).context("stderr not utf8")?;
ensure!(
re.is_match(stderr),
"stderr did not match {re}:\n'{stderr}'"
);
}
Ok(())
}
2 changes: 1 addition & 1 deletion antlir/antlir2/testing/tests/BUCK
Original file line number Diff line number Diff line change
Expand Up @@ -184,7 +184,7 @@ test_that_should_fail(
name = "booted-image-test-that-should-fail",
boot = True,
layer = ":base",
stderr_re = "^this is some stderr of a test that is expected to fail\n$",
stderr_re = "^this is some stderr of a test that is expected to fail\nfull container console output can be found at: '/",
stdout_re = "^this is some stdout of a test that is expected to fail\n$",
test = "failing_test.sh",
test_rule = image_sh_test,
Expand Down

0 comments on commit db0970f

Please sign in to comment.