From c7a98023829e88b19b85050714a3a1579d1bb956 Mon Sep 17 00:00:00 2001 From: Jean-Philippe Raynaud Date: Wed, 27 Nov 2024 15:25:19 +0100 Subject: [PATCH 1/8] feat: return dedicated error when devnet operations fails --- .../mithril-end-to-end/src/devnet/mod.rs | 2 +- .../mithril-end-to-end/src/devnet/runner.rs | 21 +++++++++++++------ 2 files changed, 16 insertions(+), 7 deletions(-) diff --git a/mithril-test-lab/mithril-end-to-end/src/devnet/mod.rs b/mithril-test-lab/mithril-end-to-end/src/devnet/mod.rs index 56cba14f58c..37b38d1f4a6 100644 --- a/mithril-test-lab/mithril-end-to-end/src/devnet/mod.rs +++ b/mithril-test-lab/mithril-end-to-end/src/devnet/mod.rs @@ -1,3 +1,3 @@ mod runner; -pub use runner::{Devnet, DevnetBootstrapArgs, DevnetTopology, PoolNode}; +pub use runner::{Devnet, DevnetBootstrapArgs, DevnetTopology, PoolNode, UnrecoverableDevnetError}; diff --git a/mithril-test-lab/mithril-end-to-end/src/devnet/runner.rs b/mithril-test-lab/mithril-end-to-end/src/devnet/runner.rs index caf04ce80dd..7e2547e386b 100644 --- a/mithril-test-lab/mithril-end-to-end/src/devnet/runner.rs +++ b/mithril-test-lab/mithril-end-to-end/src/devnet/runner.rs @@ -6,8 +6,13 @@ use std::fs::{self, read_to_string, File}; use std::io::Read; use std::path::{Path, PathBuf}; use std::process::Stdio; +use thiserror::Error; use tokio::process::Command; +#[derive(Error, Debug, PartialEq, Eq)] +#[error("Unrecoverable devnet error: `{0}`")] +pub struct UnrecoverableDevnetError(pub String); + #[derive(Debug, Clone, Default)] pub struct Devnet { artifacts_dir: PathBuf, @@ -211,7 +216,9 @@ impl Devnet { .with_context(|| "Error while starting the devnet")?; match status.code() { Some(0) => Ok(()), - Some(code) => Err(anyhow!("Run devnet exited with status code: {code}")), + Some(code) => Err(anyhow!(UnrecoverableDevnetError(format!( + "Run devnet exited with status code: {code}" + )))), None => Err(anyhow!("Run devnet terminated by signal")), } } @@ -258,7 +265,9 @@ impl Devnet { .with_context(|| "Error while delegating stakes to the pools")?; match status.code() { Some(0) => Ok(()), - Some(code) => Err(anyhow!("Delegating stakes exited with status code: {code}")), + Some(code) => Err(anyhow!(UnrecoverableDevnetError(format!( + "Delegating stakes exited with status code: {code}" + )))), None => Err(anyhow!("Delegating stakes terminated by signal")), } } @@ -282,9 +291,9 @@ impl Devnet { .with_context(|| "Error while writing era marker on chain")?; match status.code() { Some(0) => Ok(()), - Some(code) => Err(anyhow!( + Some(code) => Err(anyhow!(UnrecoverableDevnetError(format!( "Write era marker on chain exited with status code: {code}" - )), + )))), None => Err(anyhow!("Write era marker on chain terminated by signal")), } } @@ -308,9 +317,9 @@ impl Devnet { .with_context(|| "Error while to transferring funds on chain")?; match status.code() { Some(0) => Ok(()), - Some(code) => Err(anyhow!( + Some(code) => Err(anyhow!(UnrecoverableDevnetError(format!( "Transfer funds on chain exited with status code: {code}" - )), + )))), None => Err(anyhow!("Transfer funds on chain terminated by signal")), } } From e03bca1b01c677586541da37b985c391b5531200 Mon Sep 17 00:00:00 2001 From: Jean-Philippe Raynaud Date: Wed, 27 Nov 2024 15:26:58 +0100 Subject: [PATCH 2/8] feat: handle retryable errors in e2e test --- .../mithril-end-to-end/src/main.rs | 119 +++++++++++++++++- 1 file changed, 116 insertions(+), 3 deletions(-) diff --git a/mithril-test-lab/mithril-end-to-end/src/main.rs b/mithril-test-lab/mithril-end-to-end/src/main.rs index da51824c8c6..fe12487b546 100644 --- a/mithril-test-lab/mithril-end-to-end/src/main.rs +++ b/mithril-test-lab/mithril-end-to-end/src/main.rs @@ -3,8 +3,9 @@ use clap::{CommandFactory, Parser, Subcommand}; use slog::{Drain, Level, Logger}; use slog_scope::{error, info, warn}; use std::{ - fs, + fmt, fs, path::{Path, PathBuf}, + process::{ExitCode, Termination}, sync::Arc, time::Duration, }; @@ -18,6 +19,7 @@ use mithril_common::StdResult; use mithril_doc::GenerateDocCommands; use mithril_end_to_end::{ Devnet, DevnetBootstrapArgs, MithrilInfrastructure, MithrilInfrastructureConfig, RunOnly, Spec, + UnrecoverableDevnetError, }; /// Tests args @@ -152,8 +154,16 @@ enum EndToEndCommands { GenerateDoc(GenerateDocCommands), } -#[tokio::main] -async fn main() -> StdResult<()> { +fn main() -> AppResult { + tokio::runtime::Builder::new_multi_thread() + .enable_all() + .build() + .unwrap() + .block_on(async { main_exec().await }) + .into() +} + +async fn main_exec() -> StdResult<()> { let args = Args::parse(); let _guard = slog_scope::set_global_logger(build_logger(&args)); @@ -198,9 +208,66 @@ async fn main() -> StdResult<()> { app_stopper.stop().await; join_set.shutdown().await; + res } +#[derive(Debug)] +enum AppResult { + Success(), + UnretryableError(anyhow::Error), + RetryableError(anyhow::Error), +} + +impl AppResult { + fn exit_code(&self) -> ExitCode { + match self { + AppResult::Success() => ExitCode::SUCCESS, + AppResult::UnretryableError(_) => ExitCode::FAILURE, + AppResult::RetryableError(_) => ExitCode::from(2), + } + } +} + +impl fmt::Display for AppResult { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + match self { + AppResult::Success() => write!(f, "Success"), + AppResult::UnretryableError(error) => write!(f, "Error(Unretryable): {error:?}"), + AppResult::RetryableError(error) => write!(f, "Error(Retryable): {error:?}"), + } + } +} + +impl Termination for AppResult { + fn report(self) -> ExitCode { + let exit_code = self.exit_code(); + println!(" "); + println!("----------------------------------------------------------------------------------------------------"); + println!("Mithril End to End test outcome:"); + println!("----------------------------------------------------------------------------------------------------"); + println!("{self}"); + println!("{exit_code:?}"); + + exit_code + } +} + +impl From> for AppResult { + fn from(result: StdResult<()>) -> Self { + match result { + Ok(()) => AppResult::Success(), + Err(error) => { + if error.is::() { + AppResult::RetryableError(error) + } else { + AppResult::UnretryableError(error) + } + } + } + } +} + struct App { devnet: Arc>>, infrastructure: Arc>>, @@ -366,3 +433,49 @@ fn with_gracefull_shutdown(join_set: &mut JoinSet>) { .inspect(|()| warn!("Received SIGQUIT")) }); } + +#[cfg(test)] +mod tests { + use super::*; + + #[test] + fn app_result_exit_code() { + let expected_exit_code = ExitCode::SUCCESS; + let exit_code = AppResult::Success().exit_code(); + assert_eq!( + format!("{:?}", expected_exit_code), + format!("{:?}", exit_code) + ); + + let expected_exit_code = ExitCode::FAILURE; + let exit_code = AppResult::UnretryableError(anyhow::anyhow!("an error")).exit_code(); + assert_eq!( + format!("{:?}", expected_exit_code), + format!("{:?}", exit_code) + ); + + let expected_exit_code = ExitCode::from(2); + let exit_code = AppResult::RetryableError(anyhow::anyhow!("an error")).exit_code(); + assert_eq!( + format!("{:?}", expected_exit_code), + format!("{:?}", exit_code) + ); + } + + #[test] + fn app_result_conversion() { + assert!(matches!(AppResult::from(Ok(())), AppResult::Success())); + + assert!(matches!( + AppResult::from(Err(anyhow!(UnrecoverableDevnetError( + "an error".to_string() + )))), + AppResult::RetryableError(_) + )); + + assert!(matches!( + AppResult::from(Err(anyhow!("an error"))), + AppResult::UnretryableError(_) + )); + } +} From d01eb728955e7055468561873e54dadb63663b1d Mon Sep 17 00:00:00 2001 From: Jean-Philippe Raynaud Date: Wed, 27 Nov 2024 16:08:33 +0100 Subject: [PATCH 3/8] feat: implement retries in e2e test in CI --- .github/workflows/ci.yml | 47 ++++++++++++++++++++++++---------------- 1 file changed, 28 insertions(+), 19 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index fe11f788f04..9b756fdaa4e 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -347,25 +347,34 @@ jobs: mkdir artifacts - name: Test - run: | - cat > ./mithril-end-to-end.sh << EOF - #!/bin/bash - set -x - ./mithril-end-to-end -vvv \\ - --bin-directory ./bin \\ - --work-directory=./artifacts \\ - --devnet-scripts-directory=./mithril-test-lab/mithril-devnet \\ - --mithril-era=${{ matrix.era }} \\ - --cardano-node-version ${{ matrix.cardano_node_version }} \\ - --cardano-hard-fork-latest-era-at-epoch ${{ matrix.hard_fork_latest_era_at_epoch }} ${{ matrix.extra_args }} \\ - EOF - # If there is a next era, we need to specify it with '--mithril-next-era' - if [[ "${{ matrix.next_era }}" != "" ]]; then - echo " --mithril-next-era=${{ matrix.next_era }}" >> ./mithril-end-to-end.sh - fi - chmod u+x ./mithril-end-to-end.sh - ./mithril-end-to-end.sh - rm ./mithril-end-to-end.sh + uses: nick-fields/retry@v3 + with: + shell: bash + max_attempts: 3 + retry_on_exit_code: 2 + timeout_minutes: 10 + warning_on_retry: true + command: | + cat > ./mithril-end-to-end.sh << EOF + #!/bin/bash + set -x + ./mithril-end-to-end -vvv \\ + --bin-directory ./bin \\ + --work-directory=./artifacts \\ + --devnet-scripts-directory=./mithril-test-lab/mithril-devnet \\ + --mithril-era=${{ matrix.era }} \\ + --cardano-node-version ${{ matrix.cardano_node_version }} \\ + --cardano-hard-fork-latest-era-at-epoch ${{ matrix.hard_fork_latest_era_at_epoch }} ${{ matrix.extra_args }} \\ + EOF + # If there is a next era, we need to specify it with '--mithril-next-era' + if [[ "${{ matrix.next_era }}" != "" ]]; then + echo " --mithril-next-era=${{ matrix.next_era }}" >> ./mithril-end-to-end.sh + fi + chmod u+x ./mithril-end-to-end.sh + ./mithril-end-to-end.sh + EXIT_CODE=$? + rm ./mithril-end-to-end.sh + exit $EXIT_CODE - name: Upload E2E Tests Artifacts if: ${{ failure() }} From 79e81f3e828b1a7eebb5e04e0cfadc6ead406d62 Mon Sep 17 00:00:00 2001 From: Jean-Philippe Raynaud Date: Wed, 27 Nov 2024 16:09:11 +0100 Subject: [PATCH 4/8] feat: implement retries in e2e test in backward compatibility workflow --- .github/workflows/backward-compatibility.yml | 35 +++++++++++++------- 1 file changed, 23 insertions(+), 12 deletions(-) diff --git a/.github/workflows/backward-compatibility.yml b/.github/workflows/backward-compatibility.yml index a554b4f7321..6e66301db3a 100644 --- a/.github/workflows/backward-compatibility.yml +++ b/.github/workflows/backward-compatibility.yml @@ -119,18 +119,29 @@ jobs: mkdir artifacts - name: Run E2E tests - shell: bash - run: | - ./mithril-binaries/e2e/mithril-end-to-end -vvv \ - --bin-directory ./mithril-binaries/e2e \ - --work-directory=./artifacts \ - --devnet-scripts-directory=./mithril-test-lab/mithril-devnet \ - --cardano-node-version ${{ matrix.cardano_node_version }} \ - --cardano-slot-length 0.25 \ - --cardano-epoch-length 45.0 \ - --signed-entity-types ${{ needs.prepare-env-variables.outputs.signed-entity-types }} \ - && echo "SUCCESS=true" >> $GITHUB_ENV \ - || (echo "SUCCESS=false" >> $GITHUB_ENV && exit 1) + uses: nick-fields/retry@v3 + with: + shell: bash + max_attempts: 3 + retry_on_exit_code: 2 + timeout_minutes: 10 + warning_on_retry: true + command: | + ./mithril-binaries/e2e/mithril-end-to-end -vvv \ + --bin-directory ./mithril-binaries/e2e \ + --work-directory=./artifacts \ + --devnet-scripts-directory=./mithril-test-lab/mithril-devnet \ + --cardano-node-version ${{ matrix.cardano_node_version }} \ + --cardano-slot-length 0.25 \ + --cardano-epoch-length 45.0 \ + --signed-entity-types ${{ needs.prepare-env-variables.outputs.signed-entity-types }} + EXIT_CODE=$? + if [ $EXIT_CODE -eq 0 ]; then + echo "SUCCESS=true" >> $GITHUB_ENV + else + echo "SUCCESS=false" >> $GITHUB_ENV + fi + exit $EXIT_CODE - name: Define the JSON file name for the test result shell: bash From e7bd46ed30756a32f965860e606615476ad86917 Mon Sep 17 00:00:00 2001 From: Jean-Philippe Raynaud Date: Thu, 28 Nov 2024 16:24:24 +0100 Subject: [PATCH 5/8] chore: apply style review comments --- mithril-test-lab/mithril-end-to-end/src/main.rs | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/mithril-test-lab/mithril-end-to-end/src/main.rs b/mithril-test-lab/mithril-end-to-end/src/main.rs index fe12487b546..1e5f67439a6 100644 --- a/mithril-test-lab/mithril-end-to-end/src/main.rs +++ b/mithril-test-lab/mithril-end-to-end/src/main.rs @@ -243,11 +243,10 @@ impl Termination for AppResult { fn report(self) -> ExitCode { let exit_code = self.exit_code(); println!(" "); - println!("----------------------------------------------------------------------------------------------------"); + println!("{:-^100}", ""); println!("Mithril End to End test outcome:"); - println!("----------------------------------------------------------------------------------------------------"); + println!("{:-^100}", ""); println!("{self}"); - println!("{exit_code:?}"); exit_code } From 7e4c6d75bd9c44c74ed236066db906a13f5f28d3 Mon Sep 17 00:00:00 2001 From: Jean-Philippe Raynaud Date: Thu, 28 Nov 2024 16:25:23 +0100 Subject: [PATCH 6/8] chore: better naming for caught devnet retryable error --- .../mithril-end-to-end/src/devnet/mod.rs | 2 +- .../mithril-end-to-end/src/devnet/runner.rs | 12 ++++++------ mithril-test-lab/mithril-end-to-end/src/main.rs | 10 ++++------ 3 files changed, 11 insertions(+), 13 deletions(-) diff --git a/mithril-test-lab/mithril-end-to-end/src/devnet/mod.rs b/mithril-test-lab/mithril-end-to-end/src/devnet/mod.rs index 37b38d1f4a6..551593c489e 100644 --- a/mithril-test-lab/mithril-end-to-end/src/devnet/mod.rs +++ b/mithril-test-lab/mithril-end-to-end/src/devnet/mod.rs @@ -1,3 +1,3 @@ mod runner; -pub use runner::{Devnet, DevnetBootstrapArgs, DevnetTopology, PoolNode, UnrecoverableDevnetError}; +pub use runner::{Devnet, DevnetBootstrapArgs, DevnetTopology, PoolNode, RetryableDevnetError}; diff --git a/mithril-test-lab/mithril-end-to-end/src/devnet/runner.rs b/mithril-test-lab/mithril-end-to-end/src/devnet/runner.rs index 7e2547e386b..c2312b9b156 100644 --- a/mithril-test-lab/mithril-end-to-end/src/devnet/runner.rs +++ b/mithril-test-lab/mithril-end-to-end/src/devnet/runner.rs @@ -10,8 +10,8 @@ use thiserror::Error; use tokio::process::Command; #[derive(Error, Debug, PartialEq, Eq)] -#[error("Unrecoverable devnet error: `{0}`")] -pub struct UnrecoverableDevnetError(pub String); +#[error("Retryable devnet error: `{0}`")] +pub struct RetryableDevnetError(pub String); #[derive(Debug, Clone, Default)] pub struct Devnet { @@ -216,7 +216,7 @@ impl Devnet { .with_context(|| "Error while starting the devnet")?; match status.code() { Some(0) => Ok(()), - Some(code) => Err(anyhow!(UnrecoverableDevnetError(format!( + Some(code) => Err(anyhow!(RetryableDevnetError(format!( "Run devnet exited with status code: {code}" )))), None => Err(anyhow!("Run devnet terminated by signal")), @@ -265,7 +265,7 @@ impl Devnet { .with_context(|| "Error while delegating stakes to the pools")?; match status.code() { Some(0) => Ok(()), - Some(code) => Err(anyhow!(UnrecoverableDevnetError(format!( + Some(code) => Err(anyhow!(RetryableDevnetError(format!( "Delegating stakes exited with status code: {code}" )))), None => Err(anyhow!("Delegating stakes terminated by signal")), @@ -291,7 +291,7 @@ impl Devnet { .with_context(|| "Error while writing era marker on chain")?; match status.code() { Some(0) => Ok(()), - Some(code) => Err(anyhow!(UnrecoverableDevnetError(format!( + Some(code) => Err(anyhow!(RetryableDevnetError(format!( "Write era marker on chain exited with status code: {code}" )))), None => Err(anyhow!("Write era marker on chain terminated by signal")), @@ -317,7 +317,7 @@ impl Devnet { .with_context(|| "Error while to transferring funds on chain")?; match status.code() { Some(0) => Ok(()), - Some(code) => Err(anyhow!(UnrecoverableDevnetError(format!( + Some(code) => Err(anyhow!(RetryableDevnetError(format!( "Transfer funds on chain exited with status code: {code}" )))), None => Err(anyhow!("Transfer funds on chain terminated by signal")), diff --git a/mithril-test-lab/mithril-end-to-end/src/main.rs b/mithril-test-lab/mithril-end-to-end/src/main.rs index 1e5f67439a6..77efedd3725 100644 --- a/mithril-test-lab/mithril-end-to-end/src/main.rs +++ b/mithril-test-lab/mithril-end-to-end/src/main.rs @@ -18,8 +18,8 @@ use tokio::{ use mithril_common::StdResult; use mithril_doc::GenerateDocCommands; use mithril_end_to_end::{ - Devnet, DevnetBootstrapArgs, MithrilInfrastructure, MithrilInfrastructureConfig, RunOnly, Spec, - UnrecoverableDevnetError, + Devnet, DevnetBootstrapArgs, MithrilInfrastructure, MithrilInfrastructureConfig, + RetryableDevnetError, RunOnly, Spec, }; /// Tests args @@ -257,7 +257,7 @@ impl From> for AppResult { match result { Ok(()) => AppResult::Success(), Err(error) => { - if error.is::() { + if error.is::() { AppResult::RetryableError(error) } else { AppResult::UnretryableError(error) @@ -466,9 +466,7 @@ mod tests { assert!(matches!(AppResult::from(Ok(())), AppResult::Success())); assert!(matches!( - AppResult::from(Err(anyhow!(UnrecoverableDevnetError( - "an error".to_string() - )))), + AppResult::from(Err(anyhow!(RetryableDevnetError("an error".to_string())))), AppResult::RetryableError(_) )); From 6fd68f146c3f825e93770f6650915ed867a8cf36 Mon Sep 17 00:00:00 2001 From: Jean-Philippe Raynaud Date: Fri, 29 Nov 2024 11:05:35 +0100 Subject: [PATCH 7/8] feat: support cancellation in e2e test app result --- .../mithril-end-to-end/src/main.rs | 61 ++++++++++--------- 1 file changed, 32 insertions(+), 29 deletions(-) diff --git a/mithril-test-lab/mithril-end-to-end/src/main.rs b/mithril-test-lab/mithril-end-to-end/src/main.rs index 77efedd3725..0a6e6e69228 100644 --- a/mithril-test-lab/mithril-end-to-end/src/main.rs +++ b/mithril-test-lab/mithril-end-to-end/src/main.rs @@ -1,7 +1,7 @@ use anyhow::{anyhow, Context}; use clap::{CommandFactory, Parser, Subcommand}; use slog::{Drain, Level, Logger}; -use slog_scope::{error, info, warn}; +use slog_scope::{error, info}; use std::{ fmt, fs, path::{Path, PathBuf}, @@ -9,6 +9,7 @@ use std::{ sync::Arc, time::Duration, }; +use thiserror::Error; use tokio::{ signal::unix::{signal, SignalKind}, sync::Mutex, @@ -217,13 +218,14 @@ enum AppResult { Success(), UnretryableError(anyhow::Error), RetryableError(anyhow::Error), + Cancelled(anyhow::Error), } impl AppResult { fn exit_code(&self) -> ExitCode { match self { AppResult::Success() => ExitCode::SUCCESS, - AppResult::UnretryableError(_) => ExitCode::FAILURE, + AppResult::UnretryableError(_) | AppResult::Cancelled(_) => ExitCode::FAILURE, AppResult::RetryableError(_) => ExitCode::from(2), } } @@ -235,6 +237,7 @@ impl fmt::Display for AppResult { AppResult::Success() => write!(f, "Success"), AppResult::UnretryableError(error) => write!(f, "Error(Unretryable): {error:?}"), AppResult::RetryableError(error) => write!(f, "Error(Retryable): {error:?}"), + AppResult::Cancelled(error) => write!(f, "Cancelled: {error:?}"), } } } @@ -259,6 +262,8 @@ impl From> for AppResult { Err(error) => { if error.is::() { AppResult::RetryableError(error) + } else if error.is::() { + AppResult::Cancelled(error) } else { AppResult::UnretryableError(error) } @@ -404,32 +409,30 @@ fn create_workdir_if_not_exist_clean_otherwise(work_dir: &Path) { fs::create_dir(work_dir).expect("Work dir creation failure"); } +#[derive(Error, Debug, PartialEq, Eq)] +#[error("Signal received: `{0}`")] +pub struct SignalError(pub String); + fn with_gracefull_shutdown(join_set: &mut JoinSet>) { join_set.spawn(async move { let mut sigterm = signal(SignalKind::terminate()).expect("Failed to create SIGTERM signal"); - sigterm - .recv() - .await - .ok_or(anyhow!("Failed to receive SIGTERM")) - .inspect(|()| warn!("Received SIGTERM")) + sigterm.recv().await; + + Err(anyhow!(SignalError("SIGTERM".to_string()))) }); join_set.spawn(async move { let mut sigterm = signal(SignalKind::interrupt()).expect("Failed to create SIGINT signal"); - sigterm - .recv() - .await - .ok_or(anyhow!("Failed to receive SIGINT")) - .inspect(|()| warn!("Received SIGINT")) + sigterm.recv().await; + + Err(anyhow!(SignalError("SIGINT".to_string()))) }); join_set.spawn(async move { let mut sigterm = signal(SignalKind::quit()).expect("Failed to create SIGQUIT signal"); - sigterm - .recv() - .await - .ok_or(anyhow!("Failed to receive SIGQUIT")) - .inspect(|()| warn!("Received SIGQUIT")) + sigterm.recv().await; + + Err(anyhow!(SignalError("SIGQUIT".to_string()))) }); } @@ -441,24 +444,19 @@ mod tests { fn app_result_exit_code() { let expected_exit_code = ExitCode::SUCCESS; let exit_code = AppResult::Success().exit_code(); - assert_eq!( - format!("{:?}", expected_exit_code), - format!("{:?}", exit_code) - ); + assert_eq!(expected_exit_code, exit_code); let expected_exit_code = ExitCode::FAILURE; let exit_code = AppResult::UnretryableError(anyhow::anyhow!("an error")).exit_code(); - assert_eq!( - format!("{:?}", expected_exit_code), - format!("{:?}", exit_code) - ); + assert_eq!(expected_exit_code, exit_code); let expected_exit_code = ExitCode::from(2); let exit_code = AppResult::RetryableError(anyhow::anyhow!("an error")).exit_code(); - assert_eq!( - format!("{:?}", expected_exit_code), - format!("{:?}", exit_code) - ); + assert_eq!(expected_exit_code, exit_code); + + let expected_exit_code = ExitCode::FAILURE; + let exit_code = AppResult::Cancelled(anyhow::anyhow!("an error")).exit_code(); + assert_eq!(expected_exit_code, exit_code); } #[test] @@ -474,5 +472,10 @@ mod tests { AppResult::from(Err(anyhow!("an error"))), AppResult::UnretryableError(_) )); + + assert!(matches!( + AppResult::from(Err(anyhow!(SignalError("an error".to_string())))), + AppResult::Cancelled(_) + )); } } From fcb728ee4325a2a9c99d9e6425741346ca39a344 Mon Sep 17 00:00:00 2001 From: Jean-Philippe Raynaud Date: Fri, 29 Nov 2024 11:07:30 +0100 Subject: [PATCH 8/8] chore: upgrade crate versions * mithril-end-to-end from `0.4.49` to `0.4.50` --- Cargo.lock | 2 +- mithril-test-lab/mithril-end-to-end/Cargo.toml | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index fb09294e4fc..7f20cb74582 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -3816,7 +3816,7 @@ dependencies = [ [[package]] name = "mithril-end-to-end" -version = "0.4.49" +version = "0.4.50" dependencies = [ "anyhow", "async-recursion", diff --git a/mithril-test-lab/mithril-end-to-end/Cargo.toml b/mithril-test-lab/mithril-end-to-end/Cargo.toml index 27a1425bbfb..ec16dab542a 100644 --- a/mithril-test-lab/mithril-end-to-end/Cargo.toml +++ b/mithril-test-lab/mithril-end-to-end/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "mithril-end-to-end" -version = "0.4.49" +version = "0.4.50" authors = { workspace = true } edition = { workspace = true } documentation = { workspace = true }