Skip to content

Commit

Permalink
feat(Azurite): Add in-memory support (#1063)
Browse files Browse the repository at this point in the history
Co-authored-by: Raphael Strotz <[email protected]>
Co-authored-by: Andre Hofmeister <[email protected]>
  • Loading branch information
3 people authored Dec 6, 2023
1 parent ae37ad4 commit 4e20ad9
Show file tree
Hide file tree
Showing 4 changed files with 116 additions and 46 deletions.
2 changes: 1 addition & 1 deletion .devcontainer/devcontainer.json
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@
"moby": true
},
"ghcr.io/devcontainers/features/dotnet:1": {
"version": "6.0.413",
"version": "8.0.100",
"installUsingApt": false
}
},
Expand Down
45 changes: 35 additions & 10 deletions src/Testcontainers.Azurite/AzuriteBuilder.cs
Original file line number Diff line number Diff line change
Expand Up @@ -4,15 +4,22 @@ namespace Testcontainers.Azurite;
[PublicAPI]
public sealed class AzuriteBuilder : ContainerBuilder<AzuriteBuilder, AzuriteContainer, AzuriteConfiguration>
{
public const string AzuriteImage = "mcr.microsoft.com/azure-storage/azurite:3.24.0";
public const string AzuriteImage = "mcr.microsoft.com/azure-storage/azurite:3.28.0";

public const ushort BlobPort = 10000;

public const ushort QueuePort = 10001;

public const ushort TablePort = 10002;

private readonly ISet<AzuriteService> _enabledServices = new HashSet<AzuriteService>();
private static readonly ISet<AzuriteService> EnabledServices = new HashSet<AzuriteService>();

static AzuriteBuilder()
{
EnabledServices.Add(AzuriteService.Blob);
EnabledServices.Add(AzuriteService.Queue);
EnabledServices.Add(AzuriteService.Table);
}

/// <summary>
/// Initializes a new instance of the <see cref="AzuriteBuilder" /> class.
Expand All @@ -21,10 +28,6 @@ public AzuriteBuilder()
: this(new AzuriteConfiguration())
{
DockerResourceConfiguration = Init().DockerResourceConfiguration;

_enabledServices.Add(AzuriteService.Blob);
_enabledServices.Add(AzuriteService.Queue);
_enabledServices.Add(AzuriteService.Table);
}

/// <summary>
Expand All @@ -40,24 +43,44 @@ private AzuriteBuilder(AzuriteConfiguration resourceConfiguration)
/// <inheritdoc />
protected override AzuriteConfiguration DockerResourceConfiguration { get; }

/// <summary>
/// Enables in-memory persistence.
/// </summary>
/// <remarks>
/// By default, the in-memory is limited to 50% of the total memory on the container.
/// </remarks>
/// <param name="megabytes">An optional in-memory limit in megabytes.</param>
/// <returns>A configured instance of <see cref="AzuriteBuilder" />.</returns>
public AzuriteBuilder WithInMemoryPersistence(float? megabytes = null)
{
if (megabytes.HasValue)
{
return WithCommand("--inMemoryPersistence", "--extentMemoryLimit", megabytes.ToString());
}
else
{
return WithCommand("--inMemoryPersistence");
}
}

/// <inheritdoc />
public override AzuriteContainer Build()
{
Validate();

var waitStrategy = Wait.ForUnixContainer();

if (_enabledServices.Contains(AzuriteService.Blob))
if (EnabledServices.Contains(AzuriteService.Blob))
{
waitStrategy = waitStrategy.UntilMessageIsLogged("Blob service is successfully listening");
}

if (_enabledServices.Contains(AzuriteService.Queue))
if (EnabledServices.Contains(AzuriteService.Queue))
{
waitStrategy = waitStrategy.UntilMessageIsLogged("Queue service is successfully listening");
}

if (_enabledServices.Contains(AzuriteService.Table))
if (EnabledServices.Contains(AzuriteService.Table))
{
waitStrategy = waitStrategy.UntilMessageIsLogged("Table service is successfully listening");
}
Expand All @@ -73,7 +96,9 @@ protected override AzuriteBuilder Init()
.WithImage(AzuriteImage)
.WithPortBinding(BlobPort, true)
.WithPortBinding(QueuePort, true)
.WithPortBinding(TablePort, true);
.WithPortBinding(TablePort, true)
.WithEntrypoint("azurite")
.WithCommand("--blobHost", "0.0.0.0", "--queueHost", "0.0.0.0", "--tableHost", "0.0.0.0");
}

/// <inheritdoc />
Expand Down
111 changes: 76 additions & 35 deletions tests/Testcontainers.Azurite.Tests/AzuriteContainerTest.cs
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,12 @@ namespace Testcontainers.Azurite;

public abstract class AzuriteContainerTest : IAsyncLifetime
{
private readonly AzuriteContainer _azuriteContainer = new AzuriteBuilder().Build();
private readonly AzuriteContainer _azuriteContainer;

private AzuriteContainerTest(AzuriteContainer azuriteContainer)
{
_azuriteContainer = azuriteContainer;
}

public Task InitializeAsync()
{
Expand All @@ -14,6 +19,51 @@ public Task DisposeAsync()
return _azuriteContainer.DisposeAsync().AsTask();
}

[Fact]
[Trait(nameof(DockerCli.DockerPlatform), nameof(DockerCli.DockerPlatform.Linux))]
public async Task EstablishesBlobServiceConnection()
{
// Give
var client = new BlobServiceClient(_azuriteContainer.GetConnectionString());

// When
var properties = await client.GetPropertiesAsync()
.ConfigureAwait(false);

// Then
Assert.False(HasError(properties));
}

[Fact]
[Trait(nameof(DockerCli.DockerPlatform), nameof(DockerCli.DockerPlatform.Linux))]
public async Task EstablishesQueueServiceConnection()
{
// Give
var client = new QueueServiceClient(_azuriteContainer.GetConnectionString());

// When
var properties = await client.GetPropertiesAsync()
.ConfigureAwait(false);

// Then
Assert.False(HasError(properties));
}

[Fact]
[Trait(nameof(DockerCli.DockerPlatform), nameof(DockerCli.DockerPlatform.Linux))]
public async Task EstablishesTableServiceConnection()
{
// Give
var client = new TableServiceClient(_azuriteContainer.GetConnectionString());

// When
var properties = await client.GetPropertiesAsync()
.ConfigureAwait(false);

// Then
Assert.False(HasError(properties));
}

private static bool HasError<TResponseEntity>(NullableResponse<TResponseEntity> response)
{
using (var rawResponse = response.GetRawResponse())
Expand All @@ -22,57 +72,48 @@ private static bool HasError<TResponseEntity>(NullableResponse<TResponseEntity>
}
}

public sealed class BlobService : AzuriteContainerTest
[UsedImplicitly]
public sealed class AzuriteDefaultConfiguration : AzuriteContainerTest
{
[Fact]
[Trait(nameof(DockerCli.DockerPlatform), nameof(DockerCli.DockerPlatform.Linux))]
public async Task EstablishesConnection()
public AzuriteDefaultConfiguration()
: base(new AzuriteBuilder().Build())
{
// Give
var client = new BlobServiceClient(_azuriteContainer.GetConnectionString());

// When
var properties = await client.GetPropertiesAsync()
.ConfigureAwait(false);

// Then
Assert.False(HasError(properties));
}
}

public sealed class QueueService : AzuriteContainerTest
[UsedImplicitly]
public sealed class AzuriteInMemoryConfiguration : AzuriteContainerTest
{
[Fact]
[Trait(nameof(DockerCli.DockerPlatform), nameof(DockerCli.DockerPlatform.Linux))]
public async Task EstablishesConnection()
public AzuriteInMemoryConfiguration()
: base(new AzuriteBuilder().WithInMemoryPersistence().Build())
{
// Give
var client = new QueueServiceClient(_azuriteContainer.GetConnectionString());

// When
var properties = await client.GetPropertiesAsync()
.ConfigureAwait(false);

// Then
Assert.False(HasError(properties));
}
}

public sealed class TableService : AzuriteContainerTest
[UsedImplicitly]
public sealed class AzuriteMemoryLimitConfiguration : AzuriteContainerTest
{
private const int MemoryLimitInMb = 64;

private static readonly string[] LineEndings = { "\r\n", "\n" };

public AzuriteMemoryLimitConfiguration()
: base(new AzuriteBuilder().WithInMemoryPersistence(MemoryLimitInMb).Build())
{
}

[Fact]
[Trait(nameof(DockerCli.DockerPlatform), nameof(DockerCli.DockerPlatform.Linux))]
public async Task EstablishesConnection()
public async Task MemoryLimitIsConfigured()
{
// Give
var client = new TableServiceClient(_azuriteContainer.GetConnectionString());
// Given
var (stdout, _) = await _azuriteContainer.GetLogsAsync(timestampsEnabled: false)
.ConfigureAwait(false);

// When
var properties = await client.GetPropertiesAsync()
.ConfigureAwait(false);
var firstLine = stdout.Split(LineEndings, StringSplitOptions.RemoveEmptyEntries).First();

// Then
Assert.False(HasError(properties));
Assert.StartsWith(string.Format(CultureInfo.InvariantCulture, "In-memory extent storage is enabled with a limit of {0:F2} MB", MemoryLimitInMb), firstLine);
}
}
}
4 changes: 4 additions & 0 deletions tests/Testcontainers.Azurite.Tests/Usings.cs
Original file line number Diff line number Diff line change
@@ -1,7 +1,11 @@
global using System;
global using System.Globalization;
global using System.Linq;
global using System.Threading.Tasks;
global using Azure;
global using Azure.Data.Tables;
global using Azure.Storage.Blobs;
global using Azure.Storage.Queues;
global using DotNet.Testcontainers.Commons;
global using JetBrains.Annotations;
global using Xunit;

0 comments on commit 4e20ad9

Please sign in to comment.