Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Bugfix/631 debug azurite configuration #651

Merged
merged 8 commits into from
Nov 2, 2022
4 changes: 4 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,10 @@

- 642 Expose container port bindings automatically

### Fixed

- 610 Trim traling slashes in Dockerfile directory path (otherwise, it cuts the first character of the relative path), Normalize paths to forward slashes

## [2.2.0]

### Added
Expand Down
9 changes: 8 additions & 1 deletion examples/WeatherForecast/README.md
Original file line number Diff line number Diff line change
@@ -1,3 +1,10 @@
# Testcontainers for .NET WeatherForecast example

This example builds and ships a Blazor application in a Docker image build, runs a Docker container and executes tests against a running instance of the application. Testcontainers for .NET takes care of the Docker image build and the Docker container that hosts the application. Spin up as much as containers as you like and run your tests heavily in parallel.
This example builds and ships a Blazor application in a Docker image build, runs a Docker container and executes tests against a running instance of the application. Testcontainers for .NET takes care of the Docker image build and the Docker container that hosts the application. Spin up as much as containers as you like and run your tests heavily in parallel. Checkout and run the tests on your machine:

```console
git clone [email protected]:testcontainers/testcontainers-dotnet.git
cd ./testcontainers-dotnet/examples/WeatherForecast/
dotnet build WeatherForecast.sln
dotnet test WeatherForecast.sln
```
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@
using DotNet.Testcontainers.Builders;
using OpenQA.Selenium;
using OpenQA.Selenium.Chrome;
using OpenQA.Selenium.Support.UI;
using WeatherForecast.Entities;
using Xunit;

Expand Down Expand Up @@ -69,7 +70,7 @@ public Web(WeatherForecastContainer weatherForecastContainer)

[Fact]
[Trait("Category", nameof(Web))]
public async Task Get_WeatherForecast_ReturnsSevenDays()
public void Get_WeatherForecast_ReturnsSevenDays()
{
// Given
string ScreenshotFileName() => $"{nameof(Get_WeatherForecast_ReturnsSevenDays)}_{DateTimeOffset.UtcNow.ToUnixTimeMilliseconds()}.png";
Expand All @@ -83,8 +84,8 @@ public async Task Get_WeatherForecast_ReturnsSevenDays()

chrome.FindElement(By.TagName("fluent-button")).Click();

await Task.Delay(TimeSpan.FromSeconds(1))
.ConfigureAwait(false);
var wait = new WebDriverWait(chrome, TimeSpan.FromSeconds(10));
wait.Until(webDriver => 1.Equals(webDriver.FindElements(By.TagName("span")).Count));

chrome.GetScreenshot().SaveAsFile(Path.Combine(CommonDirectoryPath.GetSolutionDirectory().DirectoryPath, ScreenshotFileName()));

Expand Down
Original file line number Diff line number Diff line change
@@ -1,12 +1,16 @@
namespace DotNet.Testcontainers.Builders
{
using System;
using System.Threading;
using System.Threading.Tasks;
using DotNet.Testcontainers.Configurations;
using DotNet.Testcontainers.Containers;

/// <inheritdoc cref="IDockerEndpointAuthenticationProvider" />
internal class DockerEndpointAuthenticationProvider : IDockerEndpointAuthenticationProvider
{
private static readonly TaskFactory TaskFactory = new TaskFactory(CancellationToken.None, TaskCreationOptions.None, TaskContinuationOptions.None, TaskScheduler.Default);

/// <inheritdoc />
public virtual bool IsApplicable()
{
Expand All @@ -29,7 +33,7 @@ public virtual bool IsAvailable()
{
try
{
dockerClient.System.PingAsync().GetAwaiter().GetResult();
TaskFactory.StartNew(() => dockerClient.System.PingAsync()).Unwrap().GetAwaiter().GetResult();
return true;
}
catch (Exception)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -58,7 +58,7 @@ public static ITestcontainersBuilder<AzuriteTestcontainer> WithAzurite(this ITes
}

return builder
.WithCommand(GetExecutable(configuration))
.WithEntrypoint(GetExecutable(configuration))
.WithCommand(GetEnabledServices(configuration))
.WithCommand(GetWorkspaceDirectoryPath())
.WithCommand(GetDebugModeEnabled(configuration))
Expand Down
2 changes: 1 addition & 1 deletion src/Testcontainers/Clients/TestcontainersClient.cs
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@ namespace DotNet.Testcontainers.Clients
/// <inheritdoc cref="ITestcontainersClient" />
internal sealed class TestcontainersClient : ITestcontainersClient
{
public const string TestcontainersLabel = "testcontainers";
public const string TestcontainersLabel = "org.testcontainers";

private readonly string osRootDirectory = Path.GetPathRoot(Directory.GetCurrentDirectory());

Expand Down
2 changes: 1 addition & 1 deletion src/Testcontainers/Configurations/IOperatingSystem.cs
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,6 @@ public interface IOperatingSystem
/// <param name="path">Path to normalize.</param>
/// <returns>Normalized path.</returns>
[PublicAPI]
string NormalizePath(string path);
string NormalizePath([CanBeNull] string path);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,8 @@ namespace DotNet.Testcontainers.Configurations
/// <inheritdoc cref="IImageFromDockerfileConfiguration" />
internal sealed class ImageFromDockerfileConfiguration : DockerResourceConfiguration, IImageFromDockerfileConfiguration
{
private static readonly IOperatingSystem OS = new Unix();

/// <summary>
/// Initializes a new instance of the <see cref="ImageFromDockerfileConfiguration" /> class.
/// </summary>
Expand Down Expand Up @@ -36,8 +38,8 @@ public ImageFromDockerfileConfiguration(
: base(dockerEndpointAuthenticationConfiguration, labels)
{
this.Image = image;
this.Dockerfile = dockerfile;
this.DockerfileDirectory = dockerfileDirectory;
this.Dockerfile = OS.NormalizePath(dockerfile);
this.DockerfileDirectory = OS.NormalizePath(dockerfileDirectory);
this.DeleteIfExists = deleteIfExists;
this.BuildArguments = buildArguments;
}
Expand Down
2 changes: 1 addition & 1 deletion src/Testcontainers/Configurations/Unix.cs
Original file line number Diff line number Diff line change
Expand Up @@ -55,7 +55,7 @@ public Unix(IDockerEndpointAuthenticationConfiguration dockerEndpointAuthConfig)
/// <inheritdoc />
public string NormalizePath(string path)
{
return path.Replace('\\', '/');
return path?.Replace('\\', '/');
}
}
}
2 changes: 1 addition & 1 deletion src/Testcontainers/Configurations/Windows.cs
Original file line number Diff line number Diff line change
Expand Up @@ -55,7 +55,7 @@ public Windows(IDockerEndpointAuthenticationConfiguration dockerEndpointAuthConf
/// <inheritdoc />
public string NormalizePath(string path)
{
return path.Replace('/', '\\');
return path?.Replace('/', '\\');
}
}
}
2 changes: 1 addition & 1 deletion src/Testcontainers/Images/DockerfileArchive.cs
Original file line number Diff line number Diff line change
Expand Up @@ -77,7 +77,7 @@ public string Tar()
foreach (var file in GetFiles(this.dockerfileDirectory.FullName))
{
// SharpZipLib drops the root path: https://github.com/icsharpcode/SharpZipLib/pull/582.
var relativePath = file.Substring(this.dockerfileDirectory.FullName.Length + 1);
var relativePath = file.Substring(this.dockerfileDirectory.FullName.TrimEnd('/', '\\').Length + 1);

if (dockerIgnoreFile.Denies(relativePath))
{
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@
using DotNet.Testcontainers.Configurations;
using DotNet.Testcontainers.Containers;
using DotNet.Testcontainers.Images;
using Microsoft.Extensions.Logging;
using Xunit;

public abstract class ProtectDockerDaemonSocket : IAsyncLifetime
Expand All @@ -34,7 +35,7 @@ protected ProtectDockerDaemonSocket(ITestcontainersBuilder<TestcontainersContain
.WithExposedPort(TlsPort)
.WithPortBinding(TlsPort, true)
.WithBindMount(this.hostCertsDirectoryPath, this.containerCertsDirectoryPath, AccessMode.ReadWrite)
.WithWaitStrategy(Wait.ForUnixContainer().UntilPortIsAvailable(TlsPort))
.WithWaitStrategy(Wait.ForUnixContainer().AddCustomWaitStrategy(new UntilListenOn()))
.Build();
}

Expand Down Expand Up @@ -67,5 +68,15 @@ public Task DisposeAsync()
{
return this.container.DisposeAsync().AsTask();
}

private sealed class UntilListenOn : IWaitUntil
{
public async Task<bool> Until(ITestcontainersContainer testcontainers, ILogger logger)
{
var (_, stderr) = await testcontainers.GetLogs()
.ConfigureAwait(false);
return stderr != null && stderr.Contains("API listen on [::]:2376");
}
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ namespace DotNet.Testcontainers.Tests.Unit
using Azure.Storage.Queues;
using DotNet.Testcontainers.Configurations;
using DotNet.Testcontainers.Tests.Fixtures;
using JetBrains.Annotations;
using Xunit;

public static class AzuriteTestcontainerTest
Expand Down Expand Up @@ -52,38 +53,9 @@ public void ShouldEnableAllServices(AzuriteTestcontainerConfiguration configurat
}
}

[Collection(nameof(Testcontainers))]
public sealed class AllServicesEnabled : IClassFixture<AzuriteFixture.AzuriteDefaultFixture>, IClassFixture<AzuriteFixture.AzuriteWithCustomContainerPortsFixture>
[UsedImplicitly]
public sealed class AllServicesEnabled
{
private readonly AzuriteFixture.AzuriteDefaultFixture commonContainerPorts;

private readonly AzuriteFixture.AzuriteDefaultFixture customContainerPorts;

public AllServicesEnabled(AzuriteFixture.AzuriteDefaultFixture commonContainerPorts, AzuriteFixture.AzuriteWithCustomContainerPortsFixture customContainerPorts)
{
this.commonContainerPorts = commonContainerPorts;
this.customContainerPorts = customContainerPorts;
}

private AllServicesEnabled(AzuriteFixture.AzuriteDefaultFixture commonContainerPorts)
{
_ = commonContainerPorts;
}

private AllServicesEnabled(AzuriteFixture.AzuriteWithCustomContainerPortsFixture customContainerPorts)
{
_ = customContainerPorts;
}

[Fact]
public async Task ConnectionEstablished()
{
var exception = await Record.ExceptionAsync(() => Task.WhenAll(EstablishConnection(this.commonContainerPorts), EstablishConnection(this.customContainerPorts)))
.ConfigureAwait(false);

Assert.Null(exception);
}

private static async Task EstablishConnection(AzuriteFixture.AzuriteDefaultFixture azurite)
{
// Given
Expand Down Expand Up @@ -118,6 +90,42 @@ private static async Task EstablishConnection(AzuriteFixture.AzuriteDefaultFixtu
Assert.Contains(QueueServiceDataFileName, execResult.Stdout);
Assert.Contains(TableServiceDataFileName, execResult.Stdout);
}

[Collection(nameof(Testcontainers))]
public sealed class CommonContainerPorts : IClassFixture<AzuriteFixture.AzuriteDefaultFixture>
{
private readonly AzuriteFixture.AzuriteDefaultFixture commonContainerPorts;

public CommonContainerPorts(AzuriteFixture.AzuriteDefaultFixture commonContainerPorts)
{
this.commonContainerPorts = commonContainerPorts;
}

[Fact]
public async Task ConnectionEstablished()
{
Assert.Null(await Record.ExceptionAsync(() => EstablishConnection(this.commonContainerPorts))
.ConfigureAwait(false));
}
}

[Collection(nameof(Testcontainers))]
public sealed class CustomContainerPorts : IClassFixture<AzuriteFixture.AzuriteWithCustomContainerPortsFixture>
{
private readonly AzuriteFixture.AzuriteDefaultFixture customContainerPorts;

public CustomContainerPorts(AzuriteFixture.AzuriteWithCustomContainerPortsFixture customContainerPorts)
{
this.customContainerPorts = customContainerPorts;
}

[Fact]
public async Task ConnectionEstablished()
{
Assert.Null(await Record.ExceptionAsync(() => EstablishConnection(this.customContainerPorts))
.ConfigureAwait(false));
}
}
}

[Collection(nameof(Testcontainers))]
Expand Down Expand Up @@ -256,16 +264,7 @@ public sealed class CustomLocation : IClassFixture<AzuriteFixture.AzuriteWithCus

public CustomLocation(AzuriteFixture.AzuriteWithCustomWorkspaceFixture azurite)
{
if (Directory.Exists(azurite.Configuration.Location))
{
this.dataFiles = Directory.EnumerateFiles(azurite.Configuration.Location, "*", SearchOption.TopDirectoryOnly)
.Select(Path.GetFileName)
.ToArray();
}
else
{
this.dataFiles = Array.Empty<string>();
}
this.dataFiles = Directory.Exists(azurite.Configuration.Location) ? Directory.EnumerateFiles(azurite.Configuration.Location, "*", SearchOption.TopDirectoryOnly).Select(Path.GetFileName) : Array.Empty<string>();
}

[Fact]
Expand Down