diff --git a/Cargo.lock b/Cargo.lock index 84f074c4b..0256775ca 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -2068,6 +2068,7 @@ dependencies = [ "serde", "serde_json", "ssh2", + "thiserror 2.0.6", "vmm-sys-util", "wait-timeout", ] diff --git a/test_infra/Cargo.toml b/test_infra/Cargo.toml index 199270d60..62bbf7347 100644 --- a/test_infra/Cargo.toml +++ b/test_infra/Cargo.toml @@ -12,5 +12,6 @@ once_cell = "1.20.2" serde = { version = "1.0.208", features = ["derive", "rc"] } serde_json = { workspace = true } ssh2 = { version = "0.9.4", features = ["vendored-openssl"] } +thiserror = "2.0.6" vmm-sys-util = { workspace = true } wait-timeout = "0.2.0" diff --git a/test_infra/src/lib.rs b/test_infra/src/lib.rs index 7cd9a8bd8..b61a57132 100644 --- a/test_infra/src/lib.rs +++ b/test_infra/src/lib.rs @@ -21,27 +21,40 @@ use std::{env, fmt, fs, io, thread}; use once_cell::sync::Lazy; use serde_json::Value; use ssh2::Session; +use thiserror::Error; use vmm_sys_util::tempdir::TempDir; use wait_timeout::ChildExt; -#[derive(Debug)] +#[derive(Error, Debug)] pub enum WaitTimeoutError { + #[error("timeout")] Timedout, + #[error("exit status indicates failure")] ExitStatus, - General(std::io::Error), + #[error("general failure: {0}")] + General(#[source] std::io::Error), } -#[derive(Debug)] +#[derive(Error, Debug)] pub enum Error { - Parsing(std::num::ParseIntError), - SshCommand(SshCommandError), - WaitForBoot(WaitForBootError), - EthrLogFile(std::io::Error), + #[error("Failed to parse: {0}")] + Parsing(#[source] std::num::ParseIntError), + #[error("ssh command failed: {0}")] + SshCommand(#[source] SshCommandError), + #[error("waiting for boot failed: {0}")] + WaitForBoot(#[source] WaitForBootError), + #[error("reading log file failed: {0}")] + EthrLogFile(#[source] std::io::Error), + #[error("parsing log file failed")] EthrLogParse, + #[error("parsing fio output failed")] FioOutputParse, + #[error("parsing iperf3 output failed")] Iperf3Parse, - Spawn(std::io::Error), - WaitTimeout(WaitTimeoutError), + #[error("spawning process failed: {0}")] + Spawn(#[source] std::io::Error), + #[error("waiting for timeout failed: {0}")] + WaitTimeout(#[source] WaitTimeoutError), } impl From for Error { @@ -67,13 +80,18 @@ pub const DEFAULT_TCP_LISTENER_MESSAGE: &str = "booted"; pub const DEFAULT_TCP_LISTENER_PORT: u16 = 8000; pub const DEFAULT_TCP_LISTENER_TIMEOUT: i32 = 120; -#[derive(Debug)] +#[derive(Error, Debug)] pub enum WaitForBootError { - EpollWait(std::io::Error), - Listen(std::io::Error), + #[error("Failed to wait for epoll: {0}")] + EpollWait(#[source] std::io::Error), + #[error("Failed to listen for boot: {0}")] + Listen(#[source] std::io::Error), + #[error("Epoll wait timeout")] EpollWaitTimeout, + #[error("wrong guest address")] WrongGuestAddr, - Accept(std::io::Error), + #[error("Failed to accept a TCP request: {0}")] + Accept(#[source] std::io::Error), } impl GuestNetworkConfig { @@ -532,21 +550,34 @@ pub struct PasswordAuth { pub const DEFAULT_SSH_RETRIES: u8 = 6; pub const DEFAULT_SSH_TIMEOUT: u8 = 10; -#[derive(Debug)] +#[derive(Error, Debug)] pub enum SshCommandError { - Connection(std::io::Error), - Handshake(ssh2::Error), - Authentication(ssh2::Error), - ChannelSession(ssh2::Error), - Command(ssh2::Error), - ExitStatus(ssh2::Error), + #[error("ssh connection failed: {0}")] + Connection(#[source] std::io::Error), + #[error("ssh handshake failed: {0}")] + Handshake(#[source] ssh2::Error), + #[error("ssh authentication failed: {0}")] + Authentication(#[source] ssh2::Error), + #[error("ssh channel session failed: {0}")] + ChannelSession(#[source] ssh2::Error), + #[error("ssh command failed: {0}")] + Command(#[source] ssh2::Error), + #[error("retrieving exit status from ssh command failed: {0}")] + ExitStatus(#[source] ssh2::Error), + #[error("the exit code indicates failure: {0}")] NonZeroExitStatus(i32), - FileRead(std::io::Error), - FileMetadata(std::io::Error), - ScpSend(ssh2::Error), - WriteAll(std::io::Error), - SendEof(ssh2::Error), - WaitEof(ssh2::Error), + #[error("failed to read file: {0}")] + FileRead(#[source] std::io::Error), + #[error("failed to read metadata: {0}")] + FileMetadata(#[source] std::io::Error), + #[error("scp send failed: {0}")] + ScpSend(#[source] ssh2::Error), + #[error("scp write failed: {0}")] + WriteAll(#[source] std::io::Error), + #[error("scp send EOF failed: {0}")] + SendEof(#[source] ssh2::Error), + #[error("scp wait EOF failed: {0}")] + WaitEof(#[source] ssh2::Error), } fn scp_to_guest_with_auth(