use arcbox_core::{Config, Runtime, VmLifecycleConfig};
use arcbox_docker::{DockerApiServer, ServerConfig};
use std::path::Path;
use std::sync::Arc;
use std::time::Duration;
use tokio::io::AsyncReadExt;
use tokio::net::UnixStream;
use tokio_util::sync::CancellationToken;
fn offline_runtime(data_dir: &Path) -> Arc<Runtime> {
let config = Config {
data_dir: data_dir.to_path_buf(),
..Default::default()
};
let vm_lifecycle_config = VmLifecycleConfig {
skip_vm_check: true,
..Default::default()
};
Arc::new(
Runtime::with_vm_lifecycle_config(config, vm_lifecycle_config)
.expect("Failed to create runtime"),
)
}
#[tokio::test]
async fn idle_connections_do_not_hold_shutdown_open() {
let tmp = tempfile::TempDir::new().expect("temp dir");
let socket_path = tmp.path().join("docker.sock");
let server = DockerApiServer::new(
ServerConfig {
socket_path: socket_path.clone(),
},
offline_runtime(tmp.path()),
);
let listener = server.bind().expect("bind");
let shutdown = CancellationToken::new();
let serve = tokio::spawn({
let shutdown = shutdown.clone();
async move { server.serve(listener, shutdown).await }
});
let mut idle = Vec::new();
for _ in 0..3 {
idle.push(UnixStream::connect(&socket_path).await.expect("connect"));
}
tokio::time::sleep(Duration::from_millis(100)).await;
shutdown.cancel();
tokio::time::timeout(Duration::from_secs(2), serve)
.await
.expect("serve must return without waiting for idle clients to hang up")
.expect("serve task panicked")
.expect("serve failed");
for mut client in idle {
let mut buf = [0_u8; 1];
let read = tokio::time::timeout(Duration::from_secs(2), client.read(&mut buf))
.await
.expect("server must close the idle connection")
.expect("read after server close");
assert_eq!(read, 0, "idle connection must see EOF from the server");
}
}