helper_handoff_feedback/support/
utils.rs1#![allow(dead_code)]
2
3use mubit_sdk::{Client, ClientConfig, TransportMode};
4use serde_json::{json, Value};
5use std::env;
6use std::error::Error;
7use std::time::{SystemTime, UNIX_EPOCH};
8
9#[derive(Debug, Clone, Copy)]
10pub struct ScenarioConfig {
11 pub expect_direct_search_enabled: bool,
12}
13
14impl ScenarioConfig {
15 pub fn from_env() -> Self {
16 Self {
17 expect_direct_search_enabled: env_bool("MUBIT_EXPECT_DIRECT_SEARCH_ENABLED", false),
18 }
19 }
20}
21
22pub fn boxed_error(message: impl Into<String>) -> Box<dyn Error> {
23 Box::new(std::io::Error::other(message.into()))
24}
25
26pub fn require(condition: bool, message: impl Into<String>) -> Result<(), Box<dyn Error>> {
27 if condition {
28 Ok(())
29 } else {
30 Err(boxed_error(message))
31 }
32}
33
34pub fn env_bool(name: &str, fallback: bool) -> bool {
35 let fallback_raw = if fallback { "1" } else { "0" };
36 let raw = env::var(name)
37 .unwrap_or_else(|_| fallback_raw.to_string())
38 .trim()
39 .to_ascii_lowercase();
40 matches!(raw.as_str(), "1" | "true" | "yes" | "on")
41}
42
43pub fn is_permission_denied_like(message: &str) -> bool {
44 let lowered = message.to_ascii_lowercase();
45 lowered.contains("permission denied")
46 || lowered.contains("permissiondenied")
47 || lowered.contains("403")
48 || lowered.contains("disabled")
49}
50
51pub fn new_run_id(prefix: &str) -> String {
52 let ms = SystemTime::now()
53 .duration_since(UNIX_EPOCH)
54 .unwrap_or_default()
55 .as_millis();
56 let pid = std::process::id();
57 format!("{prefix}_{ms}_{pid}")
58}
59
60pub async fn create_client() -> Result<Client, Box<dyn Error>> {
61 let endpoint =
62 env::var("MUBIT_ENDPOINT").unwrap_or_else(|_| "http://127.0.0.1:3000".to_string());
63 let grpc_endpoint =
64 env::var("MUBIT_GRPC_ENDPOINT").unwrap_or_else(|_| "127.0.0.1:50051".to_string());
65 let timeout_ms = env::var("MUBIT_TIMEOUT_MS")
66 .ok()
67 .and_then(|raw| raw.parse::<u64>().ok())
68 .unwrap_or(30_000);
69
70 let api_key =
71 env::var("MUBIT_API_KEY").map_err(|_| boxed_error("MUBIT_API_KEY must be set"))?;
72
73 let mut cfg = ClientConfig::new(endpoint).transport("http");
74 cfg.grpc_endpoint = Some(grpc_endpoint);
75 cfg.timeout_ms = timeout_ms;
76 cfg.api_key = Some(api_key.clone());
77
78 let client = Client::new(cfg)?;
79 client.set_transport(TransportMode::Http);
80 client.set_api_key(Some(api_key));
81
82 let _ = client.auth.health().await?;
83
84 Ok(client)
85}
86
87pub async fn cleanup_run(client: &Client, run_id: &str) -> bool {
88 let control_ok = client
89 .control
90 .delete_run(json!({ "run_id": run_id }))
91 .await
92 .is_ok();
93 let core_ok = match client.core.delete_run(json!({ "run_id": run_id })).await {
94 Ok(_) => true,
95 Err(err) => is_permission_denied_like(&err.to_string()),
96 };
97 control_ok && core_ok
98}
99
100pub fn print_summary(
101 name: &str,
102 passed: bool,
103 detail: &str,
104 metrics: &Value,
105 duration_sec: f64,
106 cleanup_ok: bool,
107) {
108 println!(
109 "[{}] {} {:.2}s {}",
110 if passed { "PASS" } else { "FAIL" },
111 name,
112 duration_sec,
113 detail
114 );
115 if let Some(map) = metrics.as_object() {
116 if !map.is_empty() {
117 println!("metrics: {}", metrics);
118 }
119 }
120 println!("cleanup: {}", if cleanup_ok { "PASS" } else { "FAIL" });
121}