From 7bb7fceb948bfc57a8649288993fc8384207eefa Mon Sep 17 00:00:00 2001 From: Artem Medvedev Date: Sat, 15 Jun 2024 20:35:23 +0200 Subject: [PATCH] feat: impl `From` for `ContainerPort` with TCP default (#658) As a result, it was decided that such a default makes sense - it corresponds to the default behavior of Docker, and is also more common use case. --- .../src/core/containers/async_container.rs | 12 ++++++++++-- testcontainers/src/core/containers/sync_container.rs | 10 ++++++++-- testcontainers/src/core/ports.rs | 12 +++++++++++- testcontainers/src/runners/async_runner.rs | 2 +- 4 files changed, 30 insertions(+), 6 deletions(-) diff --git a/testcontainers/src/core/containers/async_container.rs b/testcontainers/src/core/containers/async_container.rs index 0301a7ab..54ba7fab 100644 --- a/testcontainers/src/core/containers/async_container.rs +++ b/testcontainers/src/core/containers/async_container.rs @@ -90,9 +90,13 @@ where /// Returns the mapped host port for an internal port of this docker container, on the host's /// IPv4 interfaces. /// + /// By default, `u16` is considered as TCP port. Also, you can convert `u16` to [`ContainerPort`] port + /// by using [`crate::core::IntoContainerPort`] trait. + /// /// This method does **not** magically expose the given port, it simply performs a mapping on /// the already exposed ports. If a docker container does not expose a port, this method will return an error. - pub async fn get_host_port_ipv4(&self, internal_port: ContainerPort) -> Result { + pub async fn get_host_port_ipv4(&self, internal_port: impl Into) -> Result { + let internal_port = internal_port.into(); self.ports() .await? .map_to_host_port_ipv4(internal_port) @@ -105,9 +109,13 @@ where /// Returns the mapped host port for an internal port of this docker container, on the host's /// IPv6 interfaces. /// + /// By default, `u16` is considered as TCP port. Also, you can convert `u16` to [`ContainerPort`] port + /// by using [`crate::core::IntoContainerPort`] trait. + /// /// This method does **not** magically expose the given port, it simply performs a mapping on /// the already exposed ports. If a docker container does not expose a port, this method will return an error. - pub async fn get_host_port_ipv6(&self, internal_port: ContainerPort) -> Result { + pub async fn get_host_port_ipv6(&self, internal_port: impl Into) -> Result { + let internal_port = internal_port.into(); self.ports() .await? .map_to_host_port_ipv6(internal_port) diff --git a/testcontainers/src/core/containers/sync_container.rs b/testcontainers/src/core/containers/sync_container.rs index c3f27282..01edc63a 100644 --- a/testcontainers/src/core/containers/sync_container.rs +++ b/testcontainers/src/core/containers/sync_container.rs @@ -80,9 +80,12 @@ where /// Returns the mapped host port for an internal port of this docker container, on the host's /// IPv4 interfaces. /// + /// By default, `u16` is considered as TCP port. Also, you can convert `u16` to [`ContainerPort`] port + /// by using [`crate::core::IntoContainerPort`] trait. + /// /// This method does **not** magically expose the given port, it simply performs a mapping on /// the already exposed ports. If a docker container does not expose a port, this method returns an error. - pub fn get_host_port_ipv4(&self, internal_port: ContainerPort) -> Result { + pub fn get_host_port_ipv4(&self, internal_port: impl Into) -> Result { self.rt() .block_on(self.async_impl().get_host_port_ipv4(internal_port)) } @@ -90,9 +93,12 @@ where /// Returns the mapped host port for an internal port of this docker container, on the host's /// IPv6 interfaces. /// + /// By default, `u16` is considered as TCP port. Also, you can convert `u16` to [`ContainerPort`] port + /// by using [`crate::core::IntoContainerPort`] trait. + /// /// This method does **not** magically expose the given port, it simply performs a mapping on /// the already exposed ports. If a docker container does not expose a port, this method returns an error. - pub fn get_host_port_ipv6(&self, internal_port: ContainerPort) -> Result { + pub fn get_host_port_ipv6(&self, internal_port: impl Into) -> Result { self.rt() .block_on(self.async_impl().get_host_port_ipv6(internal_port)) } diff --git a/testcontainers/src/core/ports.rs b/testcontainers/src/core/ports.rs index 3de3e289..14b88e68 100644 --- a/testcontainers/src/core/ports.rs +++ b/testcontainers/src/core/ports.rs @@ -2,6 +2,10 @@ use std::{collections::HashMap, net::IpAddr, num::ParseIntError}; use bollard_stubs::models::{PortBinding, PortMap}; +/// Represents a port that is exposed by a container. +/// +/// There is a helper [`IntoContainerPort`] trait to convert a `u16` into a [`ContainerPort`]. +/// Also, `u16` can be directly converted into a `ContainerPort` using `Into::into`, it will default to `ContainerPort::Tcp`. #[derive( parse_display::Display, parse_display::FromStr, Debug, Clone, Copy, Eq, PartialEq, Hash, )] @@ -15,7 +19,7 @@ pub enum ContainerPort { } /// A trait to allow easy conversion of a `u16` into a `ContainerPort`. -/// For example, `123.tcp()` is equivalent to `ContainerPort::Tcp(123)`. +/// For example, `123.udp()` is equivalent to `ContainerPort::Udp(123)`. pub trait IntoContainerPort { fn tcp(self) -> ContainerPort; fn udp(self) -> ContainerPort; @@ -141,6 +145,12 @@ impl IntoContainerPort for u16 { } } +impl From for ContainerPort { + fn from(port: u16) -> Self { + ContainerPort::Tcp(port) + } +} + #[cfg(test)] mod tests { use bollard_stubs::models::ContainerInspectResponse; diff --git a/testcontainers/src/runners/async_runner.rs b/testcontainers/src/runners/async_runner.rs index b49e6458..a5593bad 100644 --- a/testcontainers/src/runners/async_runner.rs +++ b/testcontainers/src/runners/async_runner.rs @@ -290,7 +290,7 @@ mod tests { .with_wait_for(WaitFor::seconds(1)); let container = image.start().await?; container - .get_host_port_ipv4(5000.tcp()) + .get_host_port_ipv4(5000) .await .expect("Port should be mapped"); Ok(())