From 591ca6743565bf808d56bfda4fbf051899dadcd8 Mon Sep 17 00:00:00 2001 From: Solomon Jacobs Date: Mon, 11 Dec 2023 14:35:47 +0100 Subject: [PATCH] test termination 13: Don't depend on `Suite` In order to write an integration test, the relevant functionality needs to be part of the libary crate `robotmk`. The goal is to move `run_attempts_until_succesful`. With this change, `run_attempts_until_succesful` is moved to the library crate `robotmk`. CMK-15433 --- .../src/bin/scheduler/scheduling/suites.rs | 134 +----------------- v2/robotmk/src/lib.rs | 1 + v2/robotmk/src/suites.rs | 123 ++++++++++++++++ 3 files changed, 130 insertions(+), 128 deletions(-) diff --git a/v2/robotmk/src/bin/scheduler/scheduling/suites.rs b/v2/robotmk/src/bin/scheduler/scheduling/suites.rs index aed2180c..35a9e455 100644 --- a/v2/robotmk/src/bin/scheduler/scheduling/suites.rs +++ b/v2/robotmk/src/bin/scheduler/scheduling/suites.rs @@ -1,19 +1,12 @@ use crate::internal_config::Suite; -use robotmk::environment::{Environment, ResultCode}; -use robotmk::results::{AttemptOutcome, AttemptsConfig, SuiteExecutionReport}; -use robotmk::rf::{ - rebot::Rebot, - robot::{Attempt, Robot}, -}; -use robotmk::sessions::session::{RunOutcome, RunSpec, Session}; +use robotmk::results::{AttemptsConfig, SuiteExecutionReport}; +use robotmk::suites::run_attempts_with_rebot; -use anyhow::{bail, Context, Result}; -use camino::{Utf8Path, Utf8PathBuf}; +use anyhow::{Context, Result}; use chrono::Utc; -use log::{debug, error}; +use log::debug; use robotmk::section::WritePiggybackSection; use std::fs::create_dir_all; -use tokio_util::sync::CancellationToken; pub fn run_suite(suite: &Suite) -> Result<()> { debug!("Running suite {}", &suite.id); @@ -39,7 +32,7 @@ fn produce_suite_results(suite: &Suite) -> Result { output_directory ))?; - let (attempt_outcomes, output_paths) = run_attempts_until_succesful( + let (attempt_outcomes, rebot) = run_attempts_with_rebot( &suite.robot, &suite.id, &suite.environment, @@ -52,19 +45,7 @@ fn produce_suite_results(suite: &Suite) -> Result { Ok(SuiteExecutionReport { suite_id: suite.id.clone(), attempts: attempt_outcomes, - rebot: if output_paths.is_empty() { - None - } else { - Some( - Rebot { - environment: &suite.environment, - input_paths: &output_paths, - path_xml: &output_directory.join("rebot.xml"), - path_html: &output_directory.join("rebot.html"), - } - .rebot(), - ) - }, + rebot, config: AttemptsConfig { interval: suite.execution_interval_seconds, timeout: suite.timeout, @@ -72,106 +53,3 @@ fn produce_suite_results(suite: &Suite) -> Result { }, }) } - -fn run_attempts_until_succesful( - robot: &Robot, - id: &str, - environment: &Environment, - session: &Session, - timeout: u64, - cancellation_token: &CancellationToken, - output_directory: &Utf8Path, -) -> Result<(Vec, Vec)> { - let mut outcomes = vec![]; - let mut output_paths: Vec = vec![]; - - for attempt in robot.attempts(output_directory) { - let (outcome, output_path) = run_attempt( - id, - environment, - session, - timeout, - attempt, - cancellation_token, - output_directory, - )?; - let success = matches!(&outcome, &AttemptOutcome::AllTestsPassed); - outcomes.push(outcome); - if let Some(output_path) = output_path { - output_paths.push(output_path); - } - if success { - break; - } - } - - Ok((outcomes, output_paths)) -} - -fn run_attempt( - id: &str, - environment: &Environment, - session: &Session, - timeout: u64, - attempt: Attempt, - cancellation_token: &CancellationToken, - output_directory: &Utf8Path, -) -> Result<(AttemptOutcome, Option)> { - let log_message_start = format!("Suite {}, attempt {}", id, attempt.index); - - let run_outcome = match session.run(&RunSpec { - id: &format!("robotmk_suite_{}_attempt_{}", id, attempt.index), - command_spec: &environment.wrap(attempt.command_spec), - base_path: &output_directory.join(attempt.index.to_string()), - timeout, - cancellation_token, - }) { - Ok(run_outcome) => run_outcome, - Err(error_) => { - error!("{log_message_start}: {error_:?}"); - return Ok((AttemptOutcome::OtherError(format!("{error_:?}")), None)); - } - }; - let exit_code = match run_outcome { - RunOutcome::Exited(exit_code) => exit_code, - RunOutcome::TimedOut => { - error!("{log_message_start}: timed out"); - return Ok((AttemptOutcome::TimedOut, None)); - } - RunOutcome::Terminated => bail!("Terminated"), - }; - let exit_code = match exit_code { - Some(exit_code) => exit_code, - None => { - error!("{log_message_start}: failed to query exit code"); - return Ok(( - AttemptOutcome::OtherError( - "Failed to query exit code of Robot Framework call".into(), - ), - None, - )); - } - }; - match environment.create_result_code(exit_code) { - ResultCode::AllTestsPassed => { - debug!("{log_message_start}: all tests passed"); - Ok(( - AttemptOutcome::AllTestsPassed, - Some(attempt.output_xml_file), - )) - } - ResultCode::EnvironmentFailed => { - error!("{log_message_start}: environment failure"); - Ok((AttemptOutcome::EnvironmentFailure, None)) - } - ResultCode::RobotCommandFailed => { - if attempt.output_xml_file.exists() { - debug!("{log_message_start}: some tests failed"); - Ok((AttemptOutcome::TestFailures, Some(attempt.output_xml_file))) - } else { - error!("{log_message_start}: Robot Framework failure (no output)"); - Ok((AttemptOutcome::RobotFrameworkFailure, None)) - } - } - } -} diff --git a/v2/robotmk/src/lib.rs b/v2/robotmk/src/lib.rs index 76622b48..5a934458 100644 --- a/v2/robotmk/src/lib.rs +++ b/v2/robotmk/src/lib.rs @@ -7,4 +7,5 @@ pub mod results; pub mod rf; pub mod section; pub mod sessions; +pub mod suites; pub mod termination; diff --git a/v2/robotmk/src/suites.rs b/v2/robotmk/src/suites.rs index e69de29b..cc2f42bc 100644 --- a/v2/robotmk/src/suites.rs +++ b/v2/robotmk/src/suites.rs @@ -0,0 +1,123 @@ +use crate::environment::{Environment, ResultCode}; +use crate::results::{AttemptOutcome, RebotOutcome}; +use crate::rf::rebot::Rebot; +use crate::rf::robot::{Attempt, Robot}; +use crate::sessions::session::{RunOutcome, RunSpec, Session}; +use anyhow::{bail, Result}; +use camino::{Utf8Path, Utf8PathBuf}; +use log::{debug, error}; +use tokio_util::sync::CancellationToken; + +pub fn run_attempts_with_rebot( + robot: &Robot, + id: &str, + environment: &Environment, + session: &Session, + timeout: u64, + cancellation_token: &CancellationToken, + output_directory: &Utf8Path, +) -> Result<(Vec, Option)> { + let mut outcomes = vec![]; + let mut output_paths: Vec = vec![]; + + for attempt in robot.attempts(output_directory) { + let (outcome, output_path) = run_attempt( + id, + environment, + session, + timeout, + attempt, + cancellation_token, + output_directory, + )?; + let success = matches!(&outcome, &AttemptOutcome::AllTestsPassed); + outcomes.push(outcome); + if let Some(output_path) = output_path { + output_paths.push(output_path); + } + if success { + break; + } + } + + if output_paths.is_empty() { + return Ok((outcomes, None)); + } + let rebot = Rebot { + environment, + input_paths: &output_paths, + path_xml: &output_directory.join("rebot.xml"), + path_html: &output_directory.join("rebot.html"), + } + .rebot(); + + Ok((outcomes, Some(rebot))) +} + +fn run_attempt( + id: &str, + environment: &Environment, + session: &Session, + timeout: u64, + attempt: Attempt, + cancellation_token: &CancellationToken, + output_directory: &Utf8Path, +) -> Result<(AttemptOutcome, Option)> { + let log_message_start = format!("Suite {}, attempt {}", id, attempt.index); + + let run_outcome = match session.run(&RunSpec { + id: &format!("robotmk_suite_{}_attempt_{}", id, attempt.index), + command_spec: &environment.wrap(attempt.command_spec), + base_path: &output_directory.join(attempt.index.to_string()), + timeout, + cancellation_token, + }) { + Ok(run_outcome) => run_outcome, + Err(error_) => { + error!("{log_message_start}: {error_:?}"); + return Ok((AttemptOutcome::OtherError(format!("{error_:?}")), None)); + } + }; + let exit_code = match run_outcome { + RunOutcome::Exited(exit_code) => exit_code, + RunOutcome::TimedOut => { + error!("{log_message_start}: timed out"); + return Ok((AttemptOutcome::TimedOut, None)); + } + RunOutcome::Terminated => bail!("Terminated"), + }; + let exit_code = match exit_code { + Some(exit_code) => exit_code, + None => { + error!("{log_message_start}: failed to query exit code"); + return Ok(( + AttemptOutcome::OtherError( + "Failed to query exit code of Robot Framework call".into(), + ), + None, + )); + } + }; + match environment.create_result_code(exit_code) { + ResultCode::AllTestsPassed => { + debug!("{log_message_start}: all tests passed"); + Ok(( + AttemptOutcome::AllTestsPassed, + Some(attempt.output_xml_file), + )) + } + ResultCode::EnvironmentFailed => { + error!("{log_message_start}: environment failure"); + Ok((AttemptOutcome::EnvironmentFailure, None)) + } + ResultCode::RobotCommandFailed => { + if attempt.output_xml_file.exists() { + debug!("{log_message_start}: some tests failed"); + Ok((AttemptOutcome::TestFailures, Some(attempt.output_xml_file))) + } else { + error!("{log_message_start}: Robot Framework failure (no output)"); + Ok((AttemptOutcome::RobotFrameworkFailure, None)) + } + } + } +}