Skip to content

Commit

Permalink
[#123] #EXTEND 'assemblyName: DotNet.Testcontainers; function: ITestc…
Browse files Browse the repository at this point in the history
…ontainersBuilder'

{Add parameter assignRandomHostPort to bind container ports to random host ports.}
  • Loading branch information
HofmeisterAn committed Aug 13, 2019
1 parent 047a49e commit 32937ce
Show file tree
Hide file tree
Showing 7 changed files with 40 additions and 12 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -18,8 +18,7 @@ public async Task ConnectionEstablished()
{
Database = "db",
Username = "mysql",
Password = "mysql",
Port = 33061
Password = "mysql"
});

// When
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -86,8 +86,9 @@ public interface ITestcontainersBuilder<T>
/// Binds the port of the Testcontainer to the same port of the host machine.
/// </summary>
/// <param name="port">Port to bind between Testcontainer and host machine.</param>
/// <param name="assignRandomHostPort">If true, Testcontainer will bind the port to a random host port, otherwise the host and container ports are the same.</param>
/// <returns>A configured instance of <see cref="ITestcontainersBuilder{T}"/>.</returns>
ITestcontainersBuilder<T> WithPortBinding(int port);
ITestcontainersBuilder<T> WithPortBinding(int port, bool assignRandomHostPort = false);

/// <summary>
/// Binds the port of the Testcontainer to the specified port of the host machine.
Expand All @@ -101,8 +102,9 @@ public interface ITestcontainersBuilder<T>
/// Binds the port of the Testcontainer to the same port of the host machine.
/// </summary>
/// <param name="port">Port to bind between Testcontainer and host machine.</param>
/// <param name="assignRandomHostPort">If true, Testcontainer will bind the port to a random host port, otherwise the host and container ports are the same.</param>
/// <returns>A configured instance of <see cref="ITestcontainersBuilder{T}"/>.</returns>
ITestcontainersBuilder<T> WithPortBinding(string port);
ITestcontainersBuilder<T> WithPortBinding(string port, bool assignRandomHostPort = false);

/// <summary>
/// Binds the port of the Testcontainer to the specified port of the host machine.
Expand Down
10 changes: 6 additions & 4 deletions src/DotNet.Testcontainers/Core/Builder/TestcontainersBuilder.cs
Original file line number Diff line number Diff line change
Expand Up @@ -108,19 +108,21 @@ public ITestcontainersBuilder<T> WithExposedPort(string port)
});
}

public ITestcontainersBuilder<T> WithPortBinding(int port)
public ITestcontainersBuilder<T> WithPortBinding(int port, bool assignRandomHostPort = false)
{
return this.WithPortBinding(port, port);
var hostPort = assignRandomHostPort ? TestcontainersNetworkService.GetAvailablePort() : port;
return this.WithPortBinding(hostPort, port);
}

public ITestcontainersBuilder<T> WithPortBinding(int hostPort, int containerPort)
{
return this.WithPortBinding($"{hostPort}", $"{containerPort}");
}

public ITestcontainersBuilder<T> WithPortBinding(string port)
public ITestcontainersBuilder<T> WithPortBinding(string port, bool assignRandomHostPort = false)
{
return this.WithPortBinding(port, port);
var hostPort = assignRandomHostPort ? $"{TestcontainersNetworkService.GetAvailablePort()}" : port;
return this.WithPortBinding(hostPort, port);
}

public ITestcontainersBuilder<T> WithPortBinding(string hostPort, string containerPort)
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
namespace DotNet.Testcontainers.Core.Builder
{
using System.Net;
using System.Net.Sockets;

public static class TestcontainersNetworkService
{
private static readonly IPEndPoint DefaultLoopbackEndpoint = new IPEndPoint(IPAddress.Loopback, port: 0);

public static int GetAvailablePort()

This comment has been minimized.

Copy link
@SbiCA

SbiCA Aug 15, 2019

I tried to use the docker client API but I guess with this approach we're better of since you can define the port in advance. I'm just wondering if it could happen that in the meantime the port gets occupied by something else.

Whereas with this approach, you'd need to figure out the port for the connection string after the container got started, which is kind of a more foundation concern.
SbiCA@7eba3cb

This comment has been minimized.

Copy link
@HofmeisterAn

HofmeisterAn Aug 15, 2019

Author Collaborator

I'm just wondering if it could happen that in the meantime the port gets occupied by something else.

Well, I must release the port to start the Docker container. In the meantime, another process could use this port, but I think the chances are very small. If there is any better implementation we can change GetAvailablePort at any time.

Whereas with this approach, you'd need to figure out the port for the connection string after the container got started, which is kind of a more foundation concern.

True. I already prepared a new feature, to get the assigned public port. See: https://github.com/HofmeisterAn/dotnet-testcontainers/compare/feature/add-method-get-public-ports-from-private.

{
using (var socket = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp))
{
socket.Bind(DefaultLoopbackEndpoint);
return ((IPEndPoint)socket.LocalEndPoint).Port;
}
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -6,13 +6,17 @@ namespace DotNet.Testcontainers.Core.Models

public abstract class TestcontainerConfiguration
{
protected TestcontainerConfiguration(string image, int defaultPort)
protected TestcontainerConfiguration(string image, int defaultPort) : this(image, defaultPort, defaultPort)
{
}

protected TestcontainerConfiguration(string image, int defaultPort, int port)
{
this.Image = image;

this.DefaultPort = defaultPort;

this.Port = defaultPort;
this.Port = port;
}

public string Image { get; }
Expand Down
Original file line number Diff line number Diff line change
@@ -1,10 +1,11 @@
namespace DotNet.Testcontainers.Core.Models
{
using DotNet.Testcontainers.Core.Builder;
using DotNet.Testcontainers.Core.Wait;

public abstract class TestcontainerDatabaseConfiguration : TestcontainerConfiguration
{
protected TestcontainerDatabaseConfiguration(string image, int defaultPort) : base(image, defaultPort)
protected TestcontainerDatabaseConfiguration(string image, int defaultPort) : base(image, defaultPort, TestcontainersNetworkService.GetAvailablePort())
{
}

Expand Down
Original file line number Diff line number Diff line change
@@ -1,10 +1,11 @@
namespace DotNet.Testcontainers.Core.Models
{
using DotNet.Testcontainers.Core.Builder;
using DotNet.Testcontainers.Core.Wait;

public abstract class TestcontainerMessageBrokerConfiguration : TestcontainerConfiguration
{
protected TestcontainerMessageBrokerConfiguration(string image, int defaultPort) : base(image, defaultPort)
protected TestcontainerMessageBrokerConfiguration(string image, int defaultPort) : base(image, defaultPort, TestcontainersNetworkService.GetAvailablePort())
{
}

Expand Down

0 comments on commit 32937ce

Please sign in to comment.