From 3cc34f5753f6d39d6e20e833588401f8a9da02e2 Mon Sep 17 00:00:00 2001 From: Andre Hofmeister <9199345+HofmeisterAn@users.noreply.github.com> Date: Tue, 17 Mar 2026 08:49:09 +0100 Subject: [PATCH 1/2] chore(deps): Bump Docker.DotNet from 3.131.1 to 4.0.2 --- Directory.Packages.props | 4 +- .../DockerEndpointAuthenticationProvider.cs | 27 ++++++------ src/Testcontainers/Builders/TlsCredentials.cs | 14 ------- src/Testcontainers/Clients/DockerApiClient.cs | 8 ++-- ...ckerEndpointAuthenticationConfiguration.cs | 41 ++++++++++++++----- ...ckerEndpointAuthenticationConfiguration.cs | 11 ++--- .../DependsOnTest.cs | 10 ++--- .../ReusableResourceTest.cs | 10 ++--- ...ockerEndpointAuthenticationProviderTest.cs | 8 ++-- .../Unix/ProtectDockerDaemonSocketTest.cs | 9 ++-- 10 files changed, 69 insertions(+), 73 deletions(-) diff --git a/Directory.Packages.props b/Directory.Packages.props index 7ac39c5cb..72340451a 100644 --- a/Directory.Packages.props +++ b/Directory.Packages.props @@ -5,8 +5,8 @@ - - + + diff --git a/src/Testcontainers/Builders/DockerEndpointAuthenticationProvider.cs b/src/Testcontainers/Builders/DockerEndpointAuthenticationProvider.cs index 738050db8..6abd03077 100644 --- a/src/Testcontainers/Builders/DockerEndpointAuthenticationProvider.cs +++ b/src/Testcontainers/Builders/DockerEndpointAuthenticationProvider.cs @@ -39,26 +39,23 @@ public virtual bool IsAvailable() return TaskFactory.StartNew(async () => { - using (var dockerClientConfiguration = authConfig.GetDockerClientConfiguration(ResourceReaper.DefaultSessionId)) + using (var dockerClient = authConfig.GetDockerClientBuilder(ResourceReaper.DefaultSessionId).Build()) { - using (var dockerClient = dockerClientConfiguration.CreateClient(authConfig.Version)) + try { - try - { - await dockerClient.System.PingAsync() - .ConfigureAwait(false); + await dockerClient.System.PingAsync() + .ConfigureAwait(false); - _cachedException = null; + _cachedException = null; - return true; - } - catch (Exception e) - { - var message = $"Failed to connect to Docker endpoint at '{dockerClientConfiguration.EndpointBaseUri}'."; - _cachedException = new DockerUnavailableException(message, e); + return true; + } + catch (Exception e) + { + var message = $"Failed to connect to Docker endpoint at '{dockerClient.Options.Endpoint}'."; + _cachedException = new DockerUnavailableException(message, e); - return false; - } + return false; } } }) diff --git a/src/Testcontainers/Builders/TlsCredentials.cs b/src/Testcontainers/Builders/TlsCredentials.cs index d0bdb3890..9ee88d9c4 100644 --- a/src/Testcontainers/Builders/TlsCredentials.cs +++ b/src/Testcontainers/Builders/TlsCredentials.cs @@ -1,8 +1,6 @@ namespace DotNet.Testcontainers.Builders { - using System.Net.Http; using Docker.DotNet.X509; - using Microsoft.Net.Http.Client; internal sealed class TlsCredentials : CertificateCredentials { @@ -10,17 +8,5 @@ public TlsCredentials() : base(null) { } - - public override bool IsTlsCredentials() - { - return true; - } - - public override HttpMessageHandler GetHandler(HttpMessageHandler handler) - { - var managedHandler = (ManagedHandler)handler; - managedHandler.ServerCertificateValidationCallback = ServerCertificateValidationCallback; - return managedHandler; - } } } diff --git a/src/Testcontainers/Clients/DockerApiClient.cs b/src/Testcontainers/Clients/DockerApiClient.cs index bfc6b2d25..76e48d985 100644 --- a/src/Testcontainers/Clients/DockerApiClient.cs +++ b/src/Testcontainers/Clients/DockerApiClient.cs @@ -93,7 +93,7 @@ await RuntimeInitialized.WaitAsync(ct) runtimeInfo.AppendLine("Connected to Docker:"); runtimeInfo.Append(" Host: "); - runtimeInfo.AppendLine(DockerClient.Configuration.EndpointBaseUri.ToString()); + runtimeInfo.AppendLine(DockerClient.Options.Endpoint.ToString()); runtimeInfo.Append(" Server Version: "); runtimeInfo.AppendLine(dockerInfo.ServerVersion); @@ -133,10 +133,8 @@ await RuntimeInitialized.WaitAsync(ct) private static IDockerClient GetDockerClient(Guid sessionId, IDockerEndpointAuthenticationConfiguration dockerEndpointAuthConfig) { - using (var dockerClientConfiguration = dockerEndpointAuthConfig.GetDockerClientConfiguration(sessionId)) - { - return dockerClientConfiguration.CreateClient(dockerEndpointAuthConfig.Version); - } + var dockerClientBuilder = dockerEndpointAuthConfig.GetDockerClientBuilder(sessionId); + return dockerClientBuilder.Build(); } } } diff --git a/src/Testcontainers/Configurations/AuthConfigs/DockerEndpointAuthenticationConfiguration.cs b/src/Testcontainers/Configurations/AuthConfigs/DockerEndpointAuthenticationConfiguration.cs index 79f1c7d48..f934e7ad3 100644 --- a/src/Testcontainers/Configurations/AuthConfigs/DockerEndpointAuthenticationConfiguration.cs +++ b/src/Testcontainers/Configurations/AuthConfigs/DockerEndpointAuthenticationConfiguration.cs @@ -3,6 +3,8 @@ namespace DotNet.Testcontainers.Configurations using System; using System.Collections.Generic; using Docker.DotNet; + using Docker.DotNet.Handler.Abstractions; + using Docker.DotNet.NPipe; using DotNet.Testcontainers.Clients; using JetBrains.Annotations; @@ -15,22 +17,22 @@ namespace DotNet.Testcontainers.Configurations // Since the static `TestcontainersSettings` class holds the detected container // runtime information from the auto-discovery mechanism, we can't add a static - // `NamedPipeConnectionTimeout` property to it because that would create a + // `NPipeConnectTimeout` property to it because that would create a // circular dependency during discovery. To fix this, we either need to split the // class or stop exposing the `TestcontainersSettings` properties publicly. // Instead, we could rely only on custom configurations via environment variables // or the properties file. - private static readonly TimeSpan NamedPipeConnectionTimeout = EnvironmentConfiguration.Instance.GetNamedPipeConnectionTimeout() ?? PropertiesFileConfiguration.Instance.GetNamedPipeConnectionTimeout() ?? TimeSpan.FromSeconds(5); + private static readonly TimeSpan NPipeConnectTimeout = EnvironmentConfiguration.Instance.GetNamedPipeConnectionTimeout() ?? PropertiesFileConfiguration.Instance.GetNamedPipeConnectionTimeout() ?? TimeSpan.FromSeconds(10); /// /// Initializes a new instance of the struct. /// /// The Docker API endpoint. - /// The Docker API authentication credentials. - public DockerEndpointAuthenticationConfiguration(Uri endpoint, Credentials credentials = null) + /// The Docker API authentication provider. + public DockerEndpointAuthenticationConfiguration(Uri endpoint, IAuthProvider credentials = null) { Endpoint = endpoint; - Credentials = credentials; + AuthProvider = credentials; } /// @@ -40,16 +42,33 @@ public DockerEndpointAuthenticationConfiguration(Uri endpoint, Credentials crede public Uri Endpoint { get; } /// - public Credentials Credentials { get; } + public IAuthProvider AuthProvider { get; } /// - public DockerClientConfiguration GetDockerClientConfiguration(Guid sessionId = default) + public DockerClientBuilder GetDockerClientBuilder(Guid sessionId = default) { - var defaultHttpRequestHeaders = new Dictionary(); - defaultHttpRequestHeaders.Add("User-Agent", "tc-dotnet/" + TestcontainersClient.Version); - defaultHttpRequestHeaders.Add("x-tc-sid", sessionId.ToString("D")); + var headers = new Dictionary(); + headers.Add("User-Agent", "tc-dotnet/" + TestcontainersClient.Version); + headers.Add("x-tc-sid", sessionId.ToString("D")); - return new DockerClientConfiguration(Endpoint, Credentials, namedPipeConnectTimeout: NamedPipeConnectionTimeout, defaultHttpRequestHeaders: defaultHttpRequestHeaders); + var dockerClientBuilder = new DockerClientBuilder() + .WithApiVersion(Version) + .WithEndpoint(Endpoint) + .WithAuthProvider(AuthProvider) + .WithHeaders(headers); + + if ("npipe".Equals(Endpoint.Scheme, StringComparison.OrdinalIgnoreCase)) + { + var transportOptions = new NPipeTransportOptions + { + ConnectTimeout = NPipeConnectTimeout, + }; + + dockerClientBuilder = dockerClientBuilder + .WithTransportOptions(transportOptions); + } + + return dockerClientBuilder; } } } diff --git a/src/Testcontainers/Configurations/AuthConfigs/IDockerEndpointAuthenticationConfiguration.cs b/src/Testcontainers/Configurations/AuthConfigs/IDockerEndpointAuthenticationConfiguration.cs index cafcf2277..d1424ad52 100644 --- a/src/Testcontainers/Configurations/AuthConfigs/IDockerEndpointAuthenticationConfiguration.cs +++ b/src/Testcontainers/Configurations/AuthConfigs/IDockerEndpointAuthenticationConfiguration.cs @@ -2,6 +2,7 @@ namespace DotNet.Testcontainers.Configurations { using System; using Docker.DotNet; + using Docker.DotNet.Handler.Abstractions; using JetBrains.Annotations; /// @@ -23,17 +24,17 @@ public interface IDockerEndpointAuthenticationConfiguration Uri Endpoint { get; } /// - /// Gets the Docker API credentials. + /// Gets the Docker API authentication provider. /// [CanBeNull] - Credentials Credentials { get; } + IAuthProvider AuthProvider { get; } /// - /// Gets the Docker client configuration. + /// Gets the Docker client builder. /// /// The session id. - /// The Docker client configuration. + /// The Docker client builder. [NotNull] - DockerClientConfiguration GetDockerClientConfiguration(Guid sessionId = default); + DockerClientBuilder GetDockerClientBuilder(Guid sessionId = default); } } diff --git a/tests/Testcontainers.Platform.Linux.Tests/DependsOnTest.cs b/tests/Testcontainers.Platform.Linux.Tests/DependsOnTest.cs index 2cd1acf9d..21555df3a 100644 --- a/tests/Testcontainers.Platform.Linux.Tests/DependsOnTest.cs +++ b/tests/Testcontainers.Platform.Linux.Tests/DependsOnTest.cs @@ -62,9 +62,7 @@ await Task.WhenAll(_disposables.Select(disposable => disposable.DisposeAsync().A public async Task DependsOnCreatesDependentResources() { // Given - using var clientConfiguration = TestcontainersSettings.OS.DockerEndpointAuthConfig.GetDockerClientConfiguration(Guid.NewGuid()); - - using var client = clientConfiguration.CreateClient(); + using var dockerClient = TestcontainersSettings.OS.DockerEndpointAuthConfig.GetDockerClientBuilder(Guid.NewGuid()).Build(); var containersListParameters = new ContainersListParameters { All = true, Filters = _filters }; @@ -73,13 +71,13 @@ public async Task DependsOnCreatesDependentResources() var volumesListParameters = new VolumesListParameters { Filters = _filters }; // When - var containers = await client.Containers.ListContainersAsync(containersListParameters, TestContext.Current.CancellationToken) + var containers = await dockerClient.Containers.ListContainersAsync(containersListParameters, TestContext.Current.CancellationToken) .ConfigureAwait(true); - var networks = await client.Networks.ListNetworksAsync(networksListParameters, TestContext.Current.CancellationToken) + var networks = await dockerClient.Networks.ListNetworksAsync(networksListParameters, TestContext.Current.CancellationToken) .ConfigureAwait(true); - var response = await client.Volumes.ListAsync(volumesListParameters, TestContext.Current.CancellationToken) + var response = await dockerClient.Volumes.ListAsync(volumesListParameters, TestContext.Current.CancellationToken) .ConfigureAwait(true); // Then diff --git a/tests/Testcontainers.Platform.Linux.Tests/ReusableResourceTest.cs b/tests/Testcontainers.Platform.Linux.Tests/ReusableResourceTest.cs index 93ebbf726..bf3f95ed4 100644 --- a/tests/Testcontainers.Platform.Linux.Tests/ReusableResourceTest.cs +++ b/tests/Testcontainers.Platform.Linux.Tests/ReusableResourceTest.cs @@ -73,9 +73,7 @@ await Task.WhenAll(_disposables [Trait(nameof(DockerCli.DockerPlatform), nameof(DockerCli.DockerPlatform.Linux))] public async Task ShouldReuseExistingResource() { - using var clientConfiguration = TestcontainersSettings.OS.DockerEndpointAuthConfig.GetDockerClientConfiguration(Guid.NewGuid()); - - using var client = clientConfiguration.CreateClient(); + using var dockerClient = TestcontainersSettings.OS.DockerEndpointAuthConfig.GetDockerClientBuilder(Guid.NewGuid()).Build(); var containersListParameters = new ContainersListParameters { All = true, Filters = _filters }; @@ -83,13 +81,13 @@ public async Task ShouldReuseExistingResource() var volumesListParameters = new VolumesListParameters { Filters = _filters }; - var containers = await client.Containers.ListContainersAsync(containersListParameters, TestContext.Current.CancellationToken) + var containers = await dockerClient.Containers.ListContainersAsync(containersListParameters, TestContext.Current.CancellationToken) .ConfigureAwait(true); - var networks = await client.Networks.ListNetworksAsync(networksListParameters, TestContext.Current.CancellationToken) + var networks = await dockerClient.Networks.ListNetworksAsync(networksListParameters, TestContext.Current.CancellationToken) .ConfigureAwait(true); - var response = await client.Volumes.ListAsync(volumesListParameters, TestContext.Current.CancellationToken) + var response = await dockerClient.Volumes.ListAsync(volumesListParameters, TestContext.Current.CancellationToken) .ConfigureAwait(true); Assert.Single(containers); diff --git a/tests/Testcontainers.Tests/Unit/Configurations/DockerEndpointAuthenticationProviderTest.cs b/tests/Testcontainers.Tests/Unit/Configurations/DockerEndpointAuthenticationProviderTest.cs index 2ba73314f..972a20bf0 100644 --- a/tests/Testcontainers.Tests/Unit/Configurations/DockerEndpointAuthenticationProviderTest.cs +++ b/tests/Testcontainers.Tests/Unit/Configurations/DockerEndpointAuthenticationProviderTest.cs @@ -39,11 +39,9 @@ internal void AuthProviderShouldBeApplicable(IDockerEndpointAuthenticationProvid [ClassData(typeof(AuthConfigTestData))] internal void AuthConfigShouldGetDockerClientEndpoint(IDockerEndpointAuthenticationConfiguration authConfig, Uri dockerClientEndpoint) { - using (var dockerClientConfiguration = authConfig.GetDockerClientConfiguration()) - { - Assert.Equal(dockerClientEndpoint, authConfig.Endpoint); - Assert.Equal(dockerClientEndpoint, dockerClientConfiguration.EndpointBaseUri); - } + var dockerClient = authConfig.GetDockerClientBuilder().Build(); + Assert.Equal(dockerClientEndpoint, authConfig.Endpoint); + Assert.Equal(dockerClientEndpoint, dockerClient.Options.Endpoint); } public sealed class TestcontainersHostEndpointAuthenticationProviderTest diff --git a/tests/Testcontainers.Tests/Unit/Containers/Unix/ProtectDockerDaemonSocketTest.cs b/tests/Testcontainers.Tests/Unit/Containers/Unix/ProtectDockerDaemonSocketTest.cs index 19dee143f..116c44064 100644 --- a/tests/Testcontainers.Tests/Unit/Containers/Unix/ProtectDockerDaemonSocketTest.cs +++ b/tests/Testcontainers.Tests/Unit/Containers/Unix/ProtectDockerDaemonSocketTest.cs @@ -4,6 +4,7 @@ namespace DotNet.Testcontainers.Tests.Unit using System.Linq; using System.Threading.Tasks; using Docker.DotNet; + using Docker.DotNet.Handler.Abstractions; using DotNet.Testcontainers.Builders; using DotNet.Testcontainers.Clients; using DotNet.Testcontainers.Configurations; @@ -41,11 +42,11 @@ public Version Version public Uri Endpoint => _authConfig.Endpoint; - public Credentials Credentials - => _authConfig.Credentials; + public IAuthProvider AuthProvider + => _authConfig.AuthProvider; - public DockerClientConfiguration GetDockerClientConfiguration(Guid sessionId = default) - => _authConfig.GetDockerClientConfiguration(sessionId); + public DockerClientBuilder GetDockerClientBuilder(Guid sessionId = default) + => _authConfig.GetDockerClientBuilder(sessionId).WithApiVersion(Version); [Fact] public async Task GetVersionReturnsVersion() From 4a237563cc610582a049b36b3db88168fdc45a40 Mon Sep 17 00:00:00 2001 From: Andre Hofmeister <9199345+HofmeisterAn@users.noreply.github.com> Date: Wed, 18 Mar 2026 19:07:23 +0100 Subject: [PATCH 2/2] chore: Rename ctor param --- .../DockerEndpointAuthenticationConfiguration.cs | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/Testcontainers/Configurations/AuthConfigs/DockerEndpointAuthenticationConfiguration.cs b/src/Testcontainers/Configurations/AuthConfigs/DockerEndpointAuthenticationConfiguration.cs index f934e7ad3..b7a6e0c31 100644 --- a/src/Testcontainers/Configurations/AuthConfigs/DockerEndpointAuthenticationConfiguration.cs +++ b/src/Testcontainers/Configurations/AuthConfigs/DockerEndpointAuthenticationConfiguration.cs @@ -28,11 +28,11 @@ namespace DotNet.Testcontainers.Configurations /// Initializes a new instance of the struct. /// /// The Docker API endpoint. - /// The Docker API authentication provider. - public DockerEndpointAuthenticationConfiguration(Uri endpoint, IAuthProvider credentials = null) + /// The Docker API authentication provider. + public DockerEndpointAuthenticationConfiguration(Uri endpoint, IAuthProvider authProvider = null) { Endpoint = endpoint; - AuthProvider = credentials; + AuthProvider = authProvider; } ///