Skip to content

Commit

Permalink
test termination 13: Don't depend on Suite
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 2a16cdf commit 4794f1b
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 4794f1b

Please sign in to comment.