using System.Reflection;
using GFramework.Core.Abstractions.Cqrs;
using GFramework.Core.Abstractions.Logging;
using GFramework.Core.Architectures;
using GFramework.Core.Ioc;
using GFramework.Core.Logging;
using GFramework.Core.Tests.Logging;
namespace GFramework.Core.Tests.Cqrs;
///
/// 验证 CQRS 处理器自动注册在顺序与容错层面的可观察行为。
///
[TestFixture]
internal sealed class CqrsHandlerRegistrarTests
{
private static readonly MethodInfo RecoverLoadableTypesMethod = typeof(ArchitectureContext).Assembly
.GetType(
"GFramework.Core.Cqrs.Internal.CqrsHandlerRegistrar",
throwOnError: true)!
.GetMethod("RecoverLoadableTypes",
BindingFlags.NonPublic |
BindingFlags.Static)!
?? throw new InvalidOperationException(
"Failed to locate CqrsHandlerRegistrar.RecoverLoadableTypes.");
private MicrosoftDiContainer? _container;
private ArchitectureContext? _context;
///
/// 初始化测试容器并重置共享状态。
///
[SetUp]
public void SetUp()
{
LoggerFactoryResolver.Provider = new ConsoleLoggerFactoryProvider();
DeterministicNotificationHandlerState.Reset();
_container = new MicrosoftDiContainer();
CqrsTestRuntime.RegisterHandlers(
_container,
typeof(CqrsHandlerRegistrarTests).Assembly,
typeof(ArchitectureContext).Assembly);
_container.Freeze();
_context = new ArchitectureContext(_container);
}
///
/// 清理测试过程中创建的上下文与共享状态。
///
[TearDown]
public void TearDown()
{
_context = null;
_container = null;
DeterministicNotificationHandlerState.Reset();
}
///
/// 验证自动扫描到的通知处理器会按稳定名称顺序执行,而不是依赖反射枚举顺序。
///
[Test]
public async Task PublishAsync_Should_Run_Notification_Handlers_In_Deterministic_Name_Order()
{
await _context!.PublishAsync(new DeterministicOrderNotification());
Assert.That(
DeterministicNotificationHandlerState.InvocationOrder,
Is.EqualTo(
[
nameof(AlphaDeterministicNotificationHandler),
nameof(ZetaDeterministicNotificationHandler)
]));
}
///
/// 验证部分类型加载失败时仍能保留可加载类型,并记录诊断日志。
///
[Test]
public void RecoverLoadableTypes_Should_Return_Loadable_Types_And_Log_Warnings()
{
var logger = new TestLogger(nameof(CqrsHandlerRegistrarTests), LogLevel.Warning);
var reflectionTypeLoadException = new ReflectionTypeLoadException(
[typeof(AlphaDeterministicNotificationHandler), null],
[new TypeLoadException("Missing optional dependency for registrar test.")]);
var recoveredTypes = (IReadOnlyList)RecoverLoadableTypesMethod.Invoke(
null,
[typeof(CqrsHandlerRegistrarTests).Assembly, reflectionTypeLoadException, logger])!;
Assert.Multiple(() =>
{
Assert.That(recoveredTypes, Is.EqualTo([typeof(AlphaDeterministicNotificationHandler)]));
Assert.That(logger.Logs.Count(log => log.Level == LogLevel.Warning), Is.GreaterThanOrEqualTo(2));
Assert.That(
logger.Logs.Any(log => log.Message.Contains("partially failed", StringComparison.Ordinal)),
Is.True);
Assert.That(
logger.Logs.Any(log => log.Message.Contains("Missing optional dependency", StringComparison.Ordinal)),
Is.True);
});
}
}
///
/// 记录确定性通知处理器的实际执行顺序。
///
internal static class DeterministicNotificationHandlerState
{
///
/// 获取当前测试中的通知处理器执行顺序。
///
public static List InvocationOrder { get; } = [];
///
/// 重置共享的执行顺序状态。
///
public static void Reset()
{
InvocationOrder.Clear();
}
}
///
/// 用于验证同一通知的多个处理器是否按稳定顺序执行。
///
internal sealed record DeterministicOrderNotification : INotification;
///
/// 故意放在 Alpha 之前声明,用于验证注册器不会依赖源码声明顺序。
///
internal sealed class ZetaDeterministicNotificationHandler : INotificationHandler
{
///
/// 记录当前处理器已执行。
///
/// 通知实例。
/// 取消令牌。
/// 已完成任务。
public ValueTask Handle(DeterministicOrderNotification notification, CancellationToken cancellationToken)
{
DeterministicNotificationHandlerState.InvocationOrder.Add(nameof(ZetaDeterministicNotificationHandler));
return ValueTask.CompletedTask;
}
}
///
/// 名称排序上应先于 Zeta 处理器执行的通知处理器。
///
internal sealed class AlphaDeterministicNotificationHandler : INotificationHandler
{
///
/// 记录当前处理器已执行。
///
/// 通知实例。
/// 取消令牌。
/// 已完成任务。
public ValueTask Handle(DeterministicOrderNotification notification, CancellationToken cancellationToken)
{
DeterministicNotificationHandlerState.InvocationOrder.Add(nameof(AlphaDeterministicNotificationHandler));
return ValueTask.CompletedTask;
}
}