use std::{path::Path, str::FromStr, time::Instant};
use anyhow::Result;
use serde::Deserialize;
use tracing::{event, Level};
use super::{external_cmd::run_command, resmoke_suite::ResmokeSuiteConfig};
pub trait TestDiscovery: Send + Sync {
fn discover_tests(&self, suite_name: &str) -> Result<Vec<String>>;
fn get_suite_config(&self, suite_name: &str) -> Result<ResmokeSuiteConfig>;
fn get_multiversion_config(&self) -> Result<MultiversionConfig>;
}
#[derive(Debug, Clone)]
pub struct ResmokeProxy {
resmoke_cmd: String,
resmoke_script: Vec<String>,
}
impl ResmokeProxy {
pub fn new(resmoke_cmd: &str) -> Self {
let cmd_parts: Vec<_> = resmoke_cmd.split(' ').collect();
let cmd = cmd_parts[0];
let script = cmd_parts[1..].iter().map(|s| s.to_string()).collect();
Self {
resmoke_cmd: cmd.to_string(),
resmoke_script: script,
}
}
}
#[derive(Debug, Deserialize)]
#[allow(dead_code)]
struct TestDiscoveryOutput {
pub suite_name: String,
pub tests: Vec<String>,
}
impl TestDiscovery for ResmokeProxy {
fn discover_tests(&self, suite_name: &str) -> Result<Vec<String>> {
let mut cmd = vec![&*self.resmoke_cmd];
cmd.append(&mut self.resmoke_script.iter().map(|s| s.as_str()).collect());
cmd.append(&mut vec!["test-discovery", "--suite", suite_name]);
let start = Instant::now();
let cmd_output = run_command(&cmd).unwrap();
event!(
Level::INFO,
suite_name,
duration_ms = start.elapsed().as_millis() as u64,
"Resmoke test discovery finished"
);
let output: TestDiscoveryOutput = serde_yaml::from_str(&cmd_output)?;
Ok(output
.tests
.into_iter()
.filter(|f| Path::new(f).exists())
.collect())
}
fn get_suite_config(&self, suite_name: &str) -> Result<ResmokeSuiteConfig> {
let mut cmd = vec![&*self.resmoke_cmd];
cmd.append(&mut self.resmoke_script.iter().map(|s| s.as_str()).collect());
cmd.append(&mut vec!["suiteconfig", "--suite", suite_name]);
let cmd_output = run_command(&cmd).unwrap();
Ok(ResmokeSuiteConfig::from_str(&cmd_output)?)
}
fn get_multiversion_config(&self) -> Result<MultiversionConfig> {
MultiversionConfig::from_resmoke(&self.resmoke_cmd, &self.resmoke_script)
}
}
#[derive(Debug, Clone, Deserialize)]
pub struct MultiversionConfig {
pub last_versions: Vec<String>,
pub requires_fcv_tag: String,
pub requires_fcv_tag_lts: Option<String>,
pub requires_fcv_tag_continuous: Option<String>,
}
impl MultiversionConfig {
pub fn from_resmoke(cmd: &str, script: &[String]) -> Result<MultiversionConfig> {
let mut cmd = vec![cmd];
cmd.append(&mut script.iter().map(|s| s.as_str()).collect());
cmd.append(&mut vec!["multiversion-config"]);
let cmd_output = run_command(&cmd).unwrap();
Ok(serde_yaml::from_str(&cmd_output)?)
}
pub fn get_fcv_tags_for_lts(&self) -> String {
if let Some(requires_fcv_tag_lts) = &self.requires_fcv_tag_lts {
requires_fcv_tag_lts.clone()
} else {
self.requires_fcv_tag.clone()
}
}
pub fn get_fcv_tags_for_continuous(&self) -> String {
if let Some(requires_fcv_tag_continuous) = &self.requires_fcv_tag_continuous {
requires_fcv_tag_continuous.clone()
} else {
self.requires_fcv_tag.clone()
}
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_get_fcv_tags_for_lts_should_use_lts_if_provided() {
let mv_config = MultiversionConfig {
last_versions: vec![],
requires_fcv_tag: "fcv_fallback".to_string(),
requires_fcv_tag_lts: Some("fcv_lts_explicit".to_string()),
requires_fcv_tag_continuous: None,
};
assert_eq!(&mv_config.get_fcv_tags_for_lts(), "fcv_lts_explicit")
}
#[test]
fn test_get_fcv_tags_for_lts_should_fallback_if_no_lts_provided() {
let mv_config = MultiversionConfig {
last_versions: vec![],
requires_fcv_tag: "fcv_fallback".to_string(),
requires_fcv_tag_lts: None,
requires_fcv_tag_continuous: None,
};
assert_eq!(&mv_config.get_fcv_tags_for_lts(), "fcv_fallback")
}
#[test]
fn test_get_fcv_tags_for_continuous_should_use_continuous_if_provided() {
let mv_config = MultiversionConfig {
last_versions: vec![],
requires_fcv_tag: "fcv_fallback".to_string(),
requires_fcv_tag_lts: None,
requires_fcv_tag_continuous: Some("fcv_continuous_explicit".to_string()),
};
assert_eq!(
&mv_config.get_fcv_tags_for_continuous(),
"fcv_continuous_explicit"
)
}
#[test]
fn test_get_fcv_tags_for_continuous_should_fallback_if_no_continuous_provided() {
let mv_config = MultiversionConfig {
last_versions: vec![],
requires_fcv_tag: "fcv_fallback".to_string(),
requires_fcv_tag_lts: None,
requires_fcv_tag_continuous: None,
};
assert_eq!(&mv_config.get_fcv_tags_for_continuous(), "fcv_fallback")
}
}