#![allow(deprecated, clippy::unwrap_used, clippy::expect_used)]
use assert_cmd::cargo::CommandCargoExt;
use reqwest::Client;
use std::process::Command;
use std::time::Duration;
use tempfile::NamedTempFile;
use tokio::time::sleep;
#[tokio::test]
async fn test_epazote_integration() {
let mut server = mockito::Server::new_async().await;
let mock_url = server.url();
let _m = server
.mock("GET", "/health")
.with_status(200)
.create_async()
.await;
let config_content = format!(
r"
services:
test_service:
url: {mock_url}/health
every: 1s
expect:
status: 200
"
);
let config_file = NamedTempFile::new().expect("Failed to create temp file");
std::fs::write(config_file.path(), config_content).expect("Failed to write config");
let metrics_port = {
let listener = std::net::TcpListener::bind("127.0.0.1:0").unwrap();
listener.local_addr().unwrap().port()
};
let mut cmd = Command::cargo_bin("epazote").expect("Failed to find binary");
let mut child = cmd
.arg("-c")
.arg(config_file.path())
.arg("-p")
.arg(metrics_port.to_string())
.spawn()
.expect("Failed to start epazote");
let client = Client::new();
let metrics_url = format!("http://localhost:{metrics_port}/metrics");
let mut success = false;
for _ in 0..10 {
sleep(Duration::from_secs(1)).await;
if let Ok(response) = client.get(&metrics_url).send().await
&& response.status().is_success()
{
let text = response.text().await.unwrap_or_default();
println!("Metrics: {text}");
if text.contains(r#"epazote_status{service_name="test_service"} 1"#) {
success = true;
break;
}
}
}
let _ = child.kill(); let _ = child.wait();
assert!(
success,
"Failed to verify epazote metrics indicating success"
);
}
#[tokio::test]
async fn test_epazote_ssl_integration() {
let config_content = r"
services:
google_ssl:
url: https://www.google.com
every: 1s
expect:
status: 200
";
let config_file = NamedTempFile::new().expect("Failed to create temp file");
std::fs::write(config_file.path(), config_content).expect("Failed to write config");
let metrics_port = {
let listener = std::net::TcpListener::bind("127.0.0.1:0").unwrap();
listener.local_addr().unwrap().port()
};
let mut cmd = Command::cargo_bin("epazote").expect("Failed to find binary");
let mut child = cmd
.arg("-c")
.arg(config_file.path())
.arg("-p")
.arg(metrics_port.to_string())
.spawn()
.expect("Failed to start epazote");
let client = Client::new();
let metrics_url = format!("http://localhost:{metrics_port}/metrics");
let mut success = false;
for _ in 0..15 {
sleep(Duration::from_secs(1)).await;
if let Ok(response) = client.get(&metrics_url).send().await
&& response.status().is_success()
{
let text = response.text().await.unwrap_or_default();
if let Some(line) = text.lines().find(|l| {
l.contains(r#"epazote_ssl_cert_expiry_seconds{service_name="google_ssl"}"#)
&& !l.starts_with('#')
}) {
if let Some(val_str) = line.split_whitespace().last()
&& let Ok(val) = val_str.parse::<i64>()
&& val > 0
{
success = true;
break;
}
}
}
}
let _ = child.kill();
let _ = child.wait();
assert!(success, "Failed to verify epazote SSL metrics");
}
#[tokio::test]
async fn test_epazote_if_not_cmd_integration() {
let mut server = mockito::Server::new_async().await;
let mock_url = server.url();
let _m = server
.mock("GET", "/fail")
.with_status(500)
.create_async()
.await;
let marker_file = tempfile::NamedTempFile::new().expect("Failed to create marker file");
let marker_path = marker_file.path().to_owned();
std::fs::remove_file(&marker_path).expect("Failed to remove initial marker file");
let config_content = format!(
r"
services:
fail_service:
url: {mock_url}/fail
every: 1s
expect:
status: 200
if_not:
cmd: touch {}
",
marker_path.to_str().expect("Invalid marker path")
);
let config_file = NamedTempFile::new().expect("Failed to create config file");
std::fs::write(config_file.path(), config_content).expect("Failed to write config");
let metrics_port = {
let listener = std::net::TcpListener::bind("127.0.0.1:0").unwrap();
listener.local_addr().unwrap().port()
};
let mut cmd = Command::cargo_bin("epazote").expect("Failed to find binary");
let mut child = cmd
.arg("-c")
.arg(config_file.path())
.arg("-p")
.arg(metrics_port.to_string())
.spawn()
.expect("Failed to start epazote");
let mut success = false;
for _ in 0..10 {
sleep(Duration::from_secs(1)).await;
if marker_path.exists() {
success = true;
break;
}
}
let _ = child.kill();
let _ = child.wait();
assert!(
success,
"Fallback command was not executed (marker file not found)"
);
}
#[tokio::test]
async fn test_epazote_if_not_threshold_integration() {
let mut server = mockito::Server::new_async().await;
let mock_url = server.url();
let _m = server
.mock("GET", "/fail-threshold")
.with_status(500)
.create_async()
.await;
let marker_file = tempfile::NamedTempFile::new().expect("Failed to create marker file");
let marker_path = marker_file.path().to_owned();
std::fs::remove_file(&marker_path).expect("Failed to remove initial marker file");
let config_content = format!(
r"
services:
fail_service:
url: {mock_url}/fail-threshold
every: 1s
expect:
status: 200
if_not:
threshold: 3
stop: 1
cmd: touch {}
",
marker_path.to_str().expect("Invalid marker path")
);
let config_file = NamedTempFile::new().expect("Failed to create config file");
std::fs::write(config_file.path(), config_content).expect("Failed to write config");
let metrics_port = {
let listener = std::net::TcpListener::bind("127.0.0.1:0").unwrap();
listener.local_addr().unwrap().port()
};
let mut cmd = Command::cargo_bin("epazote").expect("Failed to find binary");
let mut child = cmd
.arg("-c")
.arg(config_file.path())
.arg("-p")
.arg(metrics_port.to_string())
.spawn()
.expect("Failed to start epazote");
sleep(Duration::from_secs(2)).await;
assert!(
!marker_path.exists(),
"Fallback command executed before threshold was reached"
);
let mut success = false;
for _ in 0..5 {
sleep(Duration::from_secs(1)).await;
if marker_path.exists() {
success = true;
break;
}
}
let _ = child.kill();
let _ = child.wait();
assert!(
success,
"Fallback command was not executed after threshold was reached"
);
}