Skip to content

Commit

Permalink
feat: impl From<u16> for ContainerPort with TCP default (#658)
Browse files Browse the repository at this point in the history
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.
  • Loading branch information
DDtKey authored Jun 15, 2024
1 parent 0ee4795 commit 7bb7fce
Show file tree
Hide file tree
Showing 4 changed files with 30 additions and 6 deletions.
12 changes: 10 additions & 2 deletions testcontainers/src/core/containers/async_container.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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<u16> {
pub async fn get_host_port_ipv4(&self, internal_port: impl Into<ContainerPort>) -> Result<u16> {
let internal_port = internal_port.into();
self.ports()
.await?
.map_to_host_port_ipv4(internal_port)
Expand All @@ -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<u16> {
pub async fn get_host_port_ipv6(&self, internal_port: impl Into<ContainerPort>) -> Result<u16> {
let internal_port = internal_port.into();
self.ports()
.await?
.map_to_host_port_ipv6(internal_port)
Expand Down
10 changes: 8 additions & 2 deletions testcontainers/src/core/containers/sync_container.rs
Original file line number Diff line number Diff line change
Expand Up @@ -80,19 +80,25 @@ 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<u16> {
pub fn get_host_port_ipv4(&self, internal_port: impl Into<ContainerPort>) -> Result<u16> {
self.rt()
.block_on(self.async_impl().get_host_port_ipv4(internal_port))
}

/// 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<u16> {
pub fn get_host_port_ipv6(&self, internal_port: impl Into<ContainerPort>) -> Result<u16> {
self.rt()
.block_on(self.async_impl().get_host_port_ipv6(internal_port))
}
Expand Down
12 changes: 11 additions & 1 deletion testcontainers/src/core/ports.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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,
)]
Expand All @@ -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;
Expand Down Expand Up @@ -141,6 +145,12 @@ impl IntoContainerPort for u16 {
}
}

impl From<u16> for ContainerPort {
fn from(port: u16) -> Self {
ContainerPort::Tcp(port)
}
}

#[cfg(test)]
mod tests {
use bollard_stubs::models::ContainerInspectResponse;
Expand Down
2 changes: 1 addition & 1 deletion testcontainers/src/runners/async_runner.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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(())
Expand Down

0 comments on commit 7bb7fce

Please sign in to comment.