From 1922cc1cf58069991d196cd8fd6eb6bcf703e516 Mon Sep 17 00:00:00 2001 From: Andre Hofmeister <9199345+HofmeisterAn@users.noreply.github.com> Date: Tue, 20 Dec 2022 07:55:43 +0100 Subject: [PATCH 1/8] feat(#715): Prepare HTTP wait strategy --- .../WaitStrategies/HttpWaitStrategy.cs | 29 +++++++++++++++++++ .../WaitStrategies/IWaitForContainerOS.cs | 17 +++++++---- .../WaitStrategies/WaitForContainerOS.cs | 8 ++++- .../WaitStrategies/WaitForContainerUnix.cs | 9 ++---- .../WaitStrategies/WaitForContainerWindows.cs | 9 ++---- 5 files changed, 54 insertions(+), 18 deletions(-) create mode 100644 src/Testcontainers/Configurations/WaitStrategies/HttpWaitStrategy.cs diff --git a/src/Testcontainers/Configurations/WaitStrategies/HttpWaitStrategy.cs b/src/Testcontainers/Configurations/WaitStrategies/HttpWaitStrategy.cs new file mode 100644 index 000000000..9153ae987 --- /dev/null +++ b/src/Testcontainers/Configurations/WaitStrategies/HttpWaitStrategy.cs @@ -0,0 +1,29 @@ +namespace DotNet.Testcontainers.Configurations +{ + using System; + using System.Threading.Tasks; + using DotNet.Testcontainers.Containers; + using Microsoft.Extensions.Logging; + + public sealed class HttpWaitStrategy : IWaitUntil + { + private readonly UriBuilder uriBuilder = new UriBuilder(Uri.UriSchemeHttp, "127.0.0.1"); + + public Task Until(ITestcontainersContainer testcontainers, ILogger logger) + { + return Task.FromResult(false); + } + + public HttpWaitStrategy ForPath(string path) + { + this.uriBuilder.Path = path; + return this; + } + + public HttpWaitStrategy UsingTls(bool tlsEnabled = true) + { + this.uriBuilder.Scheme = tlsEnabled ? Uri.UriSchemeHttps : Uri.UriSchemeHttp; + return this; + } + } +} diff --git a/src/Testcontainers/Configurations/WaitStrategies/IWaitForContainerOS.cs b/src/Testcontainers/Configurations/WaitStrategies/IWaitForContainerOS.cs index 8ed758b94..dbdc9996e 100644 --- a/src/Testcontainers/Configurations/WaitStrategies/IWaitForContainerOS.cs +++ b/src/Testcontainers/Configurations/WaitStrategies/IWaitForContainerOS.cs @@ -6,8 +6,7 @@ namespace DotNet.Testcontainers.Configurations using JetBrains.Annotations; /// - /// Collection of pre-configured strategies to wait until the Testcontainer is up and running. - /// Waits until all wait strategies are completed. + /// Collection of pre-configured strategies to wait until the container is up and running. /// [PublicAPI] public interface IWaitForContainerOS @@ -42,6 +41,14 @@ public interface IWaitForContainerOS [PublicAPI] IWaitForContainerOS UntilCommandIsCompleted(params string[] command); + /// + /// Waits until the port is available. + /// + /// The port to be checked. + /// A configured instance of . + [PublicAPI] + IWaitForContainerOS UntilPortIsAvailable(int port); + /// /// Waits until the file exists. /// @@ -70,12 +77,12 @@ public interface IWaitForContainerOS IWaitForContainerOS UntilOperationIsSucceeded(Func operation, int maxCallCount); /// - /// Waits until the port is available. + /// Waits until the http request is completed successfully. /// - /// The port to be checked. + /// The http request to be executed. /// A configured instance of . [PublicAPI] - IWaitForContainerOS UntilPortIsAvailable(int port); + IWaitForContainerOS UntilHttpRequestIsSucceeded(Func request); /// /// Waits until the container is healthy. diff --git a/src/Testcontainers/Configurations/WaitStrategies/WaitForContainerOS.cs b/src/Testcontainers/Configurations/WaitStrategies/WaitForContainerOS.cs index 9991c0eae..b7a9873d2 100644 --- a/src/Testcontainers/Configurations/WaitStrategies/WaitForContainerOS.cs +++ b/src/Testcontainers/Configurations/WaitStrategies/WaitForContainerOS.cs @@ -52,7 +52,13 @@ public virtual IWaitForContainerOS UntilOperationIsSucceeded(Func operatio } /// - public virtual IWaitForContainerOS UntilContainerIsHealthy(long failingStreak = 20) + public virtual IWaitForContainerOS UntilHttpRequestIsSucceeded(Func request) + { + return this.AddCustomWaitStrategy(request.Invoke(new HttpWaitStrategy())); + } + + /// + public virtual IWaitForContainerOS UntilContainerIsHealthy(long failingStreak = 3) { return this.AddCustomWaitStrategy(new UntilContainerIsHealthy(failingStreak)); } diff --git a/src/Testcontainers/Configurations/WaitStrategies/WaitForContainerUnix.cs b/src/Testcontainers/Configurations/WaitStrategies/WaitForContainerUnix.cs index 87444d6c5..01653e28e 100644 --- a/src/Testcontainers/Configurations/WaitStrategies/WaitForContainerUnix.cs +++ b/src/Testcontainers/Configurations/WaitStrategies/WaitForContainerUnix.cs @@ -6,22 +6,19 @@ internal sealed class WaitForContainerUnix : WaitForContainerOS /// public override IWaitForContainerOS UntilCommandIsCompleted(string command) { - this.AddCustomWaitStrategy(new UntilUnixCommandIsCompleted(command)); - return this; + return this.AddCustomWaitStrategy(new UntilUnixCommandIsCompleted(command)); } /// public override IWaitForContainerOS UntilCommandIsCompleted(params string[] command) { - this.AddCustomWaitStrategy(new UntilUnixCommandIsCompleted(command)); - return this; + return this.AddCustomWaitStrategy(new UntilUnixCommandIsCompleted(command)); } /// public override IWaitForContainerOS UntilPortIsAvailable(int port) { - this.AddCustomWaitStrategy(new UntilUnixPortIsAvailable(port)); - return this; + return this.AddCustomWaitStrategy(new UntilUnixPortIsAvailable(port)); } } } diff --git a/src/Testcontainers/Configurations/WaitStrategies/WaitForContainerWindows.cs b/src/Testcontainers/Configurations/WaitStrategies/WaitForContainerWindows.cs index 71014d990..a3a45cd77 100644 --- a/src/Testcontainers/Configurations/WaitStrategies/WaitForContainerWindows.cs +++ b/src/Testcontainers/Configurations/WaitStrategies/WaitForContainerWindows.cs @@ -6,22 +6,19 @@ internal sealed class WaitForContainerWindows : WaitForContainerOS /// public override IWaitForContainerOS UntilCommandIsCompleted(string command) { - this.AddCustomWaitStrategy(new UntilWindowsCommandIsCompleted(command)); - return this; + return this.AddCustomWaitStrategy(new UntilWindowsCommandIsCompleted(command)); } /// public override IWaitForContainerOS UntilCommandIsCompleted(params string[] command) { - this.AddCustomWaitStrategy(new UntilWindowsCommandIsCompleted(command)); - return this; + return this.AddCustomWaitStrategy(new UntilWindowsCommandIsCompleted(command)); } /// public override IWaitForContainerOS UntilPortIsAvailable(int port) { - this.AddCustomWaitStrategy(new UntilWindowsPortIsAvailable(port)); - return this; + return this.AddCustomWaitStrategy(new UntilWindowsPortIsAvailable(port)); } } } From 6c264f15903b6cb6b9b2604a6590ccb9118cd464 Mon Sep 17 00:00:00 2001 From: Andre Hofmeister <9199345+HofmeisterAn@users.noreply.github.com> Date: Tue, 20 Dec 2022 10:27:08 +0100 Subject: [PATCH 2/8] feat(#715): Add HttpWaitStrategy --- .../WaitStrategies/HttpWaitStrategy.cs | 107 +++++++++++++++++- 1 file changed, 104 insertions(+), 3 deletions(-) diff --git a/src/Testcontainers/Configurations/WaitStrategies/HttpWaitStrategy.cs b/src/Testcontainers/Configurations/WaitStrategies/HttpWaitStrategy.cs index 9153ae987..e55e447da 100644 --- a/src/Testcontainers/Configurations/WaitStrategies/HttpWaitStrategy.cs +++ b/src/Testcontainers/Configurations/WaitStrategies/HttpWaitStrategy.cs @@ -1,17 +1,90 @@ namespace DotNet.Testcontainers.Configurations { using System; + using System.Collections.Generic; + using System.Linq; + using System.Net; + using System.Net.Http; using System.Threading.Tasks; using DotNet.Testcontainers.Containers; + using JetBrains.Annotations; using Microsoft.Extensions.Logging; + [PublicAPI] public sealed class HttpWaitStrategy : IWaitUntil { - private readonly UriBuilder uriBuilder = new UriBuilder(Uri.UriSchemeHttp, "127.0.0.1"); + private readonly UriBuilder uriBuilder = new UriBuilder(); - public Task Until(ITestcontainersContainer testcontainers, ILogger logger) + private readonly IDictionary httpHeaders = new Dictionary(); + + private readonly ISet httpStatusCodes = new HashSet(); + + private HttpMethod httpMethod; + + private Predicate httpStatusCodePredicate; + + public HttpWaitStrategy() { - return Task.FromResult(false); + _ = this.WithMethod(HttpMethod.Get).UsingTls(false).ForPath("/"); + } + + public async Task Until(ITestcontainersContainer testcontainers, ILogger logger) + { + using (var httpClient = new HttpClient()) + { + using (var httpRequestMessage = new HttpRequestMessage(this.httpMethod, this.uriBuilder.Uri)) + { + foreach (var httpHeader in this.httpHeaders) + { + httpRequestMessage.Headers.Add(httpHeader.Key, httpHeader.Value); + } + + HttpResponseMessage httpResponseMessage; + + try + { + httpResponseMessage = await httpClient.SendAsync(httpRequestMessage) + .ConfigureAwait(false); + } + catch + { + return false; + } + + Predicate predicate; + + if (!this.httpStatusCodes.Any() && this.httpStatusCodePredicate == null) + { + predicate = statusCode => HttpStatusCode.OK.Equals(statusCode); + } + else if (this.httpStatusCodes.Any() && this.httpStatusCodePredicate == null) + { + predicate = statusCode => this.httpStatusCodes.Contains(statusCode); + } + else if (this.httpStatusCodes.Any()) + { + predicate = statusCode => this.httpStatusCodes.Contains(statusCode) || this.httpStatusCodePredicate.Invoke(statusCode); + } + else + { + predicate = this.httpStatusCodePredicate; + } + + return predicate.Invoke(httpResponseMessage.StatusCode); + } + } + } + + public HttpWaitStrategy ForStatusCode(HttpStatusCode statusCode) + { + this.httpStatusCodes.Add(statusCode); + return this; + } + + public HttpWaitStrategy ForStatusCodeMatching(Predicate statusCodePredicate) + { + this.httpStatusCodePredicate = statusCodePredicate; + return this; } public HttpWaitStrategy ForPath(string path) @@ -20,10 +93,38 @@ public HttpWaitStrategy ForPath(string path) return this; } + public HttpWaitStrategy ForPort(ushort port) + { + this.uriBuilder.Port = port; + return this; + } + public HttpWaitStrategy UsingTls(bool tlsEnabled = true) { this.uriBuilder.Scheme = tlsEnabled ? Uri.UriSchemeHttps : Uri.UriSchemeHttp; return this; } + + public HttpWaitStrategy WithMethod(HttpMethod method) + { + this.httpMethod = method; + return this; + } + + public HttpWaitStrategy WithHeader(string name, string value) + { + this.httpHeaders.Add(name, value); + return this; + } + + public HttpWaitStrategy WithHeaders(IReadOnlyDictionary headers) + { + foreach (var header in headers) + { + _ = this.WithHeader(header.Key, header.Value); + } + + return this; + } } } From 09332e78b372021c54ddedc67f51227e9b589780 Mon Sep 17 00:00:00 2001 From: Andre Hofmeister <9199345+HofmeisterAn@users.noreply.github.com> Date: Tue, 20 Dec 2022 12:28:54 +0100 Subject: [PATCH 3/8] feat(#715): Add HttpWaitStrategy tests --- .../WaitStrategies/HttpWaitStrategy.cs | 34 ++++++++++---- .../WaitUntilHttpRequestIsSucceededTest.cs | 47 +++++++++++++++++++ 2 files changed, 73 insertions(+), 8 deletions(-) create mode 100644 tests/Testcontainers.Tests/Unit/Configurations/WaitUntilHttpRequestIsSucceededTest.cs diff --git a/src/Testcontainers/Configurations/WaitStrategies/HttpWaitStrategy.cs b/src/Testcontainers/Configurations/WaitStrategies/HttpWaitStrategy.cs index e55e447da..6be5624f5 100644 --- a/src/Testcontainers/Configurations/WaitStrategies/HttpWaitStrategy.cs +++ b/src/Testcontainers/Configurations/WaitStrategies/HttpWaitStrategy.cs @@ -13,26 +13,44 @@ [PublicAPI] public sealed class HttpWaitStrategy : IWaitUntil { - private readonly UriBuilder uriBuilder = new UriBuilder(); - private readonly IDictionary httpHeaders = new Dictionary(); private readonly ISet httpStatusCodes = new HashSet(); + private Predicate httpStatusCodePredicate; + private HttpMethod httpMethod; - private Predicate httpStatusCodePredicate; + private string schemeName; + + private string pathValue; + + private ushort portNumber; public HttpWaitStrategy() { - _ = this.WithMethod(HttpMethod.Get).UsingTls(false).ForPath("/"); + _ = this.WithMethod(HttpMethod.Get).UsingTls(false).ForPort(80).ForPath("/"); } public async Task Until(ITestcontainersContainer testcontainers, ILogger logger) { + string host; + + ushort port; + + try + { + host = testcontainers.Hostname; + port = testcontainers.GetMappedPublicPort(this.portNumber); + } + catch + { + return false; + } + using (var httpClient = new HttpClient()) { - using (var httpRequestMessage = new HttpRequestMessage(this.httpMethod, this.uriBuilder.Uri)) + using (var httpRequestMessage = new HttpRequestMessage(this.httpMethod, new UriBuilder(this.schemeName, host, port, this.pathValue).Uri)) { foreach (var httpHeader in this.httpHeaders) { @@ -89,19 +107,19 @@ public HttpWaitStrategy ForStatusCodeMatching(Predicate statusCo public HttpWaitStrategy ForPath(string path) { - this.uriBuilder.Path = path; + this.pathValue = path; return this; } public HttpWaitStrategy ForPort(ushort port) { - this.uriBuilder.Port = port; + this.portNumber = port; return this; } public HttpWaitStrategy UsingTls(bool tlsEnabled = true) { - this.uriBuilder.Scheme = tlsEnabled ? Uri.UriSchemeHttps : Uri.UriSchemeHttp; + this.schemeName = tlsEnabled ? Uri.UriSchemeHttps : Uri.UriSchemeHttp; return this; } diff --git a/tests/Testcontainers.Tests/Unit/Configurations/WaitUntilHttpRequestIsSucceededTest.cs b/tests/Testcontainers.Tests/Unit/Configurations/WaitUntilHttpRequestIsSucceededTest.cs new file mode 100644 index 000000000..22cc60d01 --- /dev/null +++ b/tests/Testcontainers.Tests/Unit/Configurations/WaitUntilHttpRequestIsSucceededTest.cs @@ -0,0 +1,47 @@ +namespace DotNet.Testcontainers.Tests.Unit.Configurations +{ + using System.Collections.Generic; + using System.Net; + using System.Threading.Tasks; + using DotNet.Testcontainers.Builders; + using DotNet.Testcontainers.Commons; + using DotNet.Testcontainers.Configurations; + using DotNet.Testcontainers.Containers; + using Microsoft.Extensions.Logging.Abstractions; + using Xunit; + + public sealed class WaitUntilHttpRequestIsSucceededTest + { + public static IEnumerable GetHttpWaitStrategies() + { + yield return new object[] { new HttpWaitStrategy() }; + yield return new object[] { new HttpWaitStrategy().ForStatusCode(HttpStatusCode.OK) }; + yield return new object[] { new HttpWaitStrategy().ForStatusCodeMatching(statusCode => HttpStatusCode.OK.Equals(statusCode)) }; + yield return new object[] { new HttpWaitStrategy().ForStatusCode(HttpStatusCode.Moved).ForStatusCodeMatching(statusCode => HttpStatusCode.OK.Equals(statusCode)) }; + } + + [Theory] + [MemberData(nameof(GetHttpWaitStrategies))] + public async Task HttpWaitStrategyShouldSucceeded(HttpWaitStrategy httpWaitStrategy) + { + // Given + const ushort httpPort = 80; + + var container = new TestcontainersBuilder() + .WithImage(CommonImages.Nginx) + .WithPortBinding(httpPort, true) + .WithWaitStrategy(Wait.ForUnixContainer().UntilPortIsAvailable(httpPort)) + .Build(); + + // When + await container.StartAsync() + .ConfigureAwait(false); + + var succeeded = await httpWaitStrategy.Until(container, NullLogger.Instance) + .ConfigureAwait(false); + + // Then + Assert.True(succeeded); + } + } +} From 26c39cd1d07ab905fc4c4cdc3909123dfd23f35d Mon Sep 17 00:00:00 2001 From: Andre Hofmeister <9199345+HofmeisterAn@users.noreply.github.com> Date: Tue, 20 Dec 2022 13:47:59 +0100 Subject: [PATCH 4/8] chore: Add XML docs --- .../WaitStrategies/HttpWaitStrategy.cs | 63 ++++++++++++++++++- 1 file changed, 62 insertions(+), 1 deletion(-) diff --git a/src/Testcontainers/Configurations/WaitStrategies/HttpWaitStrategy.cs b/src/Testcontainers/Configurations/WaitStrategies/HttpWaitStrategy.cs index 6be5624f5..263bf1a10 100644 --- a/src/Testcontainers/Configurations/WaitStrategies/HttpWaitStrategy.cs +++ b/src/Testcontainers/Configurations/WaitStrategies/HttpWaitStrategy.cs @@ -10,9 +10,16 @@ using JetBrains.Annotations; using Microsoft.Extensions.Logging; + /// + /// Wait for an HTTP(S) endpoint to return a particular status code. + /// [PublicAPI] public sealed class HttpWaitStrategy : IWaitUntil { + private const ushort HttpPort = 80; + + private const ushort HttpsPort = 443; + private readonly IDictionary httpHeaders = new Dictionary(); private readonly ISet httpStatusCodes = new HashSet(); @@ -27,11 +34,15 @@ public sealed class HttpWaitStrategy : IWaitUntil private ushort portNumber; + /// + /// Initializes a new instance of the class. + /// public HttpWaitStrategy() { - _ = this.WithMethod(HttpMethod.Get).UsingTls(false).ForPort(80).ForPath("/"); + _ = this.WithMethod(HttpMethod.Get).UsingTls(false).ForPort(HttpPort).ForPath("/"); } + /// public async Task Until(ITestcontainersContainer testcontainers, ILogger logger) { string host; @@ -93,48 +104,98 @@ public async Task Until(ITestcontainersContainer testcontainers, ILogger l } } + /// + /// Waits for the status code. + /// + /// The expected status code. + /// A configured instance of . public HttpWaitStrategy ForStatusCode(HttpStatusCode statusCode) { this.httpStatusCodes.Add(statusCode); return this; } + /// + /// Waits for the status code to pass the predicate. + /// + /// The predicate to test the HTTP response against. + /// A configured instance of . public HttpWaitStrategy ForStatusCodeMatching(Predicate statusCodePredicate) { this.httpStatusCodePredicate = statusCodePredicate; return this; } + /// + /// Waits for the path. + /// + /// The path to check. + /// A configured instance of . public HttpWaitStrategy ForPath(string path) { this.pathValue = path; return this; } + /// + /// Waits for the port. + /// + /// + /// default value. + /// + /// The port to check. + /// A configured instance of . public HttpWaitStrategy ForPort(ushort port) { this.portNumber = port; return this; } + /// + /// Indicates that the HTTP request use HTTPS. + /// + /// + /// default value. + /// + /// True if the HTTP request use HTTPS, otherwise false. + /// A configured instance of . public HttpWaitStrategy UsingTls(bool tlsEnabled = true) { this.schemeName = tlsEnabled ? Uri.UriSchemeHttps : Uri.UriSchemeHttp; return this; } + /// + /// Indicates the HTTP request method. + /// + /// + /// default value. + /// + /// The HTTP method. + /// A configured instance of . public HttpWaitStrategy WithMethod(HttpMethod method) { this.httpMethod = method; return this; } + /// + /// Adds a custom HTTP header to the HTTP request. + /// + /// The HTTP header name. + /// The HTTP header value. + /// A configured instance of . public HttpWaitStrategy WithHeader(string name, string value) { this.httpHeaders.Add(name, value); return this; } + /// + /// Adds custom HTTP headers to the HTTP request. + /// + /// A list of HTTP headers. + /// A configured instance of . public HttpWaitStrategy WithHeaders(IReadOnlyDictionary headers) { foreach (var header in headers) From 3002457a4df2e50bd92c0c9e27e39035ace2bac6 Mon Sep 17 00:00:00 2001 From: Andre Hofmeister <9199345+HofmeisterAn@users.noreply.github.com> Date: Tue, 20 Dec 2022 21:18:00 +0100 Subject: [PATCH 5/8] chore: Fallback to HTTP(S) port if user does not provide a port --- .../Configurations/WaitStrategies/HttpWaitStrategy.cs | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/src/Testcontainers/Configurations/WaitStrategies/HttpWaitStrategy.cs b/src/Testcontainers/Configurations/WaitStrategies/HttpWaitStrategy.cs index 263bf1a10..446bb68be 100644 --- a/src/Testcontainers/Configurations/WaitStrategies/HttpWaitStrategy.cs +++ b/src/Testcontainers/Configurations/WaitStrategies/HttpWaitStrategy.cs @@ -32,19 +32,22 @@ public sealed class HttpWaitStrategy : IWaitUntil private string pathValue; - private ushort portNumber; + private ushort? portNumber; /// /// Initializes a new instance of the class. /// public HttpWaitStrategy() { - _ = this.WithMethod(HttpMethod.Get).UsingTls(false).ForPort(HttpPort).ForPath("/"); + _ = this.WithMethod(HttpMethod.Get).UsingTls(false).ForPath("/"); } /// public async Task Until(ITestcontainersContainer testcontainers, ILogger logger) { + // Java fall back to the first exposed port. The .NET wait strategies do not have access to the exposed port information yet. + var containerPort = this.portNumber.GetValueOrDefault(Uri.UriSchemeHttp.Equals(this.schemeName, StringComparison.OrdinalIgnoreCase) ? HttpPort : HttpsPort); + string host; ushort port; @@ -52,7 +55,7 @@ public async Task Until(ITestcontainersContainer testcontainers, ILogger l try { host = testcontainers.Hostname; - port = testcontainers.GetMappedPublicPort(this.portNumber); + port = testcontainers.GetMappedPublicPort(containerPort); } catch { From 2a77dc24478ea26a8b4ff07214bb81370adca469 Mon Sep 17 00:00:00 2001 From: Andre Hofmeister <9199345+HofmeisterAn@users.noreply.github.com> Date: Wed, 21 Dec 2022 09:50:27 +0100 Subject: [PATCH 6/8] docs: Add wait strategies docs --- docs/api/create_docker_container.md | 4 ++-- docs/api/create_docker_image.md | 2 +- docs/api/wait_strategies.md | 33 ++++++++++++++++++++++++++++- 3 files changed, 35 insertions(+), 4 deletions(-) diff --git a/docs/api/create_docker_container.md b/docs/api/create_docker_container.md index 00b64de5e..1e4b75013 100644 --- a/docs/api/create_docker_container.md +++ b/docs/api/create_docker_container.md @@ -11,7 +11,7 @@ Instead of running the NGINX application, the following container configuration ```csharp _ = new TestcontainersBuilder() .WithEntrypoint("nginx") - .WithCommand("-t") + .WithCommand("-t"); ``` ## Configure container app or service @@ -29,7 +29,7 @@ _ = new TestcontainersBuilder() .WithEnvironment("ASPNETCORE_URLS", "https://+") .WithEnvironment("ASPNETCORE_Kestrel__Certificates__Default__Path", "/app/certificate.crt") .WithEnvironment("ASPNETCORE_Kestrel__Certificates__Default__Password", "password") - .WithResourceMapping("certificate.crt", "/app/certificate.crt") + .WithResourceMapping("certificate.crt", "/app/certificate.crt"); ``` `WithBindMount(string, string)` is another option to provide access to directories or files. It mounts a host directory or file into the container. Note, this does not follow our best practices. Host paths differ between environments and may not be available on every system or Docker setup, e.g. CI. diff --git a/docs/api/create_docker_image.md b/docs/api/create_docker_image.md index 512d60fef..1bea3f354 100644 --- a/docs/api/create_docker_image.md +++ b/docs/api/create_docker_image.md @@ -11,7 +11,7 @@ _ = await new ImageFromDockerfileBuilder() .WithName(Guid.NewGuid().ToString("D")) .WithDockerfileDirectory(CommonDirectoryPath.GetSolutionDirectory(), "src") .WithDockerfile("Dockerfile") - .Build() + .Build(); ``` !!!tip diff --git a/docs/api/wait_strategies.md b/docs/api/wait_strategies.md index 46fcc6e48..56f9923e0 100644 --- a/docs/api/wait_strategies.md +++ b/docs/api/wait_strategies.md @@ -11,6 +11,37 @@ _ = Wait.ForUnixContainer() .AddCustomWaitStrategy(new MyCustomWaitStrategy()); ``` +## Wait until an HTTP(S) endpoint is available + +You can choose to wait for an HTTP(S) endpoint to return a particular HTTP response status code or to match a predicate. The default configuration tries to access the HTTP endpoint running inside the container. Chose `ForPort(ushort)` or `ForPath(string)` to adjust the endpoint or `UsingTls()` to switch to HTTPS. + +### Waiting for HTTP response status code _200 OK_ + +```csharp +_ = Wait.ForUnixContainer() + .UntilHttpRequestIsSucceeded(request => request + .ForPath("/")); +``` + +### Waiting for HTTP response status code _200 OK_ or _301 Moved Permanently_ + +```csharp +_ = Wait.ForUnixContainer() + .UntilHttpRequestIsSucceeded(request => request + .ForPath("/") + .ForStatusCode(HttpStatusCode.OK) + .ForStatusCode(HttpStatusCode.MovedPermanently)); +``` + +### Waiting for the HTTP response status code to match a predicate + +```csharp +_ = Wait.ForUnixContainer() + .UntilHttpRequestIsSucceeded(request => request + .ForPath("/") + .ForStatusCodeMatching(statusCode => statusCode >= HttpStatusCode.OK && statusCode < HttpStatusCode.MultipleChoices)); +``` + ## Wait until the container is healthy If the Docker image supports Dockers's [HEALTHCHECK][docker-docs-healthcheck] feature, like the following configuration: @@ -24,7 +55,7 @@ You can leverage the container's health status as your wait strategy to report r ```csharp _ = new TestcontainersBuilder() - .WithWaitStrategy(Wait.ForUnixContainer().UntilContainerIsHealthy()) + .WithWaitStrategy(Wait.ForUnixContainer().UntilContainerIsHealthy()); ``` [docker-docs-healthcheck]: https://docs.docker.com/engine/reference/builder/#healthcheck From b8ae06a2ebbf629f7d61a3789f93aeee625f7675 Mon Sep 17 00:00:00 2001 From: Andre Hofmeister <9199345+HofmeisterAn@users.noreply.github.com> Date: Wed, 21 Dec 2022 11:24:24 +0100 Subject: [PATCH 7/8] Update docs/api/wait_strategies.md Co-authored-by: Kevin Wittek --- docs/api/wait_strategies.md | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/docs/api/wait_strategies.md b/docs/api/wait_strategies.md index 56f9923e0..c34ecce9f 100644 --- a/docs/api/wait_strategies.md +++ b/docs/api/wait_strategies.md @@ -13,7 +13,10 @@ _ = Wait.ForUnixContainer() ## Wait until an HTTP(S) endpoint is available -You can choose to wait for an HTTP(S) endpoint to return a particular HTTP response status code or to match a predicate. The default configuration tries to access the HTTP endpoint running inside the container. Chose `ForPort(ushort)` or `ForPath(string)` to adjust the endpoint or `UsingTls()` to switch to HTTPS. +You can choose to wait for an HTTP(S) endpoint to return a particular HTTP response status code or to match a predicate. +The default configuration tries to access the HTTP endpoint running inside the container. Chose `ForPort(ushort)` or `ForPath(string)` to adjust the endpoint or `UsingTls()` to switch to HTTPS. +When using `UsingTls()` port 443 is used as a default. +If your container exposes a different HTTPS port, make sure that the correct waiting port is configured accordingly. ### Waiting for HTTP response status code _200 OK_ From 67e33b97dc6383270731447f3cccf19841f02b92 Mon Sep 17 00:00:00 2001 From: Andre Hofmeister <9199345+HofmeisterAn@users.noreply.github.com> Date: Wed, 21 Dec 2022 11:24:32 +0100 Subject: [PATCH 8/8] Update docs/api/wait_strategies.md Co-authored-by: Kevin Wittek --- docs/api/wait_strategies.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/api/wait_strategies.md b/docs/api/wait_strategies.md index c34ecce9f..8b9fdc598 100644 --- a/docs/api/wait_strategies.md +++ b/docs/api/wait_strategies.md @@ -18,7 +18,7 @@ The default configuration tries to access the HTTP endpoint running inside the c When using `UsingTls()` port 443 is used as a default. If your container exposes a different HTTPS port, make sure that the correct waiting port is configured accordingly. -### Waiting for HTTP response status code _200 OK_ +### Waiting for HTTP response status code _200 OK_ on port 80 ```csharp _ = Wait.ForUnixContainer()