Skip to main content

ContainerGuard

Struct ContainerGuard 

Source
pub struct ContainerGuard<T: Template> { /* private fields */ }
Expand description

RAII guard for automatic container lifecycle management.

When this guard is dropped, the container is automatically stopped and removed (unless configured otherwise via ContainerGuardBuilder).

§Example

use docker_wrapper::testing::ContainerGuard;
use docker_wrapper::RedisTemplate;

#[tokio::test]
async fn test_example() -> Result<(), Box<dyn std::error::Error>> {
    let guard = ContainerGuard::new(RedisTemplate::new("test"))
        .keep_on_panic(true)  // Keep container for debugging if test fails
        .capture_logs(true)   // Print logs on failure
        .start()
        .await?;

    // Container is automatically cleaned up when guard goes out of scope
    Ok(())
}

Implementations§

Source§

impl<T: Template> ContainerGuard<T>

Source

pub fn new(template: T) -> ContainerGuardBuilder<T>

Create a new builder for a container guard.

Note: This returns a builder, not a ContainerGuard. Call .start().await on the builder to create the guard.

Source

pub fn template(&self) -> &T

Get a reference to the underlying template.

Source

pub fn container_id(&self) -> Option<&str>

Get the container ID, if available.

This may be None if the container was reused from a previous run.

Source

pub fn was_reused(&self) -> bool

Check if this guard is reusing an existing container.

Source

pub fn network(&self) -> Option<&str>

Get the network name, if one was configured.

Source

pub async fn is_running(&self) -> Result<bool, TemplateError>

Check if the container is currently running.

§Errors

Returns an error if the Docker command fails.

Source

pub async fn wait_for_ready(&self) -> Result<(), TemplateError>

Wait for the container to be ready.

This calls the underlying template’s readiness check. The exact behavior depends on the template implementation - for example, Redis templates wait for a successful PING response.

§Errors

Returns an error if the readiness check times out or the Docker command fails.

§Example
let guard = ContainerGuard::new(RedisTemplate::new("test"))
    .start()
    .await?;

// Wait for Redis to be ready to accept connections
guard.wait_for_ready().await?;
Source

pub async fn host_port(&self, container_port: u16) -> Result<u16, TemplateError>

Get the host port mapped to a container port.

This is useful when using dynamic port allocation - Docker assigns a random available host port which you can query with this method.

§Errors

Returns an error if the Docker command fails or no port mapping is found.

§Example
let guard = ContainerGuard::new(RedisTemplate::new("test"))
    .start()
    .await?;

let host_port = guard.host_port(6379).await?;
println!("Redis available at localhost:{}", host_port);
Source

pub async fn logs(&self) -> Result<String, TemplateError>

Get the container logs.

§Errors

Returns an error if the Docker command fails.

Source

pub async fn stop(&self) -> Result<(), TemplateError>

Manually stop the container.

The container will still be removed on drop if remove_on_drop is enabled.

§Errors

Returns an error if the Docker command fails.

Source

pub async fn cleanup(&self) -> Result<(), TemplateError>

Manually clean up the container (stop and remove).

After calling this, the drop implementation will not attempt cleanup again.

§Errors

Returns an error if the Docker commands fail.

Source§

impl<T: Template> ContainerGuard<T>

Fault-injection helpers for chaos testing.

These are thin convenience wrappers over the underlying Docker commands (PauseCommand, UnpauseCommand, KillCommand, RestartCommand, NetworkConnectCommand, NetworkDisconnectCommand) that target the guard’s container by name. They make it easy to simulate real faults – hangs, crashes, and network partitions – against a service under test without hand-rolling the command plumbing.

§Example

let guard = ContainerGuard::new(RedisTemplate::new("redis"))
    .wait_for_ready(true)
    .start()
    .await?;

// Freeze the container's processes (simulate a hang), then resume.
guard.pause().await?;
guard.unpause().await?;

// Kill the container outright (simulate a crash).
guard.crash().await?;
Source

pub async fn pause(&self) -> Result<(), TemplateError>

Pause all processes in the container (simulate a hang).

This freezes the container’s processes using docker pause. They can be resumed with unpause.

§Errors

Returns an error if the Docker command fails (for example, if the container is not running).

Source

pub async fn unpause(&self) -> Result<(), TemplateError>

Resume a paused container.

This is the inverse of pause and uses docker unpause.

§Errors

Returns an error if the Docker command fails (for example, if the container is not paused).

Source

pub async fn crash(&self) -> Result<(), TemplateError>

Kill the container immediately with SIGKILL (simulate a crash).

This sends SIGKILL via docker kill, terminating the container without a graceful shutdown.

§Errors

Returns an error if the Docker command fails (for example, if the container is not running).

Source

pub async fn restart_container(&self) -> Result<(), TemplateError>

Restart the container.

This stops and starts the container via docker restart, which is useful for simulating a recovery after a fault.

§Errors

Returns an error if the Docker command fails.

Source

pub async fn partition( &self, network: impl Into<String>, ) -> Result<(), TemplateError>

Partition the container from a network (simulate a network outage).

This disconnects the container from network via docker network disconnect, cutting it off from other containers on that network. Use heal to reconnect.

§Errors

Returns an error if the Docker command fails (for example, if the container is not attached to the network).

Source

pub async fn heal( &self, network: impl Into<String>, ) -> Result<(), TemplateError>

Reconnect the container to a network after a partition.

This is the inverse of partition and uses docker network connect.

§Errors

Returns an error if the Docker command fails.

Source§

impl<T: Template + HasConnectionString> ContainerGuard<T>

Source

pub fn connection_string(&self) -> String

Get the connection string for the underlying service.

This is a convenience method that delegates to the template’s connection_string() implementation. The format depends on the service type (e.g., redis://host:port for Redis).

This method is only available for templates that implement HasConnectionString.

§Example
let guard = ContainerGuard::new(RedisTemplate::new("redis").port(6379))
    .start()
    .await?;

// Direct access to connection string
let conn = guard.connection_string();
// Instead of: guard.template().connection_string()

Trait Implementations§

Source§

impl<T: Template> Drop for ContainerGuard<T>

Source§

fn drop(&mut self)

Executes the destructor for this type. Read more
Source§

fn pin_drop(self: Pin<&mut Self>)

🔬This is a nightly-only experimental API. (pin_ergonomics)
Execute the destructor for this type, but different to Drop::drop, it requires self to be pinned. Read more

Auto Trait Implementations§

§

impl<T> Freeze for ContainerGuard<T>
where T: Freeze,

§

impl<T> RefUnwindSafe for ContainerGuard<T>
where T: RefUnwindSafe,

§

impl<T> Send for ContainerGuard<T>

§

impl<T> Sync for ContainerGuard<T>

§

impl<T> Unpin for ContainerGuard<T>
where T: Unpin,

§

impl<T> UnsafeUnpin for ContainerGuard<T>
where T: UnsafeUnpin,

§

impl<T> UnwindSafe for ContainerGuard<T>
where T: UnwindSafe,

Blanket Implementations§

Source§

impl<T> Any for T
where T: 'static + ?Sized,

Source§

fn type_id(&self) -> TypeId

Gets the TypeId of self. Read more
Source§

impl<T> Borrow<T> for T
where T: ?Sized,

Source§

fn borrow(&self) -> &T

Immutably borrows from an owned value. Read more
Source§

impl<T> BorrowMut<T> for T
where T: ?Sized,

Source§

fn borrow_mut(&mut self) -> &mut T

Mutably borrows from an owned value. Read more
Source§

impl<T> From<T> for T

Source§

fn from(t: T) -> T

Returns the argument unchanged.

Source§

impl<T> Instrument for T

Source§

fn instrument(self, span: Span) -> Instrumented<Self>

Instruments this type with the provided Span, returning an Instrumented wrapper. Read more
Source§

fn in_current_span(self) -> Instrumented<Self>

Instruments this type with the current Span, returning an Instrumented wrapper. Read more
Source§

impl<T, U> Into<U> for T
where U: From<T>,

Source§

fn into(self) -> U

Calls U::from(self).

That is, this conversion is whatever the implementation of From<T> for U chooses to do.

Source§

impl<T> PolicyExt for T
where T: ?Sized,

Source§

fn and<P, B, E>(self, other: P) -> And<T, P>
where T: Sized + Policy<B, E>, P: Policy<B, E>,

Create a new Policy that returns Action::Follow only if self and other return Action::Follow. Read more
Source§

fn or<P, B, E>(self, other: P) -> Or<T, P>
where T: Sized + Policy<B, E>, P: Policy<B, E>,

Create a new Policy that returns Action::Follow if either self or other returns Action::Follow. Read more
Source§

impl<T, U> TryFrom<U> for T
where U: Into<T>,

Source§

type Error = Infallible

The type returned in the event of a conversion error.
Source§

fn try_from(value: U) -> Result<T, <T as TryFrom<U>>::Error>

Performs the conversion.
Source§

impl<T, U> TryInto<U> for T
where U: TryFrom<T>,

Source§

type Error = <U as TryFrom<T>>::Error

The type returned in the event of a conversion error.
Source§

fn try_into(self) -> Result<U, <U as TryFrom<T>>::Error>

Performs the conversion.
Source§

impl<T> WithSubscriber for T

Source§

fn with_subscriber<S>(self, subscriber: S) -> WithDispatch<Self>
where S: Into<Dispatch>,

Attaches the provided Subscriber to this type, returning a WithDispatch wrapper. Read more
Source§

fn with_current_subscriber(self) -> WithDispatch<Self>

Attaches the current default Subscriber to this type, returning a WithDispatch wrapper. Read more