use std::time::Duration;
use tokio::net::TcpStream;
use crate::base::error::{TestError, TestsResult};
pub struct Runner {
host: String,
timeout: Duration,
}
impl Runner {
pub fn new(host: impl Into<String>, timeout: Duration) -> Self {
Self {
host: host.into(),
timeout,
}
}
pub async fn wait_healthy(&self) -> TestsResult<()> {
let addr = self.addr()?;
let start = std::time::Instant::now();
loop {
if start.elapsed() > self.timeout {
return Err(TestError::Timeout(format!("MCP not ready at {}", addr)));
}
if TcpStream::connect(&addr).await.is_ok() {
return Ok(());
}
tokio::time::sleep(Duration::from_millis(500)).await;
}
}
pub fn wait_dead(&self) -> TestsResult<()> {
let addr = self.addr()?;
let start = std::time::Instant::now();
loop {
if start.elapsed() > Duration::from_secs(1) {
return Err(TestError::Timeout(format!(
"MCP server at {} did not stop after 1s",
addr
)));
}
if std::net::TcpStream::connect(&addr).is_err() {
return Ok(());
}
std::thread::sleep(Duration::from_millis(50));
}
}
fn addr(&self) -> TestsResult<String> {
self.host
.trim_start_matches("http://")
.trim_start_matches("https://")
.split('/')
.next()
.map(String::from)
.ok_or_else(|| TestError::Setup(format!("Invalid mcp_host: {}", self.host)))
}
}