Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 2 additions & 2 deletions testcontainers/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -17,8 +17,8 @@ rustdoc-args = ["--cfg", "docsrs"]

[dependencies]
async-trait = { version = "0.1" }
bollard = { version = "0.18.1"}
bollard-stubs = "=1.47.1-rc.27.3.1"
bollard = { version = "0.19.1"}
bollard-stubs = "=1.48.3-rc.28.0.4"
bytes = "1.6.0"
conquer-once = { version = "0.4", optional = true }
docker_credential = "1.3.1"
Expand Down
117 changes: 63 additions & 54 deletions testcontainers/src/core/client.rs
Original file line number Diff line number Diff line change
Expand Up @@ -6,14 +6,18 @@ use std::{

use bollard::{
auth::DockerCredentials,
container::{
Config, CreateContainerOptions, InspectContainerOptions, ListContainersOptions, LogOutput,
LogsOptions, RemoveContainerOptions, UploadToContainerOptions,
},
body_full,
container::LogOutput,
errors::Error as BollardError,
exec::{CreateExecOptions, StartExecOptions, StartExecResults},
image::CreateImageOptions,
network::{CreateNetworkOptions, InspectNetworkOptions},
models::{ContainerCreateBody, NetworkCreateRequest},
query_parameters::{
CreateContainerOptions, CreateImageOptionsBuilder, InspectContainerOptions,
InspectContainerOptionsBuilder, InspectNetworkOptions, InspectNetworkOptionsBuilder,
ListContainersOptionsBuilder, ListNetworksOptions, LogsOptionsBuilder,
RemoveContainerOptionsBuilder, StartContainerOptions, StopContainerOptionsBuilder,
UploadToContainerOptionsBuilder,
},
Docker,
};
use bollard_stubs::models::{ContainerInspectResponse, ExecInspectResponse, Network};
Expand Down Expand Up @@ -152,7 +156,7 @@ impl Client {

pub(crate) async fn inspect(&self, id: &str) -> Result<ContainerInspectResponse, ClientError> {
self.bollard
.inspect_container(id, None)
.inspect_container(id, None::<InspectContainerOptions>)
.await
.map_err(ClientError::InspectContainer)
}
Expand All @@ -161,11 +165,12 @@ impl Client {
self.bollard
.remove_container(
id,
Some(RemoveContainerOptions {
force: true,
v: true,
..Default::default()
}),
Some(
RemoveContainerOptionsBuilder::new()
.force(true)
.v(true)
.build(),
),
)
.await
.map_err(ClientError::RemoveContainer)
Expand All @@ -174,20 +179,20 @@ impl Client {
pub(crate) async fn stop(
&self,
id: &str,
timeout_seconds: Option<i64>,
timeout_seconds: Option<i32>,
) -> Result<(), ClientError> {
self.bollard
.stop_container(
id,
timeout_seconds.map(|t| bollard::container::StopContainerOptions { t }),
timeout_seconds.map(|t| StopContainerOptionsBuilder::new().t(t).build()),
)
.await
.map_err(ClientError::StopContainer)
}

pub(crate) async fn start(&self, id: &str) -> Result<(), ClientError> {
self.bollard
.start_container::<String>(id, None)
.start_container(id, None::<StartContainerOptions>)
.await
.map_err(ClientError::Init)
}
Expand Down Expand Up @@ -269,17 +274,20 @@ impl Client {
source_filter: Option<LogSource>,
follow: bool,
) -> LogStream {
let options = LogsOptions {
follow,
stdout: source_filter
.map(LogSource::includes_stdout)
.unwrap_or(true),
stderr: source_filter
.map(LogSource::includes_stderr)
.unwrap_or(true),
tail: "all".to_owned(),
..Default::default()
};
let options = LogsOptionsBuilder::new()
.follow(follow)
.stdout(
source_filter
.map(LogSource::includes_stdout)
.unwrap_or(true),
)
.stderr(
source_filter
.map(LogSource::includes_stderr)
.unwrap_or(true),
)
.tail("all")
.build();

self.bollard.logs(container_id, Some(options)).into()
}
Expand All @@ -288,9 +296,8 @@ impl Client {
pub(crate) async fn create_network(&self, name: &str) -> Result<String, ClientError> {
let network = self
.bollard
.create_network(CreateNetworkOptions {
.create_network(NetworkCreateRequest {
name: name.to_owned(),
check_duplicate: true,
..Default::default()
})
.await
Expand All @@ -302,26 +309,26 @@ impl Client {
/// Inspects a network
pub(crate) async fn inspect_network(&self, name: &str) -> Result<Network, ClientError> {
self.bollard
.inspect_network(name, Some(InspectNetworkOptions::<String>::default()))
.inspect_network(name, Some(InspectNetworkOptionsBuilder::new().build()))
.await
.map_err(ClientError::InspectNetwork)
}

pub(crate) async fn create_container(
&self,
options: Option<CreateContainerOptions<String>>,
config: Config<String>,
options: Option<CreateContainerOptions>,
config: ContainerCreateBody,
) -> Result<String, ClientError> {
self.bollard
.create_container(options.clone(), config.clone())
.create_container(options, config)
.await
.map(|res| res.id)
.map_err(ClientError::CreateContainer)
}

pub(crate) async fn start_container(&self, container_id: &str) -> Result<(), ClientError> {
self.bollard
.start_container::<String>(container_id, None)
.start_container(container_id, None::<StartContainerOptions>)
.await
.map_err(ClientError::StartContainer)
}
Expand All @@ -333,18 +340,18 @@ impl Client {
) -> Result<(), ClientError> {
let container_id: String = container_id.into();

let options = UploadToContainerOptions {
path: "/".to_string(),
no_overwrite_dir_non_dir: "false".into(),
};
let options = UploadToContainerOptionsBuilder::new()
.path("/")
.no_overwrite_dir_non_dir("false")
.build();

let tar = copy_to_container
.tar()
.await
.map_err(ClientError::CopyToContainerError)?;

self.bollard
.upload_to_container::<String>(&container_id, Some(options), tar)
.upload_to_container(&container_id, Some(options), body_full(tar))
.await
.map_err(ClientError::UploadToContainerError)
}
Expand All @@ -353,9 +360,10 @@ impl Client {
&self,
container_id: &str,
) -> Result<bool, ClientError> {
let options = InspectContainerOptionsBuilder::new().size(false).build();
let container_info = self
.bollard
.inspect_container(container_id, Some(InspectContainerOptions { size: false }))
.inspect_container(container_id, Some(options))
.await
.map_err(ClientError::InspectContainer)?;

Expand All @@ -370,9 +378,10 @@ impl Client {
&self,
container_id: &str,
) -> Result<Option<i64>, ClientError> {
let options = InspectContainerOptionsBuilder::new().size(false).build();
let container_info = self
.bollard
.inspect_container(container_id, Some(InspectContainerOptions { size: false }))
.inspect_container(container_id, Some(options))
.await
.map_err(ClientError::InspectContainer)?;

Expand All @@ -386,12 +395,13 @@ impl Client {
}

pub(crate) async fn pull_image(&self, descriptor: &str) -> Result<(), ClientError> {
let pull_options = Some(CreateImageOptions {
from_image: descriptor,
..Default::default()
});
let pull_options = CreateImageOptionsBuilder::new()
.from_image(descriptor)
.build();
let credentials = self.credentials_for_image(descriptor).await;
let mut pulling = self.bollard.create_image(pull_options, None, credentials);
let mut pulling = self
.bollard
.create_image(Some(pull_options), None, credentials);
while let Some(result) = pulling.next().await {
result.map_err(|err| ClientError::PullImage {
descriptor: descriptor.to_string(),
Expand All @@ -404,7 +414,7 @@ impl Client {
pub(crate) async fn network_exists(&self, network: &str) -> Result<bool, ClientError> {
let networks = self
.bollard
.list_networks::<String>(None)
.list_networks(None::<ListNetworksOptions>)
.await
.map_err(ClientError::ListNetworks)?;

Expand Down Expand Up @@ -436,7 +446,7 @@ impl Client {
if is_in_container().await {
let host = self
.bollard
.inspect_network::<String>("bridge", None)
.inspect_network("bridge", None::<InspectNetworkOptions>)
.await
.ok()
.and_then(|net| net.ipam)
Expand Down Expand Up @@ -516,16 +526,15 @@ impl Client {
.flatten()
.collect::<HashMap<_, _>>();

let options = Some(ListContainersOptions {
all: false,
size: false,
limit: None,
filters: filters.clone(),
});
let options = ListContainersOptionsBuilder::new()
.all(false)
.size(false)
.filters(&filters)
.build();

let containers = self
.bollard
.list_containers(options)
.list_containers(Some(options))
.await
.map_err(ClientError::ListContainers)?;

Expand Down
83 changes: 45 additions & 38 deletions testcontainers/src/core/containers/async_container.rs
Original file line number Diff line number Diff line change
Expand Up @@ -221,7 +221,7 @@
cmd_ready_condition,
} = cmd;

log::debug!("Executing command {:?}", cmd);

Check warning on line 224 in testcontainers/src/core/containers/async_container.rs

View workflow job for this annotation

GitHub Actions / clippy

variables can be used directly in the `format!` string

warning: variables can be used directly in the `format!` string --> testcontainers/src/core/containers/async_container.rs:224:9 | 224 | log::debug!("Executing command {:?}", cmd); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | = help: for further information visit https://rust-lang.github.io/rust-clippy/master/index.html#uninlined_format_args = note: `#[warn(clippy::uninlined_format_args)]` on by default help: change this to | 224 - log::debug!("Executing command {:?}", cmd); 224 + log::debug!("Executing command {cmd:?}"); |

let mut exec = self.docker_client.exec(&self.id, cmd).await?;
self.block_until_ready(container_ready_conditions).await?;
Expand Down Expand Up @@ -291,7 +291,7 @@
/// Set Some(-1) to wait indefinitely, None to use system configured default and Some(0)
/// to forcibly stop the container immediately - otherwise the runtime will issue SIGINT
/// and then wait timeout_seconds seconds for the process to stop before issuing SIGKILL.
pub async fn stop_with_timeout(&self, timeout_seconds: Option<i64>) -> Result<()> {
pub async fn stop_with_timeout(&self, timeout_seconds: Option<i32>) -> Result<()> {
log::debug!(
"Stopping docker container {} with {} second timeout",
self.id,
Expand Down Expand Up @@ -442,7 +442,7 @@
match command {
env::Command::Remove => {
if let Err(e) = client.rm(&id).await {
log::error!("Failed to remove container on drop: {}", e);

Check warning on line 445 in testcontainers/src/core/containers/async_container.rs

View workflow job for this annotation

GitHub Actions / clippy

variables can be used directly in the `format!` string

warning: variables can be used directly in the `format!` string --> testcontainers/src/core/containers/async_container.rs:445:29 | 445 | ... log::error!("Failed to remove container on drop: {}", e); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | = help: for further information visit https://rust-lang.github.io/rust-clippy/master/index.html#uninlined_format_args help: change this to | 445 - log::error!("Failed to remove container on drop: {}", e); 445 + log::error!("Failed to remove container on drop: {e}"); |
}
}
env::Command::Keep => {}
Expand Down Expand Up @@ -581,25 +581,27 @@

let client = crate::core::client::docker_client_instance().await?;

let options = bollard::container::ListContainersOptions {
all: false,
limit: Some(2),
size: false,
filters: std::collections::HashMap::from_iter([(
"label".to_string(),
labels
.iter()
.map(|(key, value)| format!("{key}={value}"))
.chain([
"org.testcontainers.managed-by=testcontainers".to_string(),
format!(
"org.testcontainers.session-id={}",
crate::runners::async_runner::session_id()
),
])
.collect(),
)]),
};
let filters = std::collections::HashMap::from_iter([(
"label".to_string(),
labels
.iter()
.map(|(key, value)| format!("{key}={value}"))
.chain([
"org.testcontainers.managed-by=testcontainers".to_string(),
format!(
"org.testcontainers.session-id={}",
crate::runners::async_runner::session_id()
),
])
.collect(),
)]);

let options = bollard::query_parameters::ListContainersOptionsBuilder::new()
.all(false)
.limit(2)
.size(false)
.filters(&filters)
.build();

let containers = client.list_containers(Some(options)).await?;

Expand Down Expand Up @@ -643,19 +645,21 @@

let client = crate::core::client::docker_client_instance().await?;

let options = bollard::container::ListContainersOptions {
all: false,
limit: Some(2),
size: false,
filters: std::collections::HashMap::from_iter([(
"label".to_string(),
labels
.iter()
.map(|(key, value)| format!("{key}={value}"))
.chain(["org.testcontainers.managed-by=testcontainers".to_string()])
.collect(),
)]),
};
let filters = std::collections::HashMap::from_iter([(
"label".to_string(),
labels
.iter()
.map(|(key, value)| format!("{key}={value}"))
.chain(["org.testcontainers.managed-by=testcontainers".to_string()])
.collect(),
)]);

let options = bollard::query_parameters::ListContainersOptionsBuilder::new()
.all(false)
.limit(2)
.size(false)
.filters(&filters)
.build();

let containers = client.list_containers(Some(options)).await?;

Expand All @@ -678,6 +682,8 @@
#[cfg(feature = "reusable-containers")]
#[tokio::test]
async fn async_reusable_containers_are_not_dropped() -> anyhow::Result<()> {
use bollard::query_parameters::InspectContainerOptions;

use crate::{ImageExt, ReuseDirective};

let client = crate::core::client::docker_client_instance().await?;
Expand All @@ -700,7 +706,7 @@
};

assert!(client
.inspect_container(&container_id, None)
.inspect_container(&container_id, None::<InspectContainerOptions>)
.await?
.state
.and_then(|state| state.running)
Expand All @@ -709,10 +715,11 @@
client
.remove_container(
&container_id,
Some(bollard::container::RemoveContainerOptions {
force: true,
..Default::default()
}),
Some(
bollard::query_parameters::RemoveContainerOptionsBuilder::new()
.force(true)
.build(),
),
)
.await
.map_err(anyhow::Error::from)
Expand Down
Loading
Loading