Skip to content

Commit

Permalink
test termination 13: move run_attempts_until_succesful
Browse files Browse the repository at this point in the history
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
  • Loading branch information
SoloJacobs committed Dec 11, 2023
1 parent 12eaf61 commit 7a55726
Show file tree
Hide file tree
Showing 3 changed files with 130 additions and 128 deletions.
134 changes: 6 additions & 128 deletions v2/robotmk/src/bin/scheduler/scheduling/suites.rs
Original file line number Diff line number Diff line change
@@ -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);
Expand All @@ -39,7 +32,7 @@ fn produce_suite_results(suite: &Suite) -> Result<SuiteExecutionReport> {
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,
Expand All @@ -52,126 +45,11 @@ fn produce_suite_results(suite: &Suite) -> Result<SuiteExecutionReport> {
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,
n_attempts_max: suite.robot.n_attempts_max,
},
})
}

fn run_attempts_until_succesful(
robot: &Robot,
id: &str,
environment: &Environment,
session: &Session,
timeout: u64,
cancellation_token: &CancellationToken,
output_directory: &Utf8Path,
) -> Result<(Vec<AttemptOutcome>, Vec<Utf8PathBuf>)> {
let mut outcomes = vec![];
let mut output_paths: Vec<Utf8PathBuf> = 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<Utf8PathBuf>)> {
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))
}
}
}
}
1 change: 1 addition & 0 deletions v2/robotmk/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -7,4 +7,5 @@ pub mod results;
pub mod rf;
pub mod section;
pub mod sessions;
pub mod suites;
pub mod termination;
123 changes: 123 additions & 0 deletions v2/robotmk/src/suites.rs
Original file line number Diff line number Diff line change
@@ -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<AttemptOutcome>, Option<RebotOutcome>)> {
let mut outcomes = vec![];
let mut output_paths: Vec<Utf8PathBuf> = 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<Utf8PathBuf>)> {
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))
}
}
}
}

0 comments on commit 7a55726

Please sign in to comment.