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

feat(servicebus): Add support to use a custom MsSqlContainer instance with Service Bus emulator #1335

Open
wants to merge 19 commits into
base: develop
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from 7 commits
Commits
Show all changes
19 commits
Select commit Hold shift + click to select a range
bf3a42f
feat: add exposed API to attach MsSqlContainer to Azure Service Bus e…
lgcmotta Jan 11, 2025
3c3c2b9
feat: invoke CreateAsync for each network attached to ServiceBusConta…
lgcmotta Jan 11, 2025
632aba5
test: create test with custom instance of MsSqlContainer to attach to…
lgcmotta Jan 11, 2025
761cea3
docs: enhance summary documentation for WithMsSqlContainer
lgcmotta Jan 11, 2025
2f74cd3
refactor: remove network and mssql start from asb emulator test
lgcmotta Jan 12, 2025
fee3432
refactor: enumerate networks to array before invoking create async
lgcmotta Jan 12, 2025
fee7110
fix: exclude implicit imported IContainer types when checking for IDa…
lgcmotta Jan 12, 2025
209b2a6
Merge branch 'develop' into develop
lgcmotta Jan 15, 2025
89c3040
test: move service bus container test to abstract class and resolve c…
lgcmotta Jan 20, 2025
8a5f3a0
refactor: reuse public WithMsSqlContainer when invoking private WithM…
lgcmotta Jan 20, 2025
562ffd3
refactor: change summary docs to consistently use MSSQL instead of SQL
lgcmotta Jan 20, 2025
1d4547f
fix: remove commented code
lgcmotta Jan 20, 2025
d78b741
refactor: make ServiceBusContainerTest constructor protected
lgcmotta Jan 20, 2025
9611f83
refactor: place service bus test with default MSSQL before the custom
lgcmotta Jan 20, 2025
952839b
fix: commit 8a5f3a0 causes MSSQL container to be duplicated when usin…
lgcmotta Jan 20, 2025
4aa61f2
refactor: move ASB emulator tests to inside ServiceBusContainerTest c…
lgcmotta Jan 20, 2025
c54334c
chore: reverting `Single` invoke when creating container's network
lgcmotta Jan 21, 2025
a4ef713
feat: move defaults (network and MSSQL) setup from Init to Build
lgcmotta Jan 21, 2025
791f694
chore: merge upstream/develop into develop
lgcmotta Jan 22, 2025
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
22 changes: 22 additions & 0 deletions src/Testcontainers.ServiceBus/ServiceBusBuilder.cs
Original file line number Diff line number Diff line change
Expand Up @@ -54,6 +54,28 @@ public ServiceBusBuilder WithAcceptLicenseAgreement(bool acceptLicenseAgreement)
return WithEnvironment(AcceptLicenseAgreementEnvVar, licenseAgreement);
}

/// <summary>
/// Sets the dependent MSSQL container for the Azure Service Bus Emulator.
/// </summary>
/// <remarks>
/// This method allows attaching an existing SQL Server container instance to the Azure Service Bus Emulator.
/// The containers must be in the same network to enable communication between them.
/// </remarks>
/// <param name="msSqlContainer">An existing instance of <see cref="MsSqlContainer"/> to use as the database backend.</param>
/// <param name="databaseNetworkAlias">The network alias that will be used to connect to the SQL Server container.</param>
/// <param name="saPassword">The SA password for the SQL Server container. Defaults to <see cref="MsSqlBuilder.DefaultPassword"/>.</param>
/// <returns>A configured instance of <see cref="ServiceBusBuilder"/>.</returns>
public ServiceBusBuilder WithMsSqlContainer(
MsSqlContainer msSqlContainer,
string databaseNetworkAlias,
string saPassword = MsSqlBuilder.DefaultPassword)
{
return Merge(DockerResourceConfiguration, new ServiceBusConfiguration(databaseContainer: msSqlContainer))
lgcmotta marked this conversation as resolved.
Show resolved Hide resolved
.DependsOn(msSqlContainer)
.WithEnvironment("MSSQL_SA_PASSWORD", saPassword)
.WithEnvironment("SQL_SERVER", databaseNetworkAlias);
}

/// <inheritdoc />
public override ServiceBusContainer Build()
{
Expand Down
7 changes: 5 additions & 2 deletions src/Testcontainers.ServiceBus/ServiceBusContainer.cs
Original file line number Diff line number Diff line change
Expand Up @@ -33,8 +33,11 @@ public string GetConnectionString()
/// <inheritdoc />
protected override async Task UnsafeCreateAsync(CancellationToken ct = default)
{
await _configuration.Networks.Single().CreateAsync(ct)
.ConfigureAwait(false);
foreach (var network in _configuration.Networks.ToArray())
lgcmotta marked this conversation as resolved.
Show resolved Hide resolved
{
await network.CreateAsync(ct)
.ConfigureAwait(false);
}

await base.UnsafeCreateAsync(ct)
.ConfigureAwait(false);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -37,9 +37,18 @@ public static TheoryData<Type> GetContainerImplementations(bool expectDataProvid

foreach (var testAssembly in testAssemblies)
{
var testAssemblyName = testAssembly.Key.GetName().Name;

// TODO: If a module contains multiple container implementations, it would require all container implementations to implement the interface.
foreach (var containerType in testAssembly.Value.Where(type => type.IsAssignableTo(typeof(IContainer))))
{
var typeAssemblyName = containerType.Assembly.GetName().Name;

if (!string.IsNullOrWhiteSpace(testAssemblyName) && !string.IsNullOrWhiteSpace(typeAssemblyName) && !testAssemblyName.Contains(typeAssemblyName))
{
continue;
}

HofmeisterAn marked this conversation as resolved.
Show resolved Hide resolved
var hasDataProvider = testAssembly.Value.Exists(type => type.IsSubclassOf(typeof(DbProviderFactory)));

if (expectDataProvider && hasDataProvider)
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,60 @@
namespace Testcontainers.ServiceBus;

public class ServiceBusContainerWithCustomMsSqlTest : IAsyncLifetime
lgcmotta marked this conversation as resolved.
Show resolved Hide resolved
{
private static readonly INetwork Network = new NetworkBuilder().Build();

private readonly ServiceBusContainer _serviceBusContainer = new ServiceBusBuilder()
.WithNetwork(Network)
.WithAcceptLicenseAgreement(true)
.WithMsSqlContainer(new MsSqlBuilder()
.WithImage("mcr.microsoft.com/azure-sql-edge:latest")
.WithNetwork(Network)
.WithNetworkAliases("sql-server")
.Build(), "sql-server")
.Build();

public Task InitializeAsync()
{
return _serviceBusContainer.StartAsync();
}

public Task DisposeAsync()
{
return _serviceBusContainer.DisposeAsync().AsTask();
}

[Fact]
[Trait(nameof(DockerCli.DockerPlatform), nameof(DockerCli.DockerPlatform.Linux))]
public async Task ReceiveMessageReturnsSentMessage()
{
// Given
const string helloServiceBus = "Hello, Service Bus!";

// By default, the emulator uses the following configuration:
// https://learn.microsoft.com/en-us/azure/service-bus-messaging/test-locally-with-service-bus-emulator?tabs=automated-script#interact-with-the-emulator.

// Upload a custom configuration before the container starts using the
// `WithResourceMapping(string, string)` API or one of its overloads:
// `WithResourceMapping("Config.json", "/ServiceBus_Emulator/ConfigFiles/")`.
const string queueName = "queue.1";

var message = new ServiceBusMessage(helloServiceBus);

await using var client = new ServiceBusClient(_serviceBusContainer.GetConnectionString());

var sender = client.CreateSender(queueName);

var receiver = client.CreateReceiver(queueName);

// When
await sender.SendMessageAsync(message)
.ConfigureAwait(true);

var receivedMessage = await receiver.ReceiveMessageAsync()
.ConfigureAwait(true);

// Then
Assert.Equal(helloServiceBus, receivedMessage.Body.ToString());
}
}
3 changes: 3 additions & 0 deletions tests/Testcontainers.ServiceBus.Tests/Usings.cs
Original file line number Diff line number Diff line change
@@ -1,5 +1,8 @@
global using System;
global using System.Threading.Tasks;
global using Azure.Messaging.ServiceBus;
global using DotNet.Testcontainers.Builders;
global using DotNet.Testcontainers.Commons;
global using DotNet.Testcontainers.Networks;
global using Testcontainers.MsSql;
global using Xunit;