fabro/lib/crates/fabro-sandbox/tests/docker_streaming.rs
Bryan Helmkamp 9f2555e497
test(sandbox): move Docker streaming check out of unit tests
Keep daemon-dependent Docker lifecycle coverage as an ignored integration test so the default unit path remains runnable without Docker.
2026-05-01 08:31:31 -04:00

89 lines
2.5 KiB
Rust

#![cfg(feature = "docker")]
use std::sync::Arc;
use bollard::Docker;
use fabro_sandbox::{CommandOutputCallback, DockerSandbox, DockerSandboxOptions, Sandbox};
use tokio::sync::Mutex;
#[tokio::test]
#[ignore = "requires real Docker container lifecycle; run explicitly when changing Docker exec integration"]
async fn streaming_timeout_terminates_docker_exec_before_returning() {
let image = "buildpack-deps:noble";
let Ok(docker) = Docker::connect_with_local_defaults() else {
return;
};
if docker.inspect_image(image).await.is_err() {
return;
}
let sandbox = DockerSandbox::new(
DockerSandboxOptions {
image: image.to_string(),
auto_pull: false,
skip_clone: true,
..DockerSandboxOptions::default()
},
None,
None,
None,
None,
)
.expect("docker sandbox should construct");
sandbox
.initialize()
.await
.expect("docker sandbox should initialize");
let chunks = Arc::new(Mutex::new(Vec::new()));
let callback_chunks = Arc::clone(&chunks);
let callback: CommandOutputCallback = Arc::new(move |_stream, bytes| {
let callback_chunks = Arc::clone(&callback_chunks);
Box::pin(async move {
callback_chunks.lock().await.extend(bytes);
Ok(())
})
});
let marker = "fabro_streaming_timeout_sentinel";
let result = sandbox
.exec_command_streaming(
&format!("trap '' HUP TERM; echo start; sleep 5 # {marker}"),
200,
None,
None,
None,
callback,
)
.await
.expect("streaming command should return a timeout result");
assert!(result.result.is_timed_out());
assert!(
String::from_utf8_lossy(&chunks.lock().await).contains("start"),
"stream should include output emitted before timeout"
);
let probe = sandbox
.exec_command(
"marker='fabro_streaming_timeout_''sentinel'; \
ps -eo pid,args | awk -v marker=\"$marker\" \
'index($0, marker) && $0 !~ /awk/ && $0 !~ /ps -eo/ { print }'",
1_000,
None,
None,
None,
)
.await
.expect("process probe should run");
sandbox
.cleanup()
.await
.expect("docker cleanup should succeed");
assert!(
!probe.stdout.contains(marker),
"timed-out docker exec should be terminated before returning, found: {}",
probe.stdout
);
}