Skip to content
Merged
Show file tree
Hide file tree
Changes from 2 commits
Commits
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
18 changes: 17 additions & 1 deletion src/Components/Aspire.RabbitMQ.Client/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@ dotnet add package Aspire.RabbitMQ.Client

## Usage example

In the _AppHost.cs_ file of your project, call the `AddRabbitMQClient` extension method to register an `IConnection` for use via the dependency injection container. The method takes a connection name parameter.
In the _Program.cs_ file of your project, call the `AddRabbitMQClient` extension method to register an `IConnection` for use via the dependency injection container. The method takes a connection name parameter.

```csharp
builder.AddRabbitMQClient("messaging");
Expand Down Expand Up @@ -89,6 +89,22 @@ You can also setup the [ConnectionFactory](https://rabbitmq.github.io/rabbitmq-d
builder.AddRabbitMQClient("messaging", configureConnectionFactory: factory => factory.ClientProvidedName = "MyApp");
```

## Observability
Comment thread
eerhardt marked this conversation as resolved.
Outdated

### Tracing

The Aspire RabbitMQ Client integration includes the following activity sources for OpenTelemetry tracing:

- `Aspire.RabbitMQ.Client` - Tracks connection establishment and retry attempts.
- `RabbitMQ.Client.Publisher` - Tracks message publishing operations.
- `RabbitMQ.Client.Subscriber` - Tracks message consumption operations.

Tracing is enabled by default. To disable it, set `DisableTracing` to `true` in the settings:

```csharp
builder.AddRabbitMQClient("messaging", settings => settings.DisableTracing = true);
```

## AppHost extensions

In your AppHost project, install the `Aspire.Hosting.RabbitMQ` library with [NuGet](https://www.nuget.org):
Expand Down
71 changes: 60 additions & 11 deletions tests/Aspire.RabbitMQ.Client.Tests/ConformanceTests.cs
Original file line number Diff line number Diff line change
@@ -1,23 +1,30 @@
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.

using System.Diagnostics;
using Aspire.TestUtilities;
using Aspire.Components.ConformanceTests;
using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Hosting;
using Microsoft.Extensions.Logging;
using OpenTelemetry.Trace;
using RabbitMQ.Client;
using Xunit;

namespace Aspire.RabbitMQ.Client.Tests;

public class ConformanceTests : ConformanceTests<IConnection, RabbitMQClientSettings>, IClassFixture<RabbitMQContainerFixture>
{
private readonly RabbitMQContainerFixture _containerFixture;
private readonly RabbitMQContainerFixture? _containerFixture;
private string ConnectionString { get; set; }

public ConformanceTests(RabbitMQContainerFixture containerFixture, ITestOutputHelper? output = null) : base(output)
public ConformanceTests(RabbitMQContainerFixture? containerFixture, ITestOutputHelper? output = null) : base(output)
{
_containerFixture = containerFixture;
ConnectionString = (_containerFixture is not null && RequiresFeatureAttribute.IsFeatureSupported(TestFeature.Docker))
? _containerFixture.GetConnectionString()
: "amqp://localhost:5672";
}

protected override ServiceLifetime ServiceLifetime => ServiceLifetime.Singleton;
Expand All @@ -31,7 +38,11 @@ public ConformanceTests(RabbitMQContainerFixture containerFixture, ITestOutputHe

protected override string[] RequiredLogCategories => Array.Empty<string>();

protected override string ActivitySourceName => "";
#if RABBITMQ_V6
protected override string ActivitySourceName => "Aspire.RabbitMQ.Client";
Comment thread
eerhardt marked this conversation as resolved.
#else
protected override string ActivitySourceName => "RabbitMQ.Client.Publisher";
#endif

protected override string? ConfigurationSectionName => "Aspire:RabbitMQ:Client";

Expand Down Expand Up @@ -69,15 +80,9 @@ protected override (string json, string error)[] InvalidJsonToErrorMessage => ne
};

protected override void PopulateConfiguration(ConfigurationManager configuration, string? key = null)
{
var connectionString = RequiresFeatureAttribute.IsFeatureSupported(TestFeature.Docker) ?
Comment thread
eerhardt marked this conversation as resolved.
_containerFixture.GetConnectionString() :
"amqp://localhost:5672";

configuration.AddInMemoryCollection([
new(CreateConfigKey("Aspire:RabbitMQ:Client", key, "ConnectionString"), connectionString)
=> configuration.AddInMemoryCollection([
new(CreateConfigKey("Aspire:RabbitMQ:Client", key, "ConnectionString"), ConnectionString)
]);
}

protected override void RegisterComponent(HostApplicationBuilder builder, Action<RabbitMQClientSettings>? configure = null, string? key = null)
{
Expand Down Expand Up @@ -132,4 +137,48 @@ protected override void SetupConnectionInformationIsDelayValidated()
{
Assert.Skip("RabbitMQ connects to localhost by default if the connection information isn't available.");
}

#if !RABBITMQ_V6
[Fact]
[RequiresFeature(TestFeature.Docker)]
public void TracingEnablesTheRightActivitySource()
=> RemoteInvokeWithLogging(static connectionStringToUse =>
RunWithConnectionString(connectionStringToUse, static obj => obj.RunActivitySourceTest(key: null)),
ConnectionString, Output);

[Fact]
[RequiresFeature(TestFeature.Docker)]
public void TracingEnablesTheRightActivitySource_Keyed()
=> RemoteInvokeWithLogging(static connectionStringToUse =>
RunWithConnectionString(connectionStringToUse, static obj => obj.RunActivitySourceTest(key: "key")),
ConnectionString, Output);

private void RunActivitySourceTest(string? key)
Comment thread
eerhardt marked this conversation as resolved.
{
HostApplicationBuilder builder = CreateHostBuilder(key: key);
builder.Logging.AddConsole();
RegisterComponent(builder, options => SetTracing(options, true), key);

List<Activity> exportedActivities = [];
builder.Services.AddOpenTelemetry().WithTracing(traceBuilder => traceBuilder.AddInMemoryExporter(exportedActivities));

using IHost host = builder.Build();
host.Start();

IConnection service = key is null
? host.Services.GetRequiredService<IConnection>()
: host.Services.GetRequiredKeyedService<IConnection>(key);

// Clear activities generated during connection establishment (from "Aspire.RabbitMQ.Client" source)
exportedActivities.Clear();

TriggerActivity(service);

Assert.NotEmpty(exportedActivities);
Assert.Contains(exportedActivities, activity => activity.Source.Name == ActivitySourceName);
}

private static void RunWithConnectionString(string connectionString, Action<ConformanceTests> test)
=> test(new ConformanceTests(null) { ConnectionString = connectionString });
#endif
}