use std::net::SocketAddr;
use std::sync::Arc;
use std::time::Duration;
use aa_gateway::storage::{SqliteBackend, SqliteConfig, StorageBackend};
use axum_server::Handle;
async fn open_test_backend(tmp: &tempfile::TempDir) -> Arc<dyn StorageBackend> {
let path = tmp.path().join("local.db");
let backend = SqliteBackend::open(&SqliteConfig { path })
.await
.expect("open sqlite backend");
backend.migrate().await.expect("migrate");
Arc::new(backend)
}
#[tokio::test]
async fn admin_status_returns_documented_storage_block_through_router() {
let tmp = tempfile::tempdir().expect("create tempdir");
let backend = open_test_backend(&tmp).await;
let app = aa_gateway::remote_mode::router(
Some(backend),
Some("postgresql://aasm:secret@db.internal:5432/aasm".to_string()),
)
.into_make_service();
let handle: Handle<SocketAddr> = Handle::new();
let shutdown_handle = handle.clone();
let probe_handle = handle.clone();
let server = tokio::spawn(async move {
axum_server::bind("127.0.0.1:0".parse().expect("listen_addr"))
.handle(handle)
.serve(app)
.await
.expect("serve admin_status_e2e router");
});
let listening = tokio::time::timeout(Duration::from_secs(5), probe_handle.listening())
.await
.expect("listener must bind within 5s")
.expect("listener address");
let url = format!("http://{listening}/api/v1/admin/status");
let body: serde_json::Value = reqwest::Client::new()
.get(&url)
.send()
.await
.expect("GET /api/v1/admin/status")
.json()
.await
.expect("response body must be JSON");
assert_eq!(body["mode"], "remote");
assert!(body["version"].is_string(), "version must be string");
assert!(body["uptime_secs"].is_number(), "uptime_secs must be number");
let storage = &body["storage"];
assert_eq!(storage["backend"], "sqlite");
assert_eq!(storage["health"], "ok");
assert!(
storage["latency_ms"].as_u64().is_some(),
"latency_ms must be a number, got {:?}",
storage["latency_ms"]
);
assert!(
storage.get("database_url").is_none(),
"sqlite branch must omit database_url, got {:?}",
storage["database_url"]
);
assert!(
storage.get("timescaledb").is_none(),
"no TimescaleDB on sqlite, got {:?}",
storage["timescaledb"]
);
let counts = &storage["row_counts"];
assert!(counts["audit_events_hot"].as_u64().is_some());
assert!(counts["agents"].as_u64().is_some());
assert!(counts["policy_versions"].as_u64().is_some());
shutdown_handle.graceful_shutdown(Some(Duration::from_secs(1)));
let _ = server.await;
}