Skip to content

Commit

Permalink
feat: support HTTP wait strategy (#659)
Browse files Browse the repository at this point in the history
Introduces HTTP wait strategy

Closes #648 

Additional documentation in follow-up PR
  • Loading branch information
DDtKey committed Jun 15, 2024
1 parent 7bb7fce commit 10cf094
Show file tree
Hide file tree
Showing 11 changed files with 417 additions and 74 deletions.
3 changes: 2 additions & 1 deletion testcontainers/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,7 @@ futures = "0.3"
log = "0.4"
memchr = "2.7.2"
parse-display = "0.9.0"
reqwest = { version = "0.12.4", features = ["default-tls", "hickory-dns", "json", "charset", "http2"], default-features = false }
serde = { version = "1", features = ["derive"] }
serde-java-properties = { version = "0.2.0", optional = true }
serde_json = "1"
Expand All @@ -48,6 +49,6 @@ properties-config = ["serde-java-properties"]
[dev-dependencies]
anyhow = "1.0.86"
pretty_env_logger = "0.5"
reqwest = { version = "0.12.3", features = ["blocking"] }
reqwest = { version = "0.12.4", features = ["blocking"] }
testimages.workspace = true
tokio = { version = "1", features = ["macros"] }
4 changes: 3 additions & 1 deletion testcontainers/src/core.rs
Original file line number Diff line number Diff line change
@@ -1,8 +1,9 @@
pub use self::{
containers::*,
image::{CmdWaitFor, ContainerState, ExecCommand, Image, ImageExt, WaitFor},
image::{ContainerState, ExecCommand, Image, ImageExt},
mounts::{AccessMode, Mount, MountType},
ports::{ContainerPort, IntoContainerPort},
wait::{cmd_wait::CmdWaitFor, WaitFor},
};

mod image;
Expand All @@ -16,3 +17,4 @@ pub(crate) mod macros;
pub(crate) mod mounts;
pub(crate) mod network;
pub(crate) mod ports;
pub mod wait;
7 changes: 5 additions & 2 deletions testcontainers/src/core/containers/async_container.rs
Original file line number Diff line number Diff line change
Expand Up @@ -10,11 +10,11 @@ use crate::{
client::Client,
env,
error::{ContainerMissingInfo, ExecError, Result, TestcontainersError, WaitContainerError},
image::CmdWaitFor,
macros,
network::Network,
ports::Ports,
ContainerPort, ContainerState, ExecCommand, WaitFor,
wait::WaitStrategy,
CmdWaitFor, ContainerPort, ContainerState, ExecCommand, WaitFor,
},
ContainerRequest, Image,
};
Expand Down Expand Up @@ -342,6 +342,9 @@ where
}
}
},
WaitFor::Http(http_strategy) => {
http_strategy.wait_until_ready(self).await?;
}
WaitFor::Nothing => {}
}
}
Expand Down
4 changes: 3 additions & 1 deletion testcontainers/src/core/error.rs
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
use std::error::Error;

use crate::core::logs::WaitLogError;
pub use crate::core::{client::ClientError, env::ConfigurationError, ContainerPort};
use crate::core::{logs::WaitLogError, wait::http_strategy::HttpWaitError};

pub type Result<T> = std::result::Result<T, TestcontainersError>;

Expand Down Expand Up @@ -54,6 +54,8 @@ pub enum WaitContainerError {
WaitLog(#[from] WaitLogError),
#[error("container state is unavailable")]
StateUnavailable,
#[error("container is not ready: {0}")]
HttpWait(#[from] HttpWaitError),
#[error("healthcheck is not configured for container: {0}")]
HealthCheckNotConfigured(String),
#[error("container is unhealthy")]
Expand Down
9 changes: 5 additions & 4 deletions testcontainers/src/core/image.rs
Original file line number Diff line number Diff line change
@@ -1,15 +1,16 @@
use std::{borrow::Cow, fmt::Debug};

pub use exec::{CmdWaitFor, ExecCommand};
pub use exec::ExecCommand;
pub use image_ext::ImageExt;
pub use wait_for::WaitFor;

use super::ports::{ContainerPort, Ports};
use crate::{core::mounts::Mount, TestcontainersError};
use crate::{
core::{mounts::Mount, WaitFor},
TestcontainersError,
};

mod exec;
mod image_ext;
mod wait_for;

/// Represents a docker image.
///
Expand Down
62 changes: 1 addition & 61 deletions testcontainers/src/core/image/exec.rs
Original file line number Diff line number Diff line change
@@ -1,8 +1,4 @@
use std::time::Duration;

use bytes::Bytes;

use crate::core::WaitFor;
use crate::core::{CmdWaitFor, WaitFor};

#[derive(Debug)]
pub struct ExecCommand {
Expand Down Expand Up @@ -39,59 +35,3 @@ impl Default for ExecCommand {
Self::new(Vec::<String>::new())
}
}

#[derive(Debug, Eq, PartialEq, Clone)]
pub enum CmdWaitFor {
/// An empty condition. Useful for default cases or fallbacks.
Nothing,
/// Wait for a message on the stdout stream of the command's output.
StdOutMessage { message: Bytes },
/// Wait for a message on the stderr stream of the command's output.
StdErrMessage { message: Bytes },
/// Wait for a certain amount of time.
Duration { length: Duration },
/// Wait for the command's exit code to be equal to the provided one.
ExitCode { code: i64 },
}

impl CmdWaitFor {
pub fn message_on_stdout(message: impl AsRef<[u8]>) -> Self {
Self::StdOutMessage {
message: Bytes::from(message.as_ref().to_vec()),
}
}

pub fn message_on_stderr(message: impl AsRef<[u8]>) -> Self {
Self::StdErrMessage {
message: Bytes::from(message.as_ref().to_vec()),
}
}

pub fn exit_code(code: i64) -> Self {
Self::ExitCode { code }
}

pub fn seconds(length: u64) -> Self {
Self::Duration {
length: Duration::from_secs(length),
}
}

pub fn millis(length: u64) -> Self {
Self::Duration {
length: Duration::from_millis(length),
}
}
}

impl From<WaitFor> for CmdWaitFor {
fn from(wait_for: WaitFor) -> Self {
match wait_for {
WaitFor::Nothing => Self::Nothing,
WaitFor::StdOutMessage { message } => Self::StdOutMessage { message },
WaitFor::StdErrMessage { message } => Self::StdErrMessage { message },
WaitFor::Duration { length } => Self::Duration { length },
WaitFor::Healthcheck => Self::ExitCode { code: 0 },
}
}
}
47 changes: 47 additions & 0 deletions testcontainers/src/core/wait/cmd_wait.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
use std::time::Duration;

use bytes::Bytes;

#[derive(Debug, Eq, PartialEq, Clone)]
pub enum CmdWaitFor {
/// An empty condition. Useful for default cases or fallbacks.
Nothing,
/// Wait for a message on the stdout stream of the command's output.
StdOutMessage { message: Bytes },
/// Wait for a message on the stderr stream of the command's output.
StdErrMessage { message: Bytes },
/// Wait for a certain amount of time.
Duration { length: Duration },
/// Wait for the command's exit code to be equal to the provided one.
ExitCode { code: i64 },
}

impl CmdWaitFor {
pub fn message_on_stdout(message: impl AsRef<[u8]>) -> Self {
Self::StdOutMessage {
message: Bytes::from(message.as_ref().to_vec()),
}
}

pub fn message_on_stderr(message: impl AsRef<[u8]>) -> Self {
Self::StdErrMessage {
message: Bytes::from(message.as_ref().to_vec()),
}
}

pub fn exit_code(code: i64) -> Self {
Self::ExitCode { code }
}

pub fn seconds(length: u64) -> Self {
Self::Duration {
length: Duration::from_secs(length),
}
}

pub fn millis(length: u64) -> Self {
Self::Duration {
length: Duration::from_millis(length),
}
}
}
Loading

0 comments on commit 10cf094

Please sign in to comment.