From e4de0c976a5546e4398df3689b9fd283ee3fe4d0 Mon Sep 17 00:00:00 2001 From: Justin Wernick Date: Thu, 9 Mar 2023 09:37:08 +0200 Subject: Make docker build only run once even if there are multiple tests using it --- tests/server_shell.rs | 71 ++++++++++++++++++++++++++++++++++++--------------- 1 file changed, 51 insertions(+), 20 deletions(-) (limited to 'tests') diff --git a/tests/server_shell.rs b/tests/server_shell.rs index 858f123..ae77a6a 100644 --- a/tests/server_shell.rs +++ b/tests/server_shell.rs @@ -1,7 +1,12 @@ -use anyhow::{bail, Result}; -use assert_cmd::{cargo::cargo_bin, Command}; +use anyhow::Result; +use assert_cmd::cargo::cargo_bin; use rexpect::session::{spawn_command, PtySession}; +use std::{io, path, sync::Once}; use tempfile::TempDir; +use thiserror::Error; + +static BUILD_DOCKER: Once = Once::new(); +static mut BUILD_DOCKER_RESULT: Result<(), DockerBuildError> = Ok(()); struct TestContext { workdir: TempDir, @@ -9,27 +14,53 @@ struct TestContext { docker_process: PtySession, } -fn build_docker_image() -> Result<()> { - let mut command = std::process::Command::new("docker"); - - let absolute_shell_path = cargo_bin(env!("CARGO_PKG_NAME")); - let relative_shell_path = absolute_shell_path.strip_prefix(std::fs::canonicalize(".")?)?; - command.args([ - "build", - "--quiet", - "-t", - "shackle-server", - "--build-arg", - &format!("SHELL={}", relative_shell_path.display()), - "./", - ]); +#[derive(Error, Debug, Clone)] +pub enum DockerBuildError { + #[error(transparent)] + StripPrefixError(#[from] path::StripPrefixError), + #[error("IO Error: `{0}`")] + IoError(String), + #[error("Failed to build dockerfile")] + CliError, +} - let status = command.status()?; - if !status.success() { - bail!("Failed to build dockerfile"); +impl From for DockerBuildError { + fn from(e: io::Error) -> Self { + DockerBuildError::IoError(e.to_string()) } +} - Ok(()) +fn build_docker_image() -> Result<(), DockerBuildError> { + let build_docker = || { + let mut command = std::process::Command::new("docker"); + + let absolute_shell_path = cargo_bin(env!("CARGO_PKG_NAME")); + let relative_shell_path = absolute_shell_path.strip_prefix(std::fs::canonicalize(".")?)?; + command.args([ + "build", + "--quiet", + "-t", + "shackle-server", + "--build-arg", + &format!("SHELL={}", relative_shell_path.display()), + "./", + ]); + + let status = command.status()?; + if status.success() { + Ok(()) + } else { + Err(DockerBuildError::CliError) + } + }; + + // Based on this example: https://doc.rust-lang.org/std/sync/struct.Once.html#examples-1 + unsafe { + BUILD_DOCKER.call_once(|| { + BUILD_DOCKER_RESULT = build_docker(); + }); + BUILD_DOCKER_RESULT.clone() + } } fn spawn_ssh_server() -> Result { -- cgit v1.2.3