Fix build and code structure improvements. New but essential UI functionality. CI improvements. Documentation improvements. AI module improvements.
This commit is contained in:
@@ -0,0 +1,108 @@
|
||||
namespace StellaOps.Messaging.Testing.Builders;
|
||||
|
||||
/// <summary>
|
||||
/// Builder for creating test messages with customizable properties.
|
||||
/// </summary>
|
||||
/// <typeparam name="TMessage">The message type.</typeparam>
|
||||
public sealed class TestMessageBuilder<TMessage> where TMessage : class, new()
|
||||
{
|
||||
private readonly Dictionary<string, object?> _properties = new();
|
||||
|
||||
/// <summary>
|
||||
/// Sets a property on the message.
|
||||
/// </summary>
|
||||
public TestMessageBuilder<TMessage> With(string propertyName, object? value)
|
||||
{
|
||||
_properties[propertyName] = value;
|
||||
return this;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Builds the message with all configured properties.
|
||||
/// </summary>
|
||||
public TMessage Build()
|
||||
{
|
||||
var message = new TMessage();
|
||||
var type = typeof(TMessage);
|
||||
|
||||
foreach (var (propertyName, value) in _properties)
|
||||
{
|
||||
var property = type.GetProperty(propertyName);
|
||||
if (property is not null && property.CanWrite)
|
||||
{
|
||||
property.SetValue(message, value);
|
||||
}
|
||||
}
|
||||
|
||||
return message;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Simple test message for queue testing.
|
||||
/// </summary>
|
||||
public sealed record TestQueueMessage
|
||||
{
|
||||
/// <summary>
|
||||
/// Gets or sets the message ID.
|
||||
/// </summary>
|
||||
public string Id { get; set; } = Guid.NewGuid().ToString("N");
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the message content.
|
||||
/// </summary>
|
||||
public string Content { get; set; } = string.Empty;
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the priority.
|
||||
/// </summary>
|
||||
public int Priority { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the tenant ID.
|
||||
/// </summary>
|
||||
public string? TenantId { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets when the message was created.
|
||||
/// </summary>
|
||||
public DateTimeOffset CreatedAt { get; set; } = DateTimeOffset.UtcNow;
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets custom metadata.
|
||||
/// </summary>
|
||||
public Dictionary<string, string> Metadata { get; set; } = new();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Extension methods for creating test messages.
|
||||
/// </summary>
|
||||
public static class TestMessageExtensions
|
||||
{
|
||||
/// <summary>
|
||||
/// Creates a new test queue message with the specified content.
|
||||
/// </summary>
|
||||
public static TestQueueMessage CreateTestMessage(this string content, string? tenantId = null)
|
||||
{
|
||||
return new TestQueueMessage
|
||||
{
|
||||
Content = content,
|
||||
TenantId = tenantId
|
||||
};
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Creates multiple test messages for batch testing.
|
||||
/// </summary>
|
||||
public static IReadOnlyList<TestQueueMessage> CreateTestMessages(int count, string? tenantId = null)
|
||||
{
|
||||
return Enumerable.Range(1, count)
|
||||
.Select(i => new TestQueueMessage
|
||||
{
|
||||
Content = $"Test message {i}",
|
||||
TenantId = tenantId,
|
||||
Priority = i % 3
|
||||
})
|
||||
.ToList();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,84 @@
|
||||
using Microsoft.Extensions.DependencyInjection;
|
||||
using StellaOps.Messaging.Abstractions;
|
||||
using StellaOps.Messaging.Transport.InMemory;
|
||||
using Xunit;
|
||||
|
||||
namespace StellaOps.Messaging.Testing.Fixtures;
|
||||
|
||||
/// <summary>
|
||||
/// xUnit fixture for in-memory messaging transport.
|
||||
/// Provides fast, isolated test infrastructure without external dependencies.
|
||||
/// </summary>
|
||||
public sealed class InMemoryMessagingFixture : IAsyncLifetime
|
||||
{
|
||||
private InMemoryQueueRegistry _registry = null!;
|
||||
|
||||
/// <summary>
|
||||
/// Gets the shared queue registry for test coordination.
|
||||
/// </summary>
|
||||
public InMemoryQueueRegistry Registry => _registry;
|
||||
|
||||
/// <inheritdoc />
|
||||
public ValueTask InitializeAsync()
|
||||
{
|
||||
_registry = new InMemoryQueueRegistry();
|
||||
return ValueTask.CompletedTask;
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public ValueTask DisposeAsync()
|
||||
{
|
||||
_registry.Clear();
|
||||
return ValueTask.CompletedTask;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Creates a service provider configured with in-memory transport.
|
||||
/// </summary>
|
||||
/// <returns>A configured service provider.</returns>
|
||||
public IServiceProvider CreateServiceProvider()
|
||||
{
|
||||
var services = new ServiceCollection();
|
||||
|
||||
services.AddSingleton(_registry);
|
||||
services.AddSingleton<IMessageQueueFactory, InMemoryMessageQueueFactory>();
|
||||
services.AddSingleton<IDistributedCacheFactory, InMemoryCacheFactory>();
|
||||
|
||||
return services.BuildServiceProvider();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Creates a message queue factory using in-memory transport.
|
||||
/// </summary>
|
||||
public IMessageQueueFactory CreateQueueFactory()
|
||||
{
|
||||
var sp = CreateServiceProvider();
|
||||
return sp.GetRequiredService<IMessageQueueFactory>();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Creates a cache factory using in-memory transport.
|
||||
/// </summary>
|
||||
public IDistributedCacheFactory CreateCacheFactory()
|
||||
{
|
||||
var sp = CreateServiceProvider();
|
||||
return sp.GetRequiredService<IDistributedCacheFactory>();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Clears all queues and caches in the registry.
|
||||
/// Call this between tests for isolation.
|
||||
/// </summary>
|
||||
public void Reset()
|
||||
{
|
||||
_registry.Clear();
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Collection definition for in-memory messaging fixture sharing across test classes.
|
||||
/// </summary>
|
||||
[CollectionDefinition(nameof(InMemoryMessagingFixtureCollection))]
|
||||
public class InMemoryMessagingFixtureCollection : ICollectionFixture<InMemoryMessagingFixture>
|
||||
{
|
||||
}
|
||||
@@ -0,0 +1,97 @@
|
||||
using Microsoft.Extensions.DependencyInjection;
|
||||
using StellaOps.Messaging.Abstractions;
|
||||
using StellaOps.Messaging.Transport.Postgres;
|
||||
using Testcontainers.PostgreSql;
|
||||
using Xunit;
|
||||
|
||||
namespace StellaOps.Messaging.Testing.Fixtures;
|
||||
|
||||
/// <summary>
|
||||
/// xUnit fixture for PostgreSQL testcontainer.
|
||||
/// Provides a containerized PostgreSQL instance for queue integration tests.
|
||||
/// </summary>
|
||||
public sealed class PostgresQueueFixture : IAsyncLifetime
|
||||
{
|
||||
private readonly PostgreSqlContainer _container;
|
||||
|
||||
/// <summary>
|
||||
/// Gets the connection string for the PostgreSQL instance.
|
||||
/// </summary>
|
||||
public string ConnectionString => _container.GetConnectionString();
|
||||
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the <see cref="PostgresQueueFixture"/> class.
|
||||
/// </summary>
|
||||
public PostgresQueueFixture()
|
||||
{
|
||||
_container = new PostgreSqlBuilder()
|
||||
.WithImage("postgres:16-alpine")
|
||||
.WithDatabase("stellaops_messaging_test")
|
||||
.WithUsername("test")
|
||||
.WithPassword("test")
|
||||
.Build();
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public async ValueTask InitializeAsync()
|
||||
{
|
||||
await _container.StartAsync();
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public async ValueTask DisposeAsync()
|
||||
{
|
||||
await _container.StopAsync();
|
||||
await _container.DisposeAsync();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Creates a service provider configured with PostgreSQL transport.
|
||||
/// </summary>
|
||||
/// <param name="configureOptions">Optional configuration for PostgreSQL options.</param>
|
||||
/// <returns>A configured service provider.</returns>
|
||||
public IServiceProvider CreateServiceProvider(Action<PostgresTransportOptions>? configureOptions = null)
|
||||
{
|
||||
var services = new ServiceCollection();
|
||||
|
||||
services.AddOptions<PostgresTransportOptions>().Configure(options =>
|
||||
{
|
||||
options.ConnectionString = ConnectionString;
|
||||
options.Schema = "messaging";
|
||||
options.AutoCreateTables = true;
|
||||
configureOptions?.Invoke(options);
|
||||
});
|
||||
|
||||
services.AddSingleton<PostgresConnectionFactory>();
|
||||
services.AddSingleton<IMessageQueueFactory, PostgresMessageQueueFactory>();
|
||||
services.AddSingleton<IDistributedCacheFactory, PostgresCacheFactory>();
|
||||
|
||||
return services.BuildServiceProvider();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Creates a message queue factory using PostgreSQL transport.
|
||||
/// </summary>
|
||||
public IMessageQueueFactory CreateQueueFactory()
|
||||
{
|
||||
var sp = CreateServiceProvider();
|
||||
return sp.GetRequiredService<IMessageQueueFactory>();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Creates a cache factory using PostgreSQL transport.
|
||||
/// </summary>
|
||||
public IDistributedCacheFactory CreateCacheFactory()
|
||||
{
|
||||
var sp = CreateServiceProvider();
|
||||
return sp.GetRequiredService<IDistributedCacheFactory>();
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Collection definition for PostgreSQL fixture sharing across test classes.
|
||||
/// </summary>
|
||||
[CollectionDefinition(nameof(PostgresQueueFixtureCollection))]
|
||||
public class PostgresQueueFixtureCollection : ICollectionFixture<PostgresQueueFixture>
|
||||
{
|
||||
}
|
||||
@@ -0,0 +1,108 @@
|
||||
using DotNet.Testcontainers.Builders;
|
||||
using DotNet.Testcontainers.Containers;
|
||||
using Microsoft.Extensions.DependencyInjection;
|
||||
using StellaOps.Messaging.Abstractions;
|
||||
using StellaOps.Messaging.Transport.Valkey;
|
||||
using Xunit;
|
||||
|
||||
namespace StellaOps.Messaging.Testing.Fixtures;
|
||||
|
||||
/// <summary>
|
||||
/// xUnit fixture for Valkey testcontainer.
|
||||
/// Provides a containerized Valkey instance for integration tests.
|
||||
/// </summary>
|
||||
public sealed class ValkeyFixture : IAsyncLifetime
|
||||
{
|
||||
private readonly IContainer _container;
|
||||
|
||||
/// <summary>
|
||||
/// Gets the connection string for the Valkey instance.
|
||||
/// </summary>
|
||||
public string ConnectionString { get; private set; } = null!;
|
||||
|
||||
/// <summary>
|
||||
/// Gets the host of the Valkey instance.
|
||||
/// </summary>
|
||||
public string Host => _container.Hostname;
|
||||
|
||||
/// <summary>
|
||||
/// Gets the mapped port for the Valkey instance.
|
||||
/// </summary>
|
||||
public ushort Port { get; private set; }
|
||||
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the <see cref="ValkeyFixture"/> class.
|
||||
/// </summary>
|
||||
public ValkeyFixture()
|
||||
{
|
||||
_container = new ContainerBuilder()
|
||||
.WithImage("valkey/valkey:8-alpine")
|
||||
.WithPortBinding(6379, true)
|
||||
.WithWaitStrategy(Wait.ForUnixContainer()
|
||||
.UntilCommandIsCompleted("valkey-cli", "ping"))
|
||||
.Build();
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public async ValueTask InitializeAsync()
|
||||
{
|
||||
await _container.StartAsync();
|
||||
Port = _container.GetMappedPublicPort(6379);
|
||||
ConnectionString = $"{Host}:{Port}";
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public async ValueTask DisposeAsync()
|
||||
{
|
||||
await _container.StopAsync();
|
||||
await _container.DisposeAsync();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Creates a service provider configured with Valkey transport.
|
||||
/// </summary>
|
||||
/// <param name="configureOptions">Optional configuration for Valkey options.</param>
|
||||
/// <returns>A configured service provider.</returns>
|
||||
public IServiceProvider CreateServiceProvider(Action<ValkeyTransportOptions>? configureOptions = null)
|
||||
{
|
||||
var services = new ServiceCollection();
|
||||
|
||||
services.AddOptions<ValkeyTransportOptions>().Configure(options =>
|
||||
{
|
||||
options.ConnectionString = ConnectionString;
|
||||
configureOptions?.Invoke(options);
|
||||
});
|
||||
|
||||
services.AddSingleton<ValkeyConnectionFactory>();
|
||||
services.AddSingleton<IMessageQueueFactory, ValkeyMessageQueueFactory>();
|
||||
services.AddSingleton<IDistributedCacheFactory, ValkeyCacheFactory>();
|
||||
|
||||
return services.BuildServiceProvider();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Creates a message queue factory using Valkey transport.
|
||||
/// </summary>
|
||||
public IMessageQueueFactory CreateQueueFactory()
|
||||
{
|
||||
var sp = CreateServiceProvider();
|
||||
return sp.GetRequiredService<IMessageQueueFactory>();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Creates a cache factory using Valkey transport.
|
||||
/// </summary>
|
||||
public IDistributedCacheFactory CreateCacheFactory()
|
||||
{
|
||||
var sp = CreateServiceProvider();
|
||||
return sp.GetRequiredService<IDistributedCacheFactory>();
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Collection definition for Valkey fixture sharing across test classes.
|
||||
/// </summary>
|
||||
[CollectionDefinition(nameof(ValkeyFixtureCollection))]
|
||||
public class ValkeyFixtureCollection : ICollectionFixture<ValkeyFixture>
|
||||
{
|
||||
}
|
||||
@@ -0,0 +1,28 @@
|
||||
<Project Sdk="Microsoft.NET.Sdk">
|
||||
|
||||
<PropertyGroup>
|
||||
<UseXunitV3>true</UseXunitV3>
|
||||
<TargetFramework>net10.0</TargetFramework>
|
||||
<ImplicitUsings>enable</ImplicitUsings>
|
||||
<Nullable>enable</Nullable>
|
||||
<LangVersion>preview</LangVersion>
|
||||
<TreatWarningsAsErrors>false</TreatWarningsAsErrors>
|
||||
<RootNamespace>StellaOps.Messaging.Testing</RootNamespace>
|
||||
</PropertyGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<ProjectReference Include="..\..\..\__Libraries\StellaOps.Messaging\StellaOps.Messaging.csproj" />
|
||||
<ProjectReference Include="..\..\..\__Libraries\StellaOps.Messaging.Transport.Valkey\StellaOps.Messaging.Transport.Valkey.csproj" />
|
||||
<ProjectReference Include="..\..\..\__Libraries\StellaOps.Messaging.Transport.Postgres\StellaOps.Messaging.Transport.Postgres.csproj" />
|
||||
<ProjectReference Include="..\..\..\__Libraries\StellaOps.Messaging.Transport.InMemory\StellaOps.Messaging.Transport.InMemory.csproj" />
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<PackageReference Include="Microsoft.Extensions.DependencyInjection" />
|
||||
<PackageReference Include="Microsoft.Extensions.Logging.Abstractions" />
|
||||
<PackageReference Include="Testcontainers" />
|
||||
<PackageReference Include="Testcontainers.PostgreSql" />
|
||||
<PackageReference Include="xunit.v3.extensibility.core" PrivateAssets="all" />
|
||||
</ItemGroup>
|
||||
|
||||
</Project>
|
||||
Reference in New Issue
Block a user