Fix build and code structure improvements. New but essential UI functionality. CI improvements. Documentation improvements. AI module improvements.

This commit is contained in:
StellaOps Bot
2025-12-26 21:54:17 +02:00
parent 335ff7da16
commit c2b9cd8d1f
3717 changed files with 264714 additions and 48202 deletions

View File

@@ -0,0 +1,203 @@
// -----------------------------------------------------------------------------
// ValkeyContainerFixture.cs
// Sprint: SPRINT_5100_0010_0003 - Router + Messaging Test Implementation
// Task: MESSAGING-5100-004 - Valkey transport compliance tests
// Description: Collection fixture providing a shared Valkey container for integration tests
// -----------------------------------------------------------------------------
using Microsoft.Extensions.Logging;
using Microsoft.Extensions.Logging.Abstractions;
using Microsoft.Extensions.Options;
using StellaOps.Router.Testing.Fixtures;
using Testcontainers.Redis;
using Xunit.Sdk;
namespace StellaOps.Messaging.Transport.Valkey.Tests.Fixtures;
/// <summary>
/// Collection fixture that provides a shared Valkey container for integration tests.
/// Uses Redis container (Valkey is Redis-compatible).
/// Implements IAsyncLifetime to start/stop the container with the test collection.
/// </summary>
public sealed class ValkeyContainerFixture : RouterCollectionFixture, IAsyncDisposable
{
private RedisContainer? _container;
private bool _disposed;
/// <summary>
/// Gets the Valkey container hostname.
/// </summary>
public string HostName => _container?.Hostname ?? "localhost";
/// <summary>
/// Gets the Valkey container mapped port.
/// </summary>
public int Port => _container?.GetMappedPublicPort(6379) ?? 6379;
/// <summary>
/// Gets the connection string for the Valkey container.
/// </summary>
public string ConnectionString => $"{HostName}:{Port}";
/// <summary>
/// Gets a null logger for tests.
/// </summary>
public ILogger<T> GetLogger<T>() => NullLogger<T>.Instance;
/// <summary>
/// Gets whether the container is running.
/// </summary>
public bool IsRunning => _container is not null;
/// <summary>
/// Creates Valkey transport options configured for the test container.
/// </summary>
public ValkeyTransportOptions CreateOptions(int? database = null)
{
return new ValkeyTransportOptions
{
ConnectionString = ConnectionString,
Database = database,
InitializationTimeout = TimeSpan.FromSeconds(30),
ConnectRetry = 3,
AbortOnConnectFail = false,
IdempotencyKeyPrefix = "test:idem:"
};
}
/// <summary>
/// Creates a ValkeyConnectionFactory configured for the test container.
/// </summary>
public ValkeyConnectionFactory CreateConnectionFactory(int? database = null)
{
var options = CreateOptions(database);
return new ValkeyConnectionFactory(
Options.Create(options),
GetLogger<ValkeyConnectionFactory>());
}
/// <summary>
/// Creates message queue options for testing.
/// </summary>
public StellaOps.Messaging.MessageQueueOptions CreateQueueOptions(
string? queueName = null,
string? consumerGroup = null,
string? consumerName = null)
{
return new StellaOps.Messaging.MessageQueueOptions
{
QueueName = queueName ?? $"test:queue:{Guid.NewGuid():N}",
ConsumerGroup = consumerGroup ?? "test-group",
ConsumerName = consumerName ?? $"consumer-{Environment.ProcessId}",
DefaultLeaseDuration = TimeSpan.FromSeconds(30),
MaxDeliveryAttempts = 3,
IdempotencyWindow = TimeSpan.FromMinutes(5),
ApproximateMaxLength = 10000,
RetryInitialBackoff = TimeSpan.FromMilliseconds(100),
RetryMaxBackoff = TimeSpan.FromSeconds(10),
RetryBackoffMultiplier = 2.0
};
}
/// <summary>
/// Creates a ValkeyMessageQueue for testing.
/// </summary>
public ValkeyMessageQueue<TMessage> CreateMessageQueue<TMessage>(
ValkeyConnectionFactory? connectionFactory = null,
StellaOps.Messaging.MessageQueueOptions? queueOptions = null,
TimeProvider? timeProvider = null)
where TMessage : class
{
connectionFactory ??= CreateConnectionFactory();
queueOptions ??= CreateQueueOptions();
var transportOptions = CreateOptions();
return new ValkeyMessageQueue<TMessage>(
connectionFactory,
queueOptions,
transportOptions,
GetLogger<ValkeyMessageQueue<TMessage>>(),
timeProvider);
}
/// <summary>
/// Restarts the container.
/// </summary>
public async Task RestartAsync()
{
if (_container is null)
{
throw new InvalidOperationException("Valkey container is not running.");
}
await _container.StopAsync();
await _container.StartAsync();
}
/// <inheritdoc />
public override async Task InitializeAsync()
{
try
{
_container = new RedisBuilder()
.WithImage("valkey/valkey:8-alpine")
.WithPortBinding(6379, true)
.Build();
await _container.StartAsync();
}
catch (Exception ex)
{
try
{
if (_container is not null)
{
await _container.DisposeAsync();
}
}
catch
{
// Ignore cleanup failures during skip.
}
_container = null;
throw SkipException.ForSkip(
$"Valkey integration tests require Docker/Testcontainers. Skipping because the container failed to start: {ex.Message}");
}
}
/// <inheritdoc />
public override async Task DisposeAsync()
{
await DisposeAsyncCore();
}
async ValueTask IAsyncDisposable.DisposeAsync()
{
await DisposeAsyncCore();
GC.SuppressFinalize(this);
}
private async Task DisposeAsyncCore()
{
if (_disposed) return;
_disposed = true;
if (_container is not null)
{
await _container.StopAsync();
await _container.DisposeAsync();
}
}
}
/// <summary>
/// Collection definition for Valkey integration tests.
/// All tests in this collection share a single Valkey container.
/// </summary>
[CollectionDefinition(Name)]
public sealed class ValkeyIntegrationTestCollection : ICollectionFixture<ValkeyContainerFixture>
{
public const string Name = "Valkey Integration Tests";
}

View File

@@ -0,0 +1,46 @@
// -----------------------------------------------------------------------------
// ValkeyIntegrationFactAttribute.cs
// Sprint: SPRINT_5100_0010_0003 - Router + Messaging Test Implementation
// Task: MESSAGING-5100-004 - Valkey transport compliance tests
// Description: Attribute that skips Valkey integration tests when Docker is not available
// -----------------------------------------------------------------------------
using Xunit;
namespace StellaOps.Messaging.Transport.Valkey.Tests.Fixtures;
/// <summary>
/// Fact attribute for Valkey integration tests.
/// Skips tests when STELLAOPS_TEST_VALKEY environment variable is not set.
/// </summary>
[AttributeUsage(AttributeTargets.Method)]
public sealed class ValkeyIntegrationFactAttribute : FactAttribute
{
public ValkeyIntegrationFactAttribute()
{
var enabled = Environment.GetEnvironmentVariable("STELLAOPS_TEST_VALKEY");
if (!string.Equals(enabled, "1", StringComparison.OrdinalIgnoreCase) &&
!string.Equals(enabled, "true", StringComparison.OrdinalIgnoreCase))
{
Skip = "Valkey integration tests are opt-in. Set STELLAOPS_TEST_VALKEY=1 (requires Docker/Testcontainers).";
}
}
}
/// <summary>
/// Theory attribute for Valkey integration tests.
/// Skips tests when STELLAOPS_TEST_VALKEY environment variable is not set.
/// </summary>
[AttributeUsage(AttributeTargets.Method)]
public sealed class ValkeyIntegrationTheoryAttribute : TheoryAttribute
{
public ValkeyIntegrationTheoryAttribute()
{
var enabled = Environment.GetEnvironmentVariable("STELLAOPS_TEST_VALKEY");
if (!string.Equals(enabled, "1", StringComparison.OrdinalIgnoreCase) &&
!string.Equals(enabled, "true", StringComparison.OrdinalIgnoreCase))
{
Skip = "Valkey integration tests are opt-in. Set STELLAOPS_TEST_VALKEY=1 (requires Docker/Testcontainers).";
}
}
}