diff --git a/src/DotNet.Testcontainers/Builders/DockerEndpointAuthenticationProvider.cs b/src/DotNet.Testcontainers/Builders/DockerEndpointAuthenticationProvider.cs new file mode 100644 index 000000000..db372275b --- /dev/null +++ b/src/DotNet.Testcontainers/Builders/DockerEndpointAuthenticationProvider.cs @@ -0,0 +1,23 @@ +namespace DotNet.Testcontainers.Builders +{ + using System.Linq; + using DotNet.Testcontainers.Configurations; + + /// + internal sealed class DockerEndpointAuthenticationProvider : IAuthenticationProvider + { + /// + public bool IsApplicable() + { + return true; + } + + /// + public IDockerEndpointAuthenticationConfiguration GetAuthConfig(string hostname) + { + return new IAuthenticationProvider[] { new EnvironmentEndpointAuthenticationProvider(), new NpipeEndpointAuthenticationProvider(), new UnixEndpointAuthenticationProvider() } + .First(authenticationProvider => authenticationProvider.IsApplicable()) + .GetAuthConfig(hostname); + } + } +} diff --git a/src/DotNet.Testcontainers/Builders/EnvironmentEndpointAuthenticationProvider.cs b/src/DotNet.Testcontainers/Builders/EnvironmentEndpointAuthenticationProvider.cs new file mode 100644 index 000000000..b7d026339 --- /dev/null +++ b/src/DotNet.Testcontainers/Builders/EnvironmentEndpointAuthenticationProvider.cs @@ -0,0 +1,28 @@ +namespace DotNet.Testcontainers.Builders +{ + using System; + using DotNet.Testcontainers.Configurations; + + /// + internal sealed class EnvironmentEndpointAuthenticationProvider : IAuthenticationProvider + { + private readonly Uri dockerEngine; + + public EnvironmentEndpointAuthenticationProvider() + { + this.dockerEngine = Uri.TryCreate(Environment.GetEnvironmentVariable("DOCKER_HOST"), UriKind.RelativeOrAbsolute, out var dockerHost) ? dockerHost : null; + } + + /// + public bool IsApplicable() + { + return this.dockerEngine != null; + } + + /// + public IDockerEndpointAuthenticationConfiguration GetAuthConfig(string hostname) + { + return new DockerEndpointAuthenticationConfiguration(this.dockerEngine); + } + } +} diff --git a/src/DotNet.Testcontainers/Builders/NpipeEndpointAuthenticationProvider.cs b/src/DotNet.Testcontainers/Builders/NpipeEndpointAuthenticationProvider.cs new file mode 100644 index 000000000..7ec26fc1f --- /dev/null +++ b/src/DotNet.Testcontainers/Builders/NpipeEndpointAuthenticationProvider.cs @@ -0,0 +1,28 @@ +namespace DotNet.Testcontainers.Builders +{ + using System; + using System.Runtime.InteropServices; + using DotNet.Testcontainers.Configurations; + + /// + internal sealed class NpipeEndpointAuthenticationProvider : IAuthenticationProvider + { +#pragma warning disable S1075 + + private static readonly Uri DockerEngine = new Uri("npipe://./pipe/docker_engine"); + +#pragma warning restore S1075 + + /// + public bool IsApplicable() + { + return RuntimeInformation.IsOSPlatform(OSPlatform.Windows); + } + + /// + public IDockerEndpointAuthenticationConfiguration GetAuthConfig(string hostname) + { + return new DockerEndpointAuthenticationConfiguration(DockerEngine); + } + } +} diff --git a/src/DotNet.Testcontainers/Builders/UnixEndpointAuthenticationProvider.cs b/src/DotNet.Testcontainers/Builders/UnixEndpointAuthenticationProvider.cs new file mode 100644 index 000000000..50b40020b --- /dev/null +++ b/src/DotNet.Testcontainers/Builders/UnixEndpointAuthenticationProvider.cs @@ -0,0 +1,24 @@ +namespace DotNet.Testcontainers.Builders +{ + using System; + using System.Runtime.InteropServices; + using DotNet.Testcontainers.Configurations; + + /// + internal sealed class UnixEndpointAuthenticationProvider : IAuthenticationProvider + { + private static readonly Uri DockerEngine = new Uri("unix:/var/run/docker.sock"); + + /// + public bool IsApplicable() + { + return !RuntimeInformation.IsOSPlatform(OSPlatform.Windows); + } + + /// + public IDockerEndpointAuthenticationConfiguration GetAuthConfig(string hostname) + { + return new DockerEndpointAuthenticationConfiguration(DockerEngine); + } + } +} diff --git a/src/DotNet.Testcontainers/Configurations/IDockerEndpointAuthenticationConfiguration.cs b/src/DotNet.Testcontainers/Configurations/IDockerEndpointAuthenticationConfiguration.cs index d34e8b226..1b9bb3f7e 100644 --- a/src/DotNet.Testcontainers/Configurations/IDockerEndpointAuthenticationConfiguration.cs +++ b/src/DotNet.Testcontainers/Configurations/IDockerEndpointAuthenticationConfiguration.cs @@ -2,21 +2,24 @@ { using System; using Docker.DotNet; + using JetBrains.Annotations; /// - /// A authentication configuration to authenticate against private Docker clients. + /// An authentication configuration to authenticate against private Docker clients. /// public interface IDockerEndpointAuthenticationConfiguration { /// /// Gets the Docker API endpoint. /// + [NotNull] Uri Endpoint { get; } /// /// Gets the Docker client configuration. /// /// The Docker client configuration. + [NotNull] DockerClientConfiguration GetDockerClientConfiguration(); } } diff --git a/src/DotNet.Testcontainers/Configurations/Images/IDockerRegistryAuthenticationConfiguration.cs b/src/DotNet.Testcontainers/Configurations/Images/IDockerRegistryAuthenticationConfiguration.cs index 63b610178..9ad062cc8 100644 --- a/src/DotNet.Testcontainers/Configurations/Images/IDockerRegistryAuthenticationConfiguration.cs +++ b/src/DotNet.Testcontainers/Configurations/Images/IDockerRegistryAuthenticationConfiguration.cs @@ -3,7 +3,7 @@ namespace DotNet.Testcontainers.Configurations using JetBrains.Annotations; /// - /// A authentication configuration to authenticate against private Docker registries. + /// An authentication configuration to authenticate against private Docker registries. /// public interface IDockerRegistryAuthenticationConfiguration { diff --git a/src/DotNet.Testcontainers/Configurations/Unix.cs b/src/DotNet.Testcontainers/Configurations/Unix.cs index 495e4ec03..635259a9b 100644 --- a/src/DotNet.Testcontainers/Configurations/Unix.cs +++ b/src/DotNet.Testcontainers/Configurations/Unix.cs @@ -1,6 +1,7 @@ namespace DotNet.Testcontainers.Configurations { using System; + using DotNet.Testcontainers.Builders; using JetBrains.Annotations; /// @@ -9,14 +10,13 @@ namespace DotNet.Testcontainers.Configurations [PublicAPI] public sealed class Unix : IOperatingSystem { - private static readonly Uri DockerEngine = new Uri("unix:/var/run/docker.sock"); - /// /// Initializes a new instance of the class. /// [PublicAPI] public Unix() - : this(DockerEngine) + : this(new DockerEndpointAuthenticationProvider() + .GetAuthConfig(null)) { } @@ -36,8 +36,18 @@ public Unix(string endpoint) /// The Docker API endpoint. [PublicAPI] public Unix(Uri endpoint) + : this(new DockerEndpointAuthenticationConfiguration(endpoint)) + { + } + + /// + /// Initializes a new instance of the class. + /// + /// The Docker endpoint authentication configuration. + [PublicAPI] + public Unix(IDockerEndpointAuthenticationConfiguration dockerEndpointAuthConfig) { - this.DockerEndpointAuthConfig = new DockerEndpointAuthenticationConfiguration(endpoint); + this.DockerEndpointAuthConfig = dockerEndpointAuthConfig; } /// diff --git a/src/DotNet.Testcontainers/Configurations/Windows.cs b/src/DotNet.Testcontainers/Configurations/Windows.cs index 911e32c2b..226d2f0cc 100644 --- a/src/DotNet.Testcontainers/Configurations/Windows.cs +++ b/src/DotNet.Testcontainers/Configurations/Windows.cs @@ -1,6 +1,7 @@ namespace DotNet.Testcontainers.Configurations { using System; + using DotNet.Testcontainers.Builders; using JetBrains.Annotations; /// @@ -9,18 +10,13 @@ namespace DotNet.Testcontainers.Configurations [PublicAPI] public sealed class Windows : IOperatingSystem { -#pragma warning disable S1075 - - private static readonly Uri DockerEngine = new Uri("npipe://./pipe/docker_engine"); - -#pragma warning restore S1075 - /// /// Initializes a new instance of the class. /// [PublicAPI] public Windows() - : this(DockerEngine) + : this(new DockerEndpointAuthenticationProvider() + .GetAuthConfig(null)) { } @@ -40,8 +36,18 @@ public Windows(string endpoint) /// The Docker API endpoint. [PublicAPI] public Windows(Uri endpoint) + : this(new DockerEndpointAuthenticationConfiguration(endpoint)) + { + } + + /// + /// Initializes a new instance of the class. + /// + /// The Docker endpoint authentication configuration. + [PublicAPI] + public Windows(IDockerEndpointAuthenticationConfiguration dockerEndpointAuthConfig) { - this.DockerEndpointAuthConfig = new DockerEndpointAuthenticationConfiguration(endpoint); + this.DockerEndpointAuthConfig = dockerEndpointAuthConfig; } /// diff --git a/tests/DotNet.Testcontainers.Tests/Unit/Configurations/DockerEndpointAuthenticationProviderTest.cs b/tests/DotNet.Testcontainers.Tests/Unit/Configurations/DockerEndpointAuthenticationProviderTest.cs new file mode 100644 index 000000000..21c880d19 --- /dev/null +++ b/tests/DotNet.Testcontainers.Tests/Unit/Configurations/DockerEndpointAuthenticationProviderTest.cs @@ -0,0 +1,35 @@ +namespace DotNet.Testcontainers.Tests.Unit +{ + using System; + using DotNet.Testcontainers.Builders; + using Xunit; + + [CollectionDefinition(nameof(DockerEndpointAuthenticationProviderTest), DisableParallelization = true)] + public sealed class DockerEndpointAuthenticationProviderTest + { + [Collection(nameof(DockerEndpointAuthenticationProviderTest))] + public sealed class EnvironmentEndpointAuthenticationProviderTest : IDisposable + { + private const string DockerHost = "127.0.0.1:2375"; + + public EnvironmentEndpointAuthenticationProviderTest() + { + Environment.SetEnvironmentVariable("DOCKER_HOST", DockerHost); + } + + [Fact] + public void GetAuthConfig() + { + using (var clientConfiguration = new DockerEndpointAuthenticationProvider().GetAuthConfig(null)!.GetDockerClientConfiguration()) + { + Assert.Equal(DockerHost, clientConfiguration.EndpointBaseUri.ToString()); + } + } + + public void Dispose() + { + Environment.SetEnvironmentVariable("DOCKER_HOST", null); + } + } + } +} diff --git a/tests/DotNet.Testcontainers.Tests/Unit/Configurations/DockerRegistryAuthenticationProviderTest.cs b/tests/DotNet.Testcontainers.Tests/Unit/Configurations/DockerRegistryAuthenticationProviderTest.cs index c955e4a34..33ccb0486 100644 --- a/tests/DotNet.Testcontainers.Tests/Unit/Configurations/DockerRegistryAuthenticationProviderTest.cs +++ b/tests/DotNet.Testcontainers.Tests/Unit/Configurations/DockerRegistryAuthenticationProviderTest.cs @@ -40,7 +40,7 @@ public void GetHostnameFromDockerImage(string dockerImageName, string hostname) [Fact] public void ShouldGetDefaultDockerRegistryAuthenticationConfiguration() { - IAuthenticationProvider authenticationProvider = new DockerRegistryAuthenticationProvider("/tmp/docker.config", TestcontainersSettings.Logger); + var authenticationProvider = new DockerRegistryAuthenticationProvider("/tmp/docker.config", TestcontainersSettings.Logger); Assert.Equal(default(DockerRegistryAuthenticationConfiguration), authenticationProvider.GetAuthConfig(DockerRegistry)); } @@ -60,7 +60,7 @@ public void ShouldGetNull(string jsonDocument, bool isApplicable) var jsonElement = JsonDocument.Parse(jsonDocument).RootElement; // When - IAuthenticationProvider authenticationProvider = new Base64Provider(jsonElement, TestcontainersSettings.Logger); + var authenticationProvider = new Base64Provider(jsonElement, TestcontainersSettings.Logger); var authConfig = authenticationProvider.GetAuthConfig(DockerRegistry); // Then @@ -76,7 +76,7 @@ public void ShouldGetAuthConfig() var jsonElement = JsonDocument.Parse(jsonDocument).RootElement; // When - IAuthenticationProvider authenticationProvider = new Base64Provider(jsonElement, TestcontainersSettings.Logger); + var authenticationProvider = new Base64Provider(jsonElement, TestcontainersSettings.Logger); var authConfig = authenticationProvider.GetAuthConfig(DockerRegistry); // Then @@ -100,7 +100,7 @@ public void ShouldGetNull(string jsonDocument, bool isApplicable) var jsonElement = JsonDocument.Parse(jsonDocument).RootElement; // When - IAuthenticationProvider authenticationProvider = new CredsStoreProvider(jsonElement, TestcontainersSettings.Logger); + var authenticationProvider = new CredsStoreProvider(jsonElement, TestcontainersSettings.Logger); var authConfig = authenticationProvider.GetAuthConfig(DockerRegistry); // Then @@ -120,7 +120,7 @@ public void ShouldGetAuthConfig() var jsonElement = JsonDocument.Parse(jsonDocument).RootElement; // When - IAuthenticationProvider authenticationProvider = new CredsStoreProvider(jsonElement, TestcontainersSettings.Logger); + var authenticationProvider = new CredsStoreProvider(jsonElement, TestcontainersSettings.Logger); var authConfig = authenticationProvider.GetAuthConfig(DockerRegistry); // Then diff --git a/tests/DotNet.Testcontainers.Tests/Unit/Containers/Unix/TestcontainersContainerTest.cs b/tests/DotNet.Testcontainers.Tests/Unit/Containers/Unix/TestcontainersContainerTest.cs index 913222f0f..1ade517d6 100644 --- a/tests/DotNet.Testcontainers.Tests/Unit/Containers/Unix/TestcontainersContainerTest.cs +++ b/tests/DotNet.Testcontainers.Tests/Unit/Containers/Unix/TestcontainersContainerTest.cs @@ -22,6 +22,21 @@ public static class TestcontainersContainerTest [Collection(nameof(Testcontainers))] public sealed class WithConfiguration { + [Fact] + public void GetAuthConfig() + { + // Given + var expected = new UnixEndpointAuthenticationProvider().GetAuthConfig(null); + + // When + var actual = new DockerEndpointAuthenticationProvider().GetAuthConfig(null); + + // Then + Assert.NotNull(expected); + Assert.NotNull(actual); + Assert.Equal(expected.Endpoint, actual.Endpoint); + } + [Fact] public async Task IsLinuxEngineEnabled() { diff --git a/tests/DotNet.Testcontainers.Tests/Unit/Containers/Windows/TestcontainersContainerTest.cs b/tests/DotNet.Testcontainers.Tests/Unit/Containers/Windows/TestcontainersContainerTest.cs index 5ca2f0ed5..36493d6e0 100644 --- a/tests/DotNet.Testcontainers.Tests/Unit/Containers/Windows/TestcontainersContainerTest.cs +++ b/tests/DotNet.Testcontainers.Tests/Unit/Containers/Windows/TestcontainersContainerTest.cs @@ -11,6 +11,21 @@ public static class TestcontainersContainerTest [Collection(nameof(Testcontainers))] public sealed class WithConfiguration { + [SkipOnLinuxEngine] + public void GetAuthConfig() + { + // Given + var expected = new NpipeEndpointAuthenticationProvider().GetAuthConfig(null); + + // When + var actual = new DockerEndpointAuthenticationProvider().GetAuthConfig(null); + + // Then + Assert.NotNull(expected); + Assert.NotNull(actual); + Assert.Equal(expected.Endpoint, actual.Endpoint); + } + [SkipOnLinuxEngine] public async Task IsWindowsEngineEnabled() {