diff --git a/src/Testcontainers.Keycloak/KeycloakContainer.cs b/src/Testcontainers.Keycloak/KeycloakContainer.cs
index b2a9b93fb..775b14834 100644
--- a/src/Testcontainers.Keycloak/KeycloakContainer.cs
+++ b/src/Testcontainers.Keycloak/KeycloakContainer.cs
@@ -4,8 +4,6 @@ namespace Testcontainers.Keycloak;
[PublicAPI]
public sealed class KeycloakContainer : DockerContainer
{
- private readonly KeycloakConfiguration _configuration;
-
///
/// Initializes a new instance of the class.
///
@@ -14,7 +12,6 @@ public sealed class KeycloakContainer : DockerContainer
public KeycloakContainer(KeycloakConfiguration configuration, ILogger logger)
: base(configuration, logger)
{
- _configuration = configuration;
}
///
diff --git a/src/Testcontainers/Builders/TestcontainersCloudEndpointAuthenticationProvider.cs b/src/Testcontainers/Builders/TestcontainersCloudEndpointAuthenticationProvider.cs
new file mode 100644
index 000000000..89482881d
--- /dev/null
+++ b/src/Testcontainers/Builders/TestcontainersCloudEndpointAuthenticationProvider.cs
@@ -0,0 +1,155 @@
+namespace DotNet.Testcontainers.Builders
+{
+ using System;
+ using System.Text.Json;
+ using DotNet.Testcontainers.Configurations;
+ using DotNet.Testcontainers.Images;
+ using JetBrains.Annotations;
+
+ ///
+ /// When configuring the endpoint for a container runtime, the `DOCKER_HOST`
+ /// environment variable is commonly used. This approach can become messy due to
+ /// the variety of alternative container runtimes. Even though Testcontainers logs
+ /// the container runtime that is being used, developers find it difficult to
+ /// determine which runtime is driving the tests on their environment. If multiple
+ /// container runtimes are present in a development environment, we prioritize
+ /// Testcontainers Cloud if it is running.
+ ///
+ [PublicAPI]
+ internal sealed class TestcontainersHostEndpointAuthenticationProvider : DockerEndpointAuthenticationProvider, ICustomConfiguration
+ {
+ private readonly ICustomConfiguration _customConfiguration;
+
+ private readonly Uri _dockerEngine;
+
+ ///
+ /// Initializes a new instance of the class.
+ ///
+ public TestcontainersHostEndpointAuthenticationProvider()
+ {
+ _customConfiguration = new TestcontainersHostConfiguration();
+ _dockerEngine = GetDockerHost();
+ }
+
+ ///
+ /// Initializes a new instance of the class.
+ ///
+ /// A list of Java properties file lines.
+ public TestcontainersHostEndpointAuthenticationProvider(params string[] lines)
+ {
+ _customConfiguration = new TestcontainersHostConfiguration(lines);
+ _dockerEngine = GetDockerHost();
+ }
+
+ ///
+ public override bool IsApplicable()
+ {
+ return _dockerEngine != null && "tcp".Equals(_dockerEngine.Scheme, StringComparison.OrdinalIgnoreCase);
+ }
+
+ ///
+ public override IDockerEndpointAuthenticationConfiguration GetAuthConfig()
+ {
+ return new DockerEndpointAuthenticationConfiguration(_dockerEngine);
+ }
+
+ ///
+ public string GetDockerConfig()
+ {
+ return _customConfiguration.GetDockerConfig();
+ }
+
+ ///
+ public Uri GetDockerHost()
+ {
+ return _customConfiguration.GetDockerHost();
+ }
+
+ ///
+ public string GetDockerHostOverride()
+ {
+ return _customConfiguration.GetDockerHostOverride();
+ }
+
+ ///
+ public string GetDockerSocketOverride()
+ {
+ return _customConfiguration.GetDockerSocketOverride();
+ }
+
+ ///
+ public JsonDocument GetDockerAuthConfig()
+ {
+ return _customConfiguration.GetDockerAuthConfig();
+ }
+
+ ///
+ public string GetDockerCertPath()
+ {
+ return _customConfiguration.GetDockerCertPath();
+ }
+
+ ///
+ public bool GetDockerTls()
+ {
+ return _customConfiguration.GetDockerTls();
+ }
+
+ ///
+ public bool GetDockerTlsVerify()
+ {
+ return _customConfiguration.GetDockerTlsVerify();
+ }
+
+ ///
+ public bool GetRyukDisabled()
+ {
+ return _customConfiguration.GetRyukDisabled();
+ }
+
+ ///
+ public bool GetRyukContainerPrivileged()
+ {
+ return _customConfiguration.GetRyukContainerPrivileged();
+ }
+
+ ///
+ public IImage GetRyukContainerImage()
+ {
+ return _customConfiguration.GetRyukContainerImage();
+ }
+
+ ///
+ public string GetHubImageNamePrefix()
+ {
+ return _customConfiguration.GetHubImageNamePrefix();
+ }
+
+ private sealed class TestcontainersHostConfiguration : PropertiesFileConfiguration
+ {
+ public TestcontainersHostConfiguration()
+ {
+ }
+
+ public TestcontainersHostConfiguration(params string[] lines)
+ : base(lines)
+ {
+ }
+
+ protected override Uri GetDockerHost(string propertyName)
+ {
+ return base.GetDockerHost("tc.host");
+ }
+
+ protected override string GetDockerHostOverride(string propertyName)
+ {
+ return null;
+ }
+
+ protected override string GetDockerSocketOverride(string propertyName)
+ {
+ return null;
+ }
+ }
+ }
+}
diff --git a/src/Testcontainers/Configurations/CustomConfiguration.cs b/src/Testcontainers/Configurations/CustomConfiguration.cs
index e062537fc..155e2dbe2 100644
--- a/src/Testcontainers/Configurations/CustomConfiguration.cs
+++ b/src/Testcontainers/Configurations/CustomConfiguration.cs
@@ -14,27 +14,27 @@ protected CustomConfiguration(IReadOnlyDictionary properties)
_properties = properties;
}
- protected string GetDockerConfig(string propertyName)
+ protected virtual string GetDockerConfig(string propertyName)
{
return GetPropertyValue(propertyName);
}
- protected Uri GetDockerHost(string propertyName)
+ protected virtual Uri GetDockerHost(string propertyName)
{
return _properties.TryGetValue(propertyName, out var propertyValue) && Uri.TryCreate(propertyValue, UriKind.RelativeOrAbsolute, out var dockerHost) ? dockerHost : null;
}
- protected string GetDockerHostOverride(string propertyName)
+ protected virtual string GetDockerHostOverride(string propertyName)
{
return GetPropertyValue(propertyName);
}
- protected string GetDockerSocketOverride(string propertyName)
+ protected virtual string GetDockerSocketOverride(string propertyName)
{
return GetPropertyValue(propertyName);
}
- protected JsonDocument GetDockerAuthConfig(string propertyName)
+ protected virtual JsonDocument GetDockerAuthConfig(string propertyName)
{
_ = _properties.TryGetValue(propertyName, out var propertyValue);
@@ -53,32 +53,32 @@ protected JsonDocument GetDockerAuthConfig(string propertyName)
}
}
- protected string GetDockerCertPath(string propertyName)
+ protected virtual string GetDockerCertPath(string propertyName)
{
return GetPropertyValue(propertyName);
}
- protected bool GetDockerTls(string propertyName)
+ protected virtual bool GetDockerTls(string propertyName)
{
return GetPropertyValue(propertyName);
}
- protected bool GetDockerTlsVerify(string propertyName)
+ protected virtual bool GetDockerTlsVerify(string propertyName)
{
return GetPropertyValue(propertyName);
}
- protected bool GetRyukDisabled(string propertyName)
+ protected virtual bool GetRyukDisabled(string propertyName)
{
return GetPropertyValue(propertyName);
}
- protected bool GetRyukContainerPrivileged(string propertyName)
+ protected virtual bool GetRyukContainerPrivileged(string propertyName)
{
return GetPropertyValue(propertyName);
}
- protected IImage GetRyukContainerImage(string propertyName)
+ protected virtual IImage GetRyukContainerImage(string propertyName)
{
_ = _properties.TryGetValue(propertyName, out var propertyValue);
@@ -97,7 +97,7 @@ protected IImage GetRyukContainerImage(string propertyName)
}
}
- protected string GetHubImageNamePrefix(string propertyName)
+ protected virtual string GetHubImageNamePrefix(string propertyName)
{
return GetPropertyValue(propertyName);
}
diff --git a/src/Testcontainers/Configurations/EnvironmentConfiguration.cs b/src/Testcontainers/Configurations/EnvironmentConfiguration.cs
index d7635cd9a..471cfc9c8 100644
--- a/src/Testcontainers/Configurations/EnvironmentConfiguration.cs
+++ b/src/Testcontainers/Configurations/EnvironmentConfiguration.cs
@@ -8,7 +8,7 @@ namespace DotNet.Testcontainers.Configurations
///
/// Reads and maps the custom configurations from the environment variables.
///
- internal sealed class EnvironmentConfiguration : CustomConfiguration, ICustomConfiguration
+ internal class EnvironmentConfiguration : CustomConfiguration, ICustomConfiguration
{
private const string DockerConfig = "DOCKER_CONFIG";
diff --git a/src/Testcontainers/Configurations/PropertiesFileConfiguration.cs b/src/Testcontainers/Configurations/PropertiesFileConfiguration.cs
index fb91bd9da..6d0367c1f 100644
--- a/src/Testcontainers/Configurations/PropertiesFileConfiguration.cs
+++ b/src/Testcontainers/Configurations/PropertiesFileConfiguration.cs
@@ -9,7 +9,7 @@ namespace DotNet.Testcontainers.Configurations
///
/// Reads and maps the custom configurations from the Testcontainers properties file.
///
- internal sealed class PropertiesFileConfiguration : CustomConfiguration, ICustomConfiguration
+ internal class PropertiesFileConfiguration : CustomConfiguration, ICustomConfiguration
{
static PropertiesFileConfiguration()
{
diff --git a/src/Testcontainers/Configurations/TestcontainersSettings.cs b/src/Testcontainers/Configurations/TestcontainersSettings.cs
index f8308cfa9..9a926d8e0 100644
--- a/src/Testcontainers/Configurations/TestcontainersSettings.cs
+++ b/src/Testcontainers/Configurations/TestcontainersSettings.cs
@@ -21,9 +21,11 @@ public static class TestcontainersSettings
{
private static readonly ManualResetEventSlim ManualResetEvent = new ManualResetEventSlim(false);
- private static readonly IDockerEndpointAuthenticationConfiguration DockerEndpointAuthConfig =
+ [CanBeNull]
+ private static readonly IDockerEndpointAuthenticationProvider DockerEndpointAuthProvider =
new IDockerEndpointAuthenticationProvider[]
{
+ new TestcontainersHostEndpointAuthenticationProvider(),
new MTlsEndpointAuthenticationProvider(),
new TlsEndpointAuthenticationProvider(),
new EnvironmentEndpointAuthenticationProvider(),
@@ -32,9 +34,11 @@ public static class TestcontainersSettings
new RootlessUnixEndpointAuthenticationProvider(),
}
.Where(authProvider => authProvider.IsApplicable())
- .Where(authProvider => authProvider.IsAvailable())
- .Select(authProvider => authProvider.GetAuthConfig())
- .FirstOrDefault();
+ .FirstOrDefault(authProvider => authProvider.IsAvailable());
+
+ [CanBeNull]
+ private static readonly IDockerEndpointAuthenticationConfiguration DockerEndpointAuthConfig =
+ DockerEndpointAuthProvider?.GetAuthConfig();
static TestcontainersSettings()
{
@@ -103,14 +107,16 @@ static TestcontainersSettings()
///
[CanBeNull]
public static string DockerHostOverride { get; set; }
- = PropertiesFileConfiguration.Instance.GetDockerHostOverride() ?? EnvironmentConfiguration.Instance.GetDockerHostOverride();
+ = DockerEndpointAuthProvider is ICustomConfiguration config
+ ? config.GetDockerHostOverride() : PropertiesFileConfiguration.Instance.GetDockerHostOverride() ?? EnvironmentConfiguration.Instance.GetDockerHostOverride();
///
/// Gets or sets the Docker socket override value.
///
[CanBeNull]
public static string DockerSocketOverride { get; set; }
- = PropertiesFileConfiguration.Instance.GetDockerSocketOverride() ?? EnvironmentConfiguration.Instance.GetDockerSocketOverride();
+ = DockerEndpointAuthProvider is ICustomConfiguration config
+ ? config.GetDockerSocketOverride() : PropertiesFileConfiguration.Instance.GetDockerSocketOverride() ?? EnvironmentConfiguration.Instance.GetDockerSocketOverride();
///
/// Gets or sets a value indicating whether the is enabled or not.
diff --git a/tests/Testcontainers.Tests/Fixtures/Images/HealthCheckFixture.cs b/tests/Testcontainers.Tests/Fixtures/Images/HealthCheckFixture.cs
index bc0ea44d5..db4034d3e 100644
--- a/tests/Testcontainers.Tests/Fixtures/Images/HealthCheckFixture.cs
+++ b/tests/Testcontainers.Tests/Fixtures/Images/HealthCheckFixture.cs
@@ -3,7 +3,6 @@ namespace DotNet.Testcontainers.Tests.Fixtures
using System.IO;
using System.Threading.Tasks;
using DotNet.Testcontainers.Builders;
- using DotNet.Testcontainers.Containers;
using DotNet.Testcontainers.Images;
using JetBrains.Annotations;
using Xunit;
diff --git a/tests/Testcontainers.Tests/Unit/Configurations/DockerEndpointAuthenticationProviderTest.cs b/tests/Testcontainers.Tests/Unit/Configurations/DockerEndpointAuthenticationProviderTest.cs
index 8b7f999d5..61663a0a5 100644
--- a/tests/Testcontainers.Tests/Unit/Configurations/DockerEndpointAuthenticationProviderTest.cs
+++ b/tests/Testcontainers.Tests/Unit/Configurations/DockerEndpointAuthenticationProviderTest.cs
@@ -46,13 +46,30 @@ internal void AuthConfigShouldGetDockerClientEndpoint(IDockerEndpointAuthenticat
}
}
+ public sealed class TestcontainersHostEndpointAuthenticationProviderTest
+ {
+ [Fact]
+ public void GetDockerHostOverrideReturnsNull()
+ {
+ ICustomConfiguration customConfiguration = new TestcontainersHostEndpointAuthenticationProvider("host.override=host.docker.internal");
+ Assert.Null(customConfiguration.GetDockerHostOverride());
+ }
+
+ [Fact]
+ public void GetDockerSocketOverrideReturnsNull()
+ {
+ ICustomConfiguration customConfiguration = new TestcontainersHostEndpointAuthenticationProvider("docker.socket.override=/var/run/docker.sock");
+ Assert.Null(customConfiguration.GetDockerSocketOverride());
+ }
+ }
+
private sealed class AuthProviderTestData : List