Skip to content

Commit

Permalink
⚡️ Prevent Infinite Wait with Timeouts Exceptions and Retry counts in…
Browse files Browse the repository at this point in the history
… UntilHttp Strategy
  • Loading branch information
Alfred Neequaye committed Dec 2, 2022
1 parent bfa4e19 commit 4758d4e
Show file tree
Hide file tree
Showing 2 changed files with 45 additions and 25 deletions.
2 changes: 2 additions & 0 deletions src/Testcontainers/Configurations/UntilHttpOptions.cs
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@ public UntilHttpOptions()
this.ExpectedResponseCodes = new() { HttpStatusCode.OK };
this.TimeOut = TimeSpan.FromMinutes(1);
this.RequestDelay = 1;
this.MaxRetries = 10;
}

public HttpMethod Method { get; set; }
Expand All @@ -36,6 +37,7 @@ public UntilHttpOptions()
public TimeSpan TimeOut { get; set; }
public bool ValidateContent { get; set; }
public double RequestDelay { get; set; }
public int MaxRetries { get; set; }

public Uri Uri => new($"{(this.UseSecure ? "https" : "http")}://{this.Host}:{this.Port}{this.Path}");
}
Expand Down
68 changes: 43 additions & 25 deletions src/Testcontainers/Configurations/WaitStrategies/UntilHttp.cs
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@
public class UntilHttp : IWaitUntil
{
private readonly UntilHttpOptions Options;
private int RetryCount = 0;

public UntilHttp(string path)
{
Expand All @@ -25,42 +26,59 @@ public UntilHttp(UntilHttpOptions options)

public async Task<bool> Until(ITestcontainersContainer testcontainers, ILogger logger)
{
var mappedPort = testcontainers.GetMappedPublicPort(this.Options.Port);
this.Options.Port = mappedPort;
var client = new HttpClient();
var message = new HttpRequestMessage(this.Options.Method, this.Options.Uri);
if (this.Options.RequestContent is not null && (this.Options.Method == HttpMethod.Post || this.Options.Method == HttpMethod.Put))
{
message.Content = this.Options.RequestContent;
}

if (this.Options.UseAuth && this.Options.AuthString is not null)
try
{
message.Headers.Authorization = AuthenticationHeaderValue.Parse(this.Options.AuthString.ToString());
}
var mappedPort = testcontainers.GetMappedPublicPort(this.Options.Port);
this.Options.Port = mappedPort;
var client = new HttpClient();
var message = new HttpRequestMessage(this.Options.Method, this.Options.Uri);
if (this.Options.RequestContent is not null && (this.Options.Method == HttpMethod.Post || this.Options.Method == HttpMethod.Put))
{
message.Content = this.Options.RequestContent;
}

var sendTask = Task.Run(async () =>
{
HttpResponseMessage response = null;
while (response is null || !this.Options.ExpectedResponseCodes.Contains(response.StatusCode))
if (this.Options.UseAuth && this.Options.AuthString is not null)
{
message.Headers.Authorization = AuthenticationHeaderValue.Parse(this.Options.AuthString.ToString());
}

var sendTask = Task.Run(async () =>
{
response = await client.SendAsync(message);
if (!this.Options.ExpectedResponseCodes.Contains(response.StatusCode))
HttpResponseMessage response = null;
while (response is null || !this.Options.ExpectedResponseCodes.Contains(response.StatusCode))
{
Thread.Sleep(TimeSpan.FromSeconds(this.Options.RequestDelay));
response = await client.SendAsync(message);
if (++this.RetryCount > this.Options.MaxRetries)
{
throw new TimeoutException($"Http Wait Failed {this.Options.MaxRetries} Times");
}

if (!this.Options.ExpectedResponseCodes.Contains(response.StatusCode))
{
Thread.Sleep(TimeSpan.FromSeconds(this.Options.RequestDelay));
}
}
return response;
});
var completed = sendTask.Wait(this.Options.TimeOut);
if (!completed)
{
throw new TimeoutException($"Http Wait Failed Timed Out after {this.Options.TimeOut}");
}

return response;
});
var completed = sendTask.Wait(this.Options.TimeOut);
if (!completed)
var responseContent = await sendTask.Result.Content.ReadAsStringAsync();
return !this.Options.ValidateContent || Regex.Match(this.Options.ExpectedOutput, responseContent).Success;
}
catch (Exception)
{
if (++this.RetryCount > this.Options.MaxRetries)
{
throw new TimeoutException($"Http Wait Failed {this.Options.MaxRetries} Times");
}

return false;
}

var responseContent = await sendTask.Result.Content.ReadAsStringAsync();
return !this.Options.ValidateContent || Regex.Match(this.Options.ExpectedOutput, responseContent).Success;
}
}
}

0 comments on commit 4758d4e

Please sign in to comment.