use std::path::Path;
use serde::Deserialize;
use xshell::Shell;
use crate::environment::{
discover_features, get_workspace_packages, Package, PackageManifest, ProgressGuard,
};
#[derive(Debug, Deserialize, Default)]
#[serde(default)]
struct IntegrationConfig {
package: Option<String>,
versions: Option<Vec<String>>,
}
impl IntegrationConfig {
fn load(crate_dir: &Path) -> Result<Self, Box<dyn std::error::Error>> {
#[derive(serde::Deserialize, Default)]
struct RbmtTable {
#[serde(default)]
integration: IntegrationConfig,
}
let path = crate_dir.join("Cargo.toml");
if !path.exists() {
return Ok(Self::default());
}
let contents = std::fs::read_to_string(&path)?;
Ok(toml::from_str::<PackageManifest<RbmtTable>>(&contents)?
.package
.metadata
.rbmt
.integration)
}
fn package_name(&self) -> &str { self.package.as_deref().unwrap_or("bitcoind-tests") }
}
fn get_package_id(sh: &Shell, dir: &Path) -> Result<String, Box<dyn std::error::Error>> {
let _dir = sh.push_dir(dir);
let id = rbmt_cmd!(sh, "cargo pkgid").read()?;
Ok(id.trim().to_string())
}
pub fn run(sh: &Shell, packages: &[String]) -> Result<(), Box<dyn std::error::Error>> {
let packages = get_workspace_packages(sh, packages)?;
let _progress = ProgressGuard::new();
rbmt_eprintln!("Looking for integration tests in {} crate(s)", packages.len());
for package in packages {
let config = IntegrationConfig::load(Path::new(&package.dir))?;
let integration_dir = package.dir.join(config.package_name());
if !integration_dir.exists() {
continue;
}
if !integration_dir.join("Cargo.toml").exists() {
continue;
}
rbmt_eprintln!("Running integration tests for {}", package.name);
let _dir = sh.push_dir(&integration_dir);
let integration_package = Package {
name: config.package_name().to_string(),
dir: integration_dir.clone(),
id: get_package_id(sh, &integration_dir)?,
};
let available_versions = discover_features(sh, &integration_package)?;
if available_versions.is_empty() {
rbmt_eprintln!(" No version features found in Cargo.toml");
continue;
}
let versions_to_test: Vec<String> = if let Some(config_versions) = &config.versions {
let mut filtered = Vec::new();
for requested in config_versions {
if available_versions.contains(requested) {
filtered.push(requested.clone());
} else {
return Err(format!(
"Requested version '{}' not found in available versions: {}",
requested,
available_versions.join(", ")
)
.into());
}
}
filtered
} else {
available_versions
};
for version in &versions_to_test {
rbmt_eprintln!(" Testing with version: {}", version);
rbmt_cmd!(sh, "cargo --locked test --features={version}").run()?;
}
}
Ok(())
}