use crate::container::{PendingContainer, RunningContainer};
use crate::waitfor::{async_trait, WaitFor};
use crate::DockerTestError;
use bollard::container::InspectContainerOptions;
use bollard::models::ContainerState;
use tokio::time::{interval, Duration};
#[derive(Clone, Debug)]
pub struct RunningWait {
pub check_interval: u64,
pub max_checks: u64,
}
#[derive(Clone, Debug)]
pub struct ExitedWait {
pub check_interval: u64,
pub max_checks: u64,
}
#[async_trait]
impl WaitFor for RunningWait {
async fn wait_for_ready(
&self,
container: PendingContainer,
) -> Result<RunningContainer, DockerTestError> {
wait_for_container_state(container, self.check_interval, self.max_checks, |state| {
state.running.unwrap()
})
.await
}
}
#[async_trait]
impl WaitFor for ExitedWait {
async fn wait_for_ready(
&self,
container: PendingContainer,
) -> Result<RunningContainer, DockerTestError> {
wait_for_container_state(container, self.check_interval, self.max_checks, |state| {
!state.running.unwrap()
})
.await
}
}
async fn wait_for_container_state(
container: PendingContainer,
check_interval: u64,
max_checks: u64,
container_state_compare: fn(&ContainerState) -> bool,
) -> Result<RunningContainer, DockerTestError> {
let client = &container.client;
let mut started = false;
let mut num_checks = 0;
let mut interval = interval(Duration::from_secs(check_interval));
loop {
if num_checks >= max_checks {
break;
}
started = if let Ok(c) = client
.inspect_container(&container.name, None::<InspectContainerOptions>)
.await
{
container_state_compare(&c.clone().state.unwrap())
} else {
false
};
if started {
break;
}
num_checks += 1;
interval.tick().await;
}
match started {
false => Err(DockerTestError::Startup(
"status waitfor is not triggered".to_string(),
)),
true => Ok(container.into()),
}
}