use std::io::{BufRead, BufReader, Write};
use std::os::unix::net::UnixStream;
use std::time::Duration;
use foundation_core::valtron::initialize_pool;
use foundation_proxy::config::ServiceConfig;
use foundation_proxy::{ProxyConfig, ProxyServer};
fn rpc(path: &str, request: &str) -> serde_json::Value {
let stream = UnixStream::connect(path).expect("connect control socket");
stream.set_read_timeout(Some(Duration::from_secs(5))).ok();
let mut writer = stream.try_clone().expect("clone stream");
writeln!(writer, "{request}").expect("write request");
writer.flush().ok();
let mut reader = BufReader::new(stream);
let mut line = String::new();
reader.read_line(&mut line).expect("read response");
serde_json::from_str(&line).expect("parse json")
}
#[test]
fn backend_drain_survives_restart() {
let _guard = initialize_pool(42, Some(4));
let tag = std::process::id();
let state_dir = std::env::temp_dir().join(format!("ewe_proxy_persist_{tag}"));
let _ = std::fs::remove_dir_all(&state_dir);
let state_dir = state_dir.to_string_lossy().into_owned();
let sock = std::env::temp_dir()
.join(format!("ewe_proxy_persist_{tag}.sock"))
.to_string_lossy()
.into_owned();
let build_config = || {
let svc = ServiceConfig::new("echo", "test.local")
.backend("http://127.0.0.1:19101")
.backend("http://127.0.0.1:19102");
ProxyConfig::new("test.local", "127.0.0.1")
.bind("127.0.0.1:0")
.control_socket(&sock)
.persist_to(&state_dir)
.service(svc)
};
{
let proxy = ProxyServer::start(build_config()).expect("start proxy 1");
std::thread::sleep(Duration::from_millis(200));
let resp = rpc(&sock, r#"{"command":"status"}"#);
assert_eq!(resp["data"]["draining"], 0, "nothing draining at first run: {resp}");
let resp = rpc(
&sock,
r#"{"command":"drain","params":{"service":"echo","url":"http://127.0.0.1:19101"}}"#,
);
assert_eq!(resp["ok"], true, "drain ok: {resp}");
proxy.shutdown();
}
{
let proxy = ProxyServer::start(build_config()).expect("start proxy 2");
std::thread::sleep(Duration::from_millis(200));
let resp = rpc(&sock, r#"{"command":"status"}"#);
assert_eq!(
resp["data"]["draining"], 1,
"the drained backend must be restored after restart: {resp}"
);
let resp = rpc(&sock, r#"{"command":"list"}"#);
let backends = resp["data"][0]["backends"].as_array().expect("backends array");
let drained = backends
.iter()
.find(|b| b["url"] == "http://127.0.0.1:19101")
.expect("backend present");
assert_eq!(drained["state"], "Draining", "restored backend is draining: {resp}");
proxy.shutdown();
}
let _ = std::fs::remove_dir_all(&state_dir);
}