use std::collections::HashMap;
use std::io::Write;
use std::time::Duration;
use lightshuttle_runtime::{
ContainerRuntime, ContainerSpec, ContainerStatus, DockerRuntime, ImageSource,
};
fn small_image_spec(name: &str) -> ContainerSpec {
ContainerSpec {
name: name.to_owned(),
project: "lightshuttle_it".to_owned(),
resource: name.to_owned(),
image: ImageSource::Pull("alpine:3.20".to_owned()),
env: HashMap::new(),
ports: Vec::new(),
volumes: Vec::new(),
command: Some(vec!["sh".to_owned(), "-c".to_owned(), "sleep 5".to_owned()]),
healthcheck: None,
working_dir: None,
}
}
#[tokio::test]
#[ignore = "requires a running Docker daemon"]
async fn start_inspect_stop_alpine() {
let runtime = DockerRuntime::connect().expect("Docker daemon reachable");
let spec = small_image_spec("lightshuttle_it_start_inspect_stop");
let id = runtime.start(&spec).await.expect("container starts");
let status = runtime.inspect(&id).await.expect("inspect succeeds");
assert!(matches!(
status,
ContainerStatus::Running | ContainerStatus::Starting | ContainerStatus::Healthy
));
runtime
.stop(&id, Duration::from_secs(2))
.await
.expect("stop succeeds");
}
#[tokio::test]
#[ignore = "requires a running Docker daemon"]
async fn builds_and_runs_a_dockerfile_resource() {
let context = tempfile::tempdir().expect("temp dir created");
let dockerfile_path = context.path().join("Dockerfile");
let mut dockerfile = std::fs::File::create(&dockerfile_path).expect("Dockerfile created");
writeln!(dockerfile, "FROM alpine:3.20").expect("write line");
writeln!(dockerfile, "CMD [\"sh\", \"-c\", \"sleep 5\"]").expect("write line");
drop(dockerfile);
std::fs::write(context.path().join("noisy.tmp"), b"junk").expect("noisy file written");
std::fs::write(context.path().join(".dockerignore"), b"*.tmp\n").expect("ignore written");
let runtime = DockerRuntime::connect().expect("Docker daemon reachable");
let spec = ContainerSpec {
name: "lightshuttle_it_build_run".to_owned(),
project: "lightshuttle_it".to_owned(),
resource: "build_run".to_owned(),
image: ImageSource::Build {
context: context.path().to_string_lossy().into_owned(),
dockerfile: "Dockerfile".to_owned(),
build_args: HashMap::new(),
target: None,
tag: "lightshuttle/it_build_run:dev".to_owned(),
},
env: HashMap::new(),
ports: Vec::new(),
volumes: Vec::new(),
command: None,
healthcheck: None,
working_dir: None,
};
let id = runtime
.start(&spec)
.await
.expect("dockerfile resource builds and starts");
runtime
.stop(&id, Duration::from_secs(2))
.await
.expect("container stops cleanly");
}
#[tokio::test]
#[ignore = "requires a running Docker daemon"]
async fn project_network_lifecycle_is_idempotent() {
let runtime = DockerRuntime::connect().expect("Docker daemon reachable");
runtime
.ensure_project_network("it-net-test")
.await
.expect("network created on first call");
runtime
.ensure_project_network("it-net-test")
.await
.expect("ensure is idempotent");
runtime
.teardown_project_network("it-net-test")
.await
.expect("network removed");
runtime
.teardown_project_network("it-net-test")
.await
.expect("teardown is idempotent");
}
#[tokio::test]
#[ignore = "requires a running Docker daemon"]
async fn builds_buildkit_only_dockerfile() {
let context = tempfile::tempdir().expect("temp dir created");
let dockerfile_path = context.path().join("Dockerfile");
let mut dockerfile = std::fs::File::create(&dockerfile_path).expect("Dockerfile created");
writeln!(dockerfile, "# syntax=docker/dockerfile:1").expect("write line");
writeln!(dockerfile, "FROM alpine:3.20").expect("write line");
writeln!(
dockerfile,
"RUN --mount=type=cache,target=/var/cache/apk echo cached"
)
.expect("write line");
writeln!(dockerfile, "CMD [\"sh\", \"-c\", \"sleep 5\"]").expect("write line");
drop(dockerfile);
let runtime = DockerRuntime::connect().expect("Docker daemon reachable");
let spec = ContainerSpec {
name: "lightshuttle_it_buildkit".to_owned(),
project: "lightshuttle_it".to_owned(),
resource: "buildkit".to_owned(),
image: ImageSource::Build {
context: context.path().to_string_lossy().into_owned(),
dockerfile: "Dockerfile".to_owned(),
build_args: HashMap::new(),
target: None,
tag: "lightshuttle/it_buildkit:dev".to_owned(),
},
env: HashMap::new(),
ports: Vec::new(),
volumes: Vec::new(),
command: None,
healthcheck: None,
working_dir: None,
};
let id = runtime
.start(&spec)
.await
.expect("BuildKit-only Dockerfile builds and starts");
runtime
.stop(&id, Duration::from_secs(2))
.await
.expect("container stops cleanly");
}