diff --git a/testcontainers/src/core/containers/request.rs b/testcontainers/src/core/containers/request.rs index 06aa949b..f98d72b7 100644 --- a/testcontainers/src/core/containers/request.rs +++ b/testcontainers/src/core/containers/request.rs @@ -35,6 +35,7 @@ pub struct ContainerRequest { pub(crate) cgroupns_mode: Option, pub(crate) userns_mode: Option, pub(crate) startup_timeout: Option, + pub(crate) working_dir: Option, pub(crate) log_consumers: Vec>, } @@ -156,6 +157,10 @@ impl ContainerRequest { pub fn startup_timeout(&self) -> Option { self.startup_timeout } + + pub fn working_dir(&self) -> Option<&str> { + self.working_dir.as_deref() + } } impl From for ContainerRequest { @@ -177,6 +182,7 @@ impl From for ContainerRequest { cgroupns_mode: None, userns_mode: None, startup_timeout: None, + working_dir: None, log_consumers: vec![], } } @@ -218,6 +224,7 @@ impl Debug for ContainerRequest { .field("cgroupns_mode", &self.cgroupns_mode) .field("userns_mode", &self.userns_mode) .field("startup_timeout", &self.startup_timeout) + .field("working_dir", &self.working_dir) .finish() } } diff --git a/testcontainers/src/core/image/image_ext.rs b/testcontainers/src/core/image/image_ext.rs index 67dc9a42..d8115dc5 100644 --- a/testcontainers/src/core/image/image_ext.rs +++ b/testcontainers/src/core/image/image_ext.rs @@ -94,6 +94,9 @@ pub trait ImageExt { /// Sets the startup timeout for the container. The default is 60 seconds. fn with_startup_timeout(self, timeout: Duration) -> ContainerRequest; + /// Sets the working directory. The default is defined by the underlying image, which in turn may default to `/`. + fn with_working_dir(self, working_dir: impl Into) -> ContainerRequest; + /// Adds the log consumer to the container. /// /// Allows to follow the container logs for the whole lifecycle of the container, starting from the creation. @@ -235,6 +238,14 @@ impl>, I: Image> ImageExt for RI { } } + fn with_working_dir(self, working_dir: impl Into) -> ContainerRequest { + let container_req = self.into(); + ContainerRequest { + working_dir: Some(working_dir.into()), + ..container_req + } + } + fn with_log_consumer(self, log_consumer: impl LogConsumer + 'static) -> ContainerRequest { let mut container_req = self.into(); container_req.log_consumers.push(Box::new(log_consumer)); diff --git a/testcontainers/src/runners/async_runner.rs b/testcontainers/src/runners/async_runner.rs index 209aced3..4ed0cf12 100644 --- a/testcontainers/src/runners/async_runner.rs +++ b/testcontainers/src/runners/async_runner.rs @@ -71,6 +71,7 @@ where userns_mode: container_req.userns_mode().map(|v| v.to_string()), ..Default::default() }), + working_dir: container_req.working_dir().map(|dir| dir.to_string()), ..Default::default() }; @@ -647,4 +648,25 @@ mod tests { assert_eq!("host", userns_mode, "userns mode must be `host`"); Ok(()) } + + #[tokio::test] + async fn async_run_command_should_have_working_dir() -> anyhow::Result<()> { + let image = GenericImage::new("hello-world", "latest"); + let expected_working_dir = "/foo"; + let container = image.with_working_dir(expected_working_dir).start().await?; + + let client = Client::lazy_client().await?; + let container_details = client.inspect(container.id()).await?; + + let working_dir = container_details + .config + .expect("ContainerConfig") + .working_dir + .expect("WorkingDir"); + assert_eq!( + expected_working_dir, &working_dir, + "working dir must be `foo`" + ); + Ok(()) + } }