diff --git a/src/Testcontainers/Clients/ContainerConfigurationConverter.cs b/src/Testcontainers/Clients/ContainerConfigurationConverter.cs index 84f7dfb7c..4d3ec077c 100644 --- a/src/Testcontainers/Clients/ContainerConfigurationConverter.cs +++ b/src/Testcontainers/Clients/ContainerConfigurationConverter.cs @@ -48,7 +48,7 @@ public ContainerConfigurationConverter(IContainerConfiguration configuration) public IDictionary Networks { get; } - private static string GetQualifiedPort(string containerPort) + public static string GetQualifiedPort(string containerPort) { return Array.Exists(new[] { UdpPortSuffix, TcpPortSuffix, SctpPortSuffix }, portSuffix => containerPort.EndsWith(portSuffix, StringComparison.OrdinalIgnoreCase)) ? containerPort.ToLowerInvariant() : containerPort + TcpPortSuffix; } diff --git a/src/Testcontainers/Containers/DockerContainer.cs b/src/Testcontainers/Containers/DockerContainer.cs index 3a6fbdffb..8cd148758 100644 --- a/src/Testcontainers/Containers/DockerContainer.cs +++ b/src/Testcontainers/Containers/DockerContainer.cs @@ -236,13 +236,15 @@ public ushort GetMappedPublicPort(string containerPort) { ThrowIfResourceNotFound(); - if (_container.NetworkSettings.Ports.TryGetValue($"{containerPort}/tcp", out var portBindings) && ushort.TryParse(portBindings[0].HostPort, out var publicPort)) + var qualifiedContainerPort = ContainerConfigurationConverter.GetQualifiedPort(containerPort); + + if (_container.NetworkSettings.Ports.TryGetValue(qualifiedContainerPort, out var portBindings) && ushort.TryParse(portBindings[0].HostPort, out var publicPort)) { return publicPort; } else { - throw new InvalidOperationException($"Exposed port {containerPort} is not mapped."); + throw new InvalidOperationException($"Exposed port {qualifiedContainerPort} is not mapped."); } } diff --git a/src/Testcontainers/Containers/IContainer.cs b/src/Testcontainers/Containers/IContainer.cs index d041f7822..7d222c0de 100644 --- a/src/Testcontainers/Containers/IContainer.cs +++ b/src/Testcontainers/Containers/IContainer.cs @@ -132,6 +132,9 @@ public interface IContainer : IAsyncDisposable /// /// Resolves the public assigned host port. /// + /// + /// Resolves the public assigned host port for the TCP protocol. To resolve a specific protocol, use . + /// /// The container port. /// Returns the public assigned host port. /// Container has not been created. @@ -140,6 +143,9 @@ public interface IContainer : IAsyncDisposable /// /// Resolves the public assigned host port. /// + /// + /// Append /tcp|udp|sctp to to resolve the public assigned host port for a specific protocol e.g. "53/udp". + /// /// The container port. /// Returns the public assigned host port. /// Container has not been created. diff --git a/tests/Testcontainers.Tests/Unit/Containers/Unix/TestcontainersContainerTest.cs b/tests/Testcontainers.Tests/Unit/Containers/Unix/TestcontainersContainerTest.cs index 2d8bdd473..bbcb8fea2 100644 --- a/tests/Testcontainers.Tests/Unit/Containers/Unix/TestcontainersContainerTest.cs +++ b/tests/Testcontainers.Tests/Unit/Containers/Unix/TestcontainersContainerTest.cs @@ -171,7 +171,29 @@ await container.StartAsync() } [Fact] - public async Task RandomPortBinding() + public async Task RandomUdpPortBinding() + { + // Given + const ushort containerPort = 53; + + const string qualifiedContainerPort = "53/udp"; + + await using var container = new ContainerBuilder() + .WithImage(CommonImages.Alpine) + .WithEntrypoint(CommonCommands.SleepInfinity) + .WithPortBinding(qualifiedContainerPort, true) + .Build(); + + // When + await container.StartAsync() + .ConfigureAwait(true); + + // Then + Assert.NotEqual(containerPort, container.GetMappedPublicPort(qualifiedContainerPort)); + } + + [Fact] + public async Task RandomTcpPortBinding() { // Given const ushort containerPort = 80;