From 02f3828d0ecb4b7f34b4e29e3a4040a6db18e5dd Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?C=C3=A9dric=20Luthi?= Date: Wed, 6 Mar 2024 20:20:18 +0100 Subject: [PATCH] feat: Make the wait strategy timeout configurable Also default to 5 minutes instead of infinite. --- .../Configurations/TestcontainersSettings.cs | 6 ++++ .../Containers/DockerContainer.cs | 11 +++++-- .../Unix/TestcontainersContainerTest.cs | 13 +++++++++ .../Unit/UseWaitTimeoutAttribute.cs | 29 +++++++++++++++++++ 4 files changed, 57 insertions(+), 2 deletions(-) create mode 100644 tests/Testcontainers.Tests/Unit/UseWaitTimeoutAttribute.cs diff --git a/src/Testcontainers/Configurations/TestcontainersSettings.cs b/src/Testcontainers/Configurations/TestcontainersSettings.cs index 40735c2dc..c2dcb12db 100644 --- a/src/Testcontainers/Configurations/TestcontainersSettings.cs +++ b/src/Testcontainers/Configurations/TestcontainersSettings.cs @@ -103,6 +103,12 @@ static TestcontainersSettings() public static string HubImageNamePrefix { get; set; } = EnvironmentConfiguration.Instance.GetHubImageNamePrefix() ?? PropertiesFileConfiguration.Instance.GetHubImageNamePrefix(); + /// + /// Gets or sets the maximum time for a wait strategy to execute before a is thrown. + /// Defaults to 5 minutes. + /// + public static TimeSpan WaitTimeout { get; set; } = TimeSpan.FromMinutes(5); + /// /// Gets or sets the logger. /// diff --git a/src/Testcontainers/Containers/DockerContainer.cs b/src/Testcontainers/Containers/DockerContainer.cs index 9d846d40f..2bd639830 100644 --- a/src/Testcontainers/Containers/DockerContainer.cs +++ b/src/Testcontainers/Containers/DockerContainer.cs @@ -503,8 +503,15 @@ await _configuration.StartupCallback(this, ct) foreach (var waitStrategy in _configuration.WaitStrategies) { - await WaitStrategy.WaitUntilAsync(() => CheckWaitStrategyAsync(waitStrategy), TimeSpan.FromSeconds(1), Timeout.InfiniteTimeSpan, ct) - .ConfigureAwait(false); + try + { + await WaitStrategy.WaitUntilAsync(() => CheckWaitStrategyAsync(waitStrategy), TimeSpan.FromSeconds(1), TestcontainersSettings.WaitTimeout, ct) + .ConfigureAwait(false); + } + catch (TimeoutException exception) when (exception.Source == "Testcontainers") + { + throw new TimeoutException(FormattableString.Invariant($"The {_container.Config.Image} container failed to complete readiness checks after waiting for {TestcontainersSettings.WaitTimeout.TotalMinutes:0.##} minutes (configurable with TestcontainersSettings.WaitTimeout).")); + } } Logger.CompleteReadinessCheck(_container.ID); diff --git a/tests/Testcontainers.Tests/Unit/Containers/Unix/TestcontainersContainerTest.cs b/tests/Testcontainers.Tests/Unit/Containers/Unix/TestcontainersContainerTest.cs index 2d8bdd473..d3d1a053b 100644 --- a/tests/Testcontainers.Tests/Unit/Containers/Unix/TestcontainersContainerTest.cs +++ b/tests/Testcontainers.Tests/Unit/Containers/Unix/TestcontainersContainerTest.cs @@ -525,6 +525,19 @@ public async Task PullPolicyNever() await Assert.ThrowsAnyAsync(() => container.StartAsync()) .ConfigureAwait(true); } + + [Fact] + [UseWaitTimeout(seconds: 1)] + public async Task WaitStrategyTimeout() + { + await using var container = new ContainerBuilder() + .WithImage(CommonImages.Alpine) + .WithWaitStrategy(Wait.ForUnixContainer().AddCustomWaitStrategy(new WaitUntilFiveSecondsPassedFixture())) + .Build(); + + var exception = await Assert.ThrowsAsync(() => container.StartAsync()); + Assert.Equal("The alpine:3.17 container failed to complete readiness checks after waiting for 0.02 minutes (configurable with TestcontainersSettings.WaitTimeout).", exception.Message); + } } } } diff --git a/tests/Testcontainers.Tests/Unit/UseWaitTimeoutAttribute.cs b/tests/Testcontainers.Tests/Unit/UseWaitTimeoutAttribute.cs new file mode 100644 index 000000000..b5ce3fc3c --- /dev/null +++ b/tests/Testcontainers.Tests/Unit/UseWaitTimeoutAttribute.cs @@ -0,0 +1,29 @@ +namespace DotNet.Testcontainers.Tests.Unit +{ + using System; + using System.Reflection; + using DotNet.Testcontainers.Configurations; + using Xunit.Sdk; + + class UseWaitTimeoutAttribute : BeforeAfterTestAttribute + { + private readonly TimeSpan _originalTimeout; + private readonly TimeSpan _timeout; + + public UseWaitTimeoutAttribute(int seconds) + { + _originalTimeout = TestcontainersSettings.WaitTimeout; + _timeout = TimeSpan.FromSeconds(seconds); + } + + public override void Before(MethodInfo methodUnderTest) + { + TestcontainersSettings.WaitTimeout = _timeout; + } + + public override void After(MethodInfo methodUnderTest) + { + TestcontainersSettings.WaitTimeout = _originalTimeout; + } + } +}