Skip to content

Commit

Permalink
libcnb-test: Implement fmt::Display for LogOutput
Browse files Browse the repository at this point in the history
Since:
- There was already duplication of formatting stderr/stdout output,
  which was otherwise going to get worse after an upcoming PR
  for #482.
- It may also be useful for end users when debugging, to save them
  having to manually print both stderr and stdout manually.

Prep for #482.
  • Loading branch information
edmorley committed Aug 17, 2023
1 parent 1cf9d61 commit fd362ae
Show file tree
Hide file tree
Showing 4 changed files with 24 additions and 17 deletions.
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ separate changelogs for each crate were used. If you need to refer to these old
### Added

- `libcnb-package`: Add cross-compilation assistance for Linux `aarch64-unknown-linux-musl`. ([#577](https://github.com/heroku/libcnb.rs/pull/577))
- `libcnb-test`: `LogOutput` now implements `std::fmt::Display`. ([#635](https://github.com/heroku/libcnb.rs/pull/635))

### Changed

Expand Down
9 changes: 9 additions & 0 deletions libcnb-test/src/log.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,15 @@
use std::fmt::Display;

/// Log output from a command.
#[derive(Debug, Default)]
pub struct LogOutput {
pub stdout: String,
pub stderr: String,
}

impl Display for LogOutput {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
let LogOutput { stdout, stderr } = self;
write!(f, "## stderr:\n\n{stderr}\n## stdout:\n\n{stdout}\n")
}
}
12 changes: 5 additions & 7 deletions libcnb-test/src/test_runner.rs
Original file line number Diff line number Diff line change
@@ -1,9 +1,7 @@
use crate::docker::DockerRemoveImageCommand;
use crate::pack::PackBuildCommand;
use crate::util::CommandError;
use crate::{
app, build, util, BuildConfig, BuildpackReference, LogOutput, PackResult, TestContext,
};
use crate::{app, build, util, BuildConfig, BuildpackReference, PackResult, TestContext};
use std::borrow::Borrow;
use std::env;
use std::path::PathBuf;
Expand Down Expand Up @@ -119,18 +117,18 @@ impl TestRunner {

let output = match (&config.expected_pack_result, pack_result) {
(PackResult::Success, Ok(output)) => output,
(PackResult::Failure, Err(CommandError::NonZeroExitCode { stdout, stderr, .. })) => {
LogOutput { stdout, stderr }
(PackResult::Failure, Err(CommandError::NonZeroExitCode { log_output, .. })) => {
log_output
}
(PackResult::Failure, Ok(LogOutput { stdout, stderr })) => {
(PackResult::Failure, Ok(log_output)) => {
// Ordinarily the Docker image created by `pack build` will either be cleaned up by
// `TestContext::Drop` later on, or will not have been created in the first place,
// if the `pack build` was not successful. However, in the case of an unexpectedly
// successful `pack build` we have to clean this image up manually before `panic`ing.
util::run_command(DockerRemoveImageCommand::new(image_name)).unwrap_or_else(
|command_err| panic!("Error removing Docker image:\n\n{command_err}"),
);
panic!("The pack build was expected to fail, but did not:\n\n## stderr:\n\n{stderr}\n## stdout:\n\n{stdout}\n");
panic!("The pack build was expected to fail, but did not:\n\n{log_output}");
}
(_, Err(command_err)) => {
panic!("Error performing pack build:\n\n{command_err}");
Expand Down
19 changes: 9 additions & 10 deletions libcnb-test/src/util.rs
Original file line number Diff line number Diff line change
Expand Up @@ -40,17 +40,18 @@ pub(crate) fn run_command(command: impl Into<Command>) -> Result<LogOutput, Comm
}
})
.and_then(|output| {
let stdout = String::from_utf8_lossy(&output.stdout).into_owned();
let stderr = String::from_utf8_lossy(&output.stderr).into_owned();
let log_output = LogOutput {
stdout: String::from_utf8_lossy(&output.stdout).into_owned(),
stderr: String::from_utf8_lossy(&output.stderr).into_owned(),
};

if output.status.success() {
Ok(LogOutput { stdout, stderr })
Ok(log_output)
} else {
Err(CommandError::NonZeroExitCode {
program,
exit_code: output.status.code(),
stdout,
stderr,
log_output,
})
}
})
Expand All @@ -69,8 +70,7 @@ pub(crate) enum CommandError {
NonZeroExitCode {
exit_code: Option<i32>,
program: String,
stdout: String,
stderr: String,
log_output: LogOutput,
},
}

Expand All @@ -89,11 +89,10 @@ impl Display for CommandError {
CommandError::NonZeroExitCode {
program,
exit_code,
stdout,
stderr,
log_output,
} => write!(
f,
"{program} command failed with exit code {}!\n\n## stderr:\n\n{stderr}\n## stdout:\n\n{stdout}\n",
"{program} command failed with exit code {}!\n\n{log_output}",
exit_code.map_or(String::from("<unknown>"), |exit_code| exit_code.to_string())
),
}
Expand Down

0 comments on commit fd362ae

Please sign in to comment.