Skip to content

Commit ca9f416

Browse files
committed
feat: Add connect to network API
1 parent 524bade commit ca9f416

4 files changed

Lines changed: 107 additions & 2 deletions

File tree

src/Testcontainers/Containers/DockerContainer.cs

Lines changed: 43 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@ namespace DotNet.Testcontainers.Containers
1212
using DotNet.Testcontainers.Clients;
1313
using DotNet.Testcontainers.Configurations;
1414
using DotNet.Testcontainers.Images;
15+
using DotNet.Testcontainers.Networks;
1516
using JetBrains.Annotations;
1617
using Microsoft.Extensions.Logging;
1718

@@ -373,6 +374,26 @@ await UnsafeUnpauseAsync(ct)
373374
.ConfigureAwait(false);
374375
}
375376

377+
/// <inheritdoc />
378+
public async Task ConnectAsync(string network, CancellationToken ct = default)
379+
{
380+
using var disposable = await AcquireLockAsync(ct)
381+
.ConfigureAwait(false);
382+
383+
await UnsafeConnectAsync(network, ct)
384+
.ConfigureAwait(false);
385+
}
386+
387+
/// <inheritdoc />
388+
public async Task ConnectAsync(INetwork network, CancellationToken ct = default)
389+
{
390+
using var disposable = await AcquireLockAsync(ct)
391+
.ConfigureAwait(false);
392+
393+
await UnsafeConnectAsync(network.Name, ct)
394+
.ConfigureAwait(false);
395+
}
396+
376397
/// <inheritdoc />
377398
public Task CopyAsync(byte[] fileContent, string filePath, uint uid = 0, uint gid = 0, UnixFileModes fileMode = Unix.FileMode644, CancellationToken ct = default)
378399
{
@@ -688,6 +709,28 @@ await _client.UnpauseAsync(_container.ID, ct)
688709
Unpaused?.Invoke(this, EventArgs.Empty);
689710
}
690711

712+
/// <summary>
713+
/// Connects the container to an existing network.
714+
/// </summary>
715+
/// <remarks>
716+
/// Only the public members <see cref="ConnectAsync(string, CancellationToken)" /> and <see cref="ConnectAsync(INetwork, CancellationToken)" /> are thread-safe for now.
717+
/// </remarks>
718+
/// <param name="network">The network name.</param>
719+
/// <param name="ct">Cancellation token.</param>
720+
/// <returns>Task that completes when the container has been connected to the network.</returns>
721+
protected virtual async Task UnsafeConnectAsync(string network, CancellationToken ct = default)
722+
{
723+
ThrowIfLockNotAcquired();
724+
725+
ThrowIfResourceNotFound();
726+
727+
await _client.Network.ConnectAsync(network, _container.ID, ct)
728+
.ConfigureAwait(false);
729+
730+
_container = await _client.Container.ByIdAsync(_container.ID, ct)
731+
.ConfigureAwait(false);
732+
}
733+
691734
/// <inheritdoc />
692735
protected override bool Exists()
693736
{

src/Testcontainers/Containers/IContainer.cs

Lines changed: 18 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@ namespace DotNet.Testcontainers.Containers
77
using System.Threading.Tasks;
88
using DotNet.Testcontainers.Configurations;
99
using DotNet.Testcontainers.Images;
10+
using DotNet.Testcontainers.Networks;
1011
using JetBrains.Annotations;
1112
using Microsoft.Extensions.Logging;
1213

@@ -252,6 +253,22 @@ public interface IContainer : IConnectionStringProvider, IAsyncDisposable
252253
/// <exception cref="TaskCanceledException">Thrown when a Testcontainers task gets canceled.</exception>
253254
Task UnpauseAsync(CancellationToken ct = default);
254255

256+
/// <summary>
257+
/// Connects the running container to an existing network.
258+
/// </summary>
259+
/// <param name="network">The existing network to connect to.</param>
260+
/// <param name="ct">Cancellation token.</param>
261+
/// <returns>Task that completes when the container has been connected to the network.</returns>
262+
Task ConnectAsync(string network, CancellationToken ct = default);
263+
264+
/// <summary>
265+
/// Connects the running container to an existing network.
266+
/// </summary>
267+
/// <param name="network">The existing network to connect to.</param>
268+
/// <param name="ct">Cancellation token.</param>
269+
/// <returns>Task that completes when the container has been connected to the network.</returns>
270+
Task ConnectAsync(INetwork network, CancellationToken ct = default);
271+
255272
/// <summary>
256273
/// Copies a test host file to the container.
257274
/// </summary>
@@ -261,7 +278,7 @@ public interface IContainer : IConnectionStringProvider, IAsyncDisposable
261278
/// <param name="gid">The group ID to set for the copied file or directory. Defaults to 0 (root).</param>
262279
/// <param name="fileMode">The POSIX file mode permission.</param>
263280
/// <param name="ct">Cancellation token.</param>
264-
/// <returns></returns>
281+
/// <returns>A task that completes when the array content has been copied.</returns>
265282
Task CopyAsync(byte[] fileContent, string filePath, uint uid = 0, uint gid = 0, UnixFileModes fileMode = Unix.FileMode644, CancellationToken ct = default);
266283

267284
/// <summary>

src/Testcontainers/Images/MatchImage.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -44,7 +44,7 @@ static ReferenceRegex()
4444
}
4545

4646
private ReferenceRegex()
47-
: base(Pattern, RegexOptions.Compiled, TimeSpan.FromSeconds(1))
47+
: base(Pattern, RegexOptions.Compiled, TimeSpan.FromSeconds(5))
4848
{
4949
}
5050

Lines changed: 45 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,45 @@
1+
namespace Testcontainers.Tests;
2+
3+
public sealed class NetworkConnectTest
4+
{
5+
[Fact]
6+
[Trait(nameof(DockerCli.DockerPlatform), nameof(DockerCli.DockerPlatform.Linux))]
7+
public async Task ConnectsRunningContainerToExistingNetworks()
8+
{
9+
// Given
10+
await using var networkByName = new NetworkBuilder()
11+
.Build();
12+
13+
await using var networkByReference = new NetworkBuilder()
14+
.Build();
15+
16+
await using var container = new ContainerBuilder(CommonImages.Alpine)
17+
.WithCommand(CommonCommands.SleepInfinity)
18+
.Build();
19+
20+
await networkByName.CreateAsync(TestContext.Current.CancellationToken)
21+
.ConfigureAwait(true);
22+
23+
await networkByReference.CreateAsync(TestContext.Current.CancellationToken)
24+
.ConfigureAwait(true);
25+
26+
await container.StartAsync(TestContext.Current.CancellationToken)
27+
.ConfigureAwait(true);
28+
29+
using var dockerClient = TestcontainersSettings.OS.DockerEndpointAuthConfig.GetDockerClientBuilder(Guid.NewGuid()).Build();
30+
31+
// When
32+
await container.ConnectAsync(networkByName.Name, TestContext.Current.CancellationToken)
33+
.ConfigureAwait(true);
34+
35+
await container.ConnectAsync(networkByReference, TestContext.Current.CancellationToken)
36+
.ConfigureAwait(true);
37+
38+
var response = await dockerClient.Containers.InspectContainerAsync(container.Id, TestContext.Current.CancellationToken)
39+
.ConfigureAwait(true);
40+
41+
// Then
42+
Assert.Contains(networkByName.Name, response.NetworkSettings.Networks.Keys);
43+
Assert.Contains(networkByReference.Name, response.NetworkSettings.Networks.Keys);
44+
}
45+
}

0 commit comments

Comments
 (0)