#![allow(dead_code)]
use mubit_sdk::{Client, ClientConfig, TransportMode};
use serde_json::{json, Value};
use std::env;
use std::error::Error;
use std::time::{SystemTime, UNIX_EPOCH};
#[derive(Debug, Clone, Copy)]
pub struct ScenarioConfig {
pub expect_direct_search_enabled: bool,
}
impl ScenarioConfig {
pub fn from_env() -> Self {
Self {
expect_direct_search_enabled: env_bool("MUBIT_EXPECT_DIRECT_SEARCH_ENABLED", false),
}
}
}
pub fn boxed_error(message: impl Into<String>) -> Box<dyn Error> {
Box::new(std::io::Error::other(message.into()))
}
pub fn require(condition: bool, message: impl Into<String>) -> Result<(), Box<dyn Error>> {
if condition {
Ok(())
} else {
Err(boxed_error(message))
}
}
pub fn env_bool(name: &str, fallback: bool) -> bool {
let fallback_raw = if fallback { "1" } else { "0" };
let raw = env::var(name)
.unwrap_or_else(|_| fallback_raw.to_string())
.trim()
.to_ascii_lowercase();
matches!(raw.as_str(), "1" | "true" | "yes" | "on")
}
pub fn is_permission_denied_like(message: &str) -> bool {
let lowered = message.to_ascii_lowercase();
lowered.contains("permission denied")
|| lowered.contains("permissiondenied")
|| lowered.contains("403")
|| lowered.contains("disabled")
}
pub fn new_run_id(prefix: &str) -> String {
let ms = SystemTime::now()
.duration_since(UNIX_EPOCH)
.unwrap_or_default()
.as_millis();
let pid = std::process::id();
format!("{prefix}_{ms}_{pid}")
}
pub async fn create_client() -> Result<Client, Box<dyn Error>> {
let endpoint =
env::var("MUBIT_ENDPOINT").unwrap_or_else(|_| "http://127.0.0.1:3000".to_string());
let grpc_endpoint =
env::var("MUBIT_GRPC_ENDPOINT").unwrap_or_else(|_| "127.0.0.1:50051".to_string());
let timeout_ms = env::var("MUBIT_TIMEOUT_MS")
.ok()
.and_then(|raw| raw.parse::<u64>().ok())
.unwrap_or(30_000);
let api_key =
env::var("MUBIT_API_KEY").map_err(|_| boxed_error("MUBIT_API_KEY must be set"))?;
let mut cfg = ClientConfig::new(endpoint).transport("http");
cfg.grpc_endpoint = Some(grpc_endpoint);
cfg.timeout_ms = timeout_ms;
cfg.api_key = Some(api_key.clone());
let client = Client::new(cfg)?;
client.set_transport(TransportMode::Http);
client.set_api_key(Some(api_key));
let _ = client.auth.health().await?;
Ok(client)
}
pub async fn cleanup_run(client: &Client, run_id: &str) -> bool {
let control_ok = client
.delete_run(json!({ "run_id": run_id }))
.await
.is_ok();
let core_ok = match client.core.delete_run(json!({ "run_id": run_id })).await {
Ok(_) => true,
Err(err) => is_permission_denied_like(&err.to_string()),
};
control_ok && core_ok
}
pub fn print_summary(
name: &str,
passed: bool,
detail: &str,
metrics: &Value,
duration_sec: f64,
cleanup_ok: bool,
) {
println!(
"[{}] {} {:.2}s {}",
if passed { "PASS" } else { "FAIL" },
name,
duration_sec,
detail
);
if let Some(map) = metrics.as_object() {
if !map.is_empty() {
println!("metrics: {}", metrics);
}
}
println!("cleanup: {}", if cleanup_ok { "PASS" } else { "FAIL" });
}