use std::{env, process::Command, thread, time::Duration};
use tonin_client::{PlatformClient, PlatformClientConfig};
fn run_command(cmd: &str, args: &[&str]) -> Result<String, Box<dyn std::error::Error>> {
let output = Command::new(cmd).args(args).output()?;
if !output.status.success() {
let stderr = String::from_utf8_lossy(&output.stderr);
return Err(format!("{} failed: {}", cmd, stderr).into());
}
Ok(String::from_utf8(output.stdout)?)
}
fn wait_for_healthy(
client: &PlatformClient,
env: &str,
service: &str,
max_attempts: u32,
) -> Result<(), Box<dyn std::error::Error>> {
for attempt in 1..=max_attempts {
let statuses = client.get_status(env)?;
if let Some(status) = statuses.iter().find(|s| s.service == service) {
if status.health == "healthy" {
println!("{}: healthy after {} attempts", service, attempt);
return Ok(());
}
println!(
"{}: health={}, attempt {}/{}",
service, status.health, attempt, max_attempts
);
} else {
println!(
"{}: not found in status, attempt {}/{}",
service, attempt, max_attempts
);
}
if attempt < max_attempts {
thread::sleep(Duration::from_secs(2));
}
}
Err(format!(
"Service {} did not become healthy after {} attempts",
service, max_attempts
)
.into())
}
#[test]
#[ignore] fn e2e_deploy_wave_ordering() {
if run_command("kubectl", &["cluster-info"]).is_err() {
eprintln!(
"WARNING: kubectl not available or k3d cluster not running. \
Start with: k3d cluster create tonin-e2e"
);
return; }
let workspace = env::var("TONIN_WORKSPACE").unwrap_or_else(|_| ".".to_string());
let config = PlatformClientConfig {
tonin_bin: "tonin".to_string(),
workspace,
};
let client = PlatformClient::with_config(config);
println!("\n=== Wave 1: Deploying users service ===");
match client.deploy_service("e2e-test", "users") {
Ok(result) => {
println!(
"Deploy result: status={}, digest={}",
result.status, result.digest
);
assert_eq!(
result.status, "success",
"users service deployment failed: {:?}",
result.message
);
if let Err(e) = wait_for_healthy(&client, "e2e-test", "users", 30) {
eprintln!("ERROR: {}", e);
panic!("users service failed to become healthy");
}
}
Err(e) => {
eprintln!("Failed to deploy users: {}", e);
panic!("Deploy failed");
}
}
println!("\n=== Wave 2: Deploying products service ===");
match client.deploy_service("e2e-test", "products") {
Ok(result) => {
println!(
"Deploy result: status={}, digest={}",
result.status, result.digest
);
assert_eq!(
result.status, "success",
"products service deployment failed: {:?}",
result.message
);
if let Err(e) = wait_for_healthy(&client, "e2e-test", "products", 30) {
eprintln!("ERROR: {}", e);
panic!("products service failed to become healthy");
}
}
Err(e) => {
eprintln!("Failed to deploy products: {}", e);
panic!("Deploy failed");
}
}
println!("\n=== Wave 3: Deploying orders service ===");
match client.deploy_service("e2e-test", "orders") {
Ok(result) => {
println!(
"Deploy result: status={}, digest={}",
result.status, result.digest
);
assert_eq!(
result.status, "success",
"orders service deployment failed: {:?}",
result.message
);
if let Err(e) = wait_for_healthy(&client, "e2e-test", "orders", 30) {
eprintln!("ERROR: {}", e);
panic!("orders service failed to become healthy");
}
}
Err(e) => {
eprintln!("Failed to deploy orders: {}", e);
panic!("Deploy failed");
}
}
println!("\n=== Final Status Verification ===");
match client.get_status("e2e-test") {
Ok(statuses) => {
for status in &statuses {
println!(
"Service: {}, Health: {}, Version: {:?}",
status.service, status.health, status.running_version
);
}
for service in &["users", "products", "orders"] {
let found = statuses
.iter()
.any(|s| s.service == *service && s.health == "healthy");
assert!(
found,
"Service {} not found or not healthy in final status",
service
);
}
println!("SUCCESS: All services deployed and healthy!");
}
Err(e) => {
panic!("Failed to get status: {}", e);
}
}
}
#[test]
#[ignore] fn e2e_rollback_on_failure() {
if run_command("kubectl", &["cluster-info"]).is_err() {
eprintln!("WARNING: kubectl not available; skipping rollback test");
return;
}
let workspace = env::var("TONIN_WORKSPACE").unwrap_or_else(|_| ".".to_string());
let config = PlatformClientConfig {
tonin_bin: "tonin".to_string(),
workspace,
};
let client = PlatformClient::with_config(config);
println!("\n=== Checking pre-deployment status ===");
let initial_statuses = match client.get_status("e2e-test") {
Ok(s) => s,
Err(e) => {
eprintln!("Cannot query initial status: {}", e);
return;
}
};
println!("Initial status: {} services", initial_statuses.len());
for status in &initial_statuses {
println!(" - {}: {}", status.service, status.health);
}
println!("\n=== Deploying users service ===");
if let Ok(result) = client.deploy_service("e2e-test", "users") {
println!("Deployment status: {}", result.status);
if result.status == "failed" {
println!("Deployment failed as expected, rolling back...");
if client.rollback_service("users", "e2e-test").is_ok() {
println!("Rollback succeeded");
if let Ok(final_statuses) = client.get_status("e2e-test")
&& let Some(status) = final_statuses.iter().find(|s| s.service == "users")
{
println!("Post-rollback status: {}", status.health);
}
}
}
}
}
#[test]
#[ignore] fn e2e_deployment_tracing() {
let workspace = env::var("TONIN_WORKSPACE").unwrap_or_else(|_| ".".to_string());
let config = PlatformClientConfig {
tonin_bin: "tonin".to_string(),
workspace,
};
let client = PlatformClient::with_config(config);
println!("\n=== Deployment Tracing Test ===");
println!("This test verifies deployment traces are captured via zradar baggage.");
match client.deploy_service("e2e-test", "users") {
Ok(result) => {
println!("Deployment succeeded: digest={}", result.digest);
println!(
"NOTE: To verify traces, query zradar with digest: {}",
result.digest
);
println!(
"Example: curl http://localhost:4317/api/traces?service=tonin&attribute=deployment.digest={}",
result.digest
);
}
Err(e) => {
eprintln!("Deployment failed: {}", e);
}
}
}