// Copyright (c) 2025-2026 GeWuYou
// SPDX-License-Identifier: Apache-2.0
using GFramework.Core.Abstractions.Architectures;
using GFramework.Core.Abstractions.Logging;
using GFramework.Core.Abstractions.Utility;
using GFramework.Core.Architectures;
using GFramework.Core.Logging;
using GFramework.Cqrs.Abstractions.Cqrs;
using Microsoft.Extensions.DependencyInjection;
namespace GFramework.Core.Tests.Architectures;
///
/// 验证 Architecture 通过 ArchitectureModules 暴露出的模块安装与 CQRS 行为注册能力。
/// 这些测试覆盖模块安装回调和请求管道行为接入,确保模块管理器仍然保持可观察行为不变。
///
[NonParallelizable]
[TestFixture]
public class ArchitectureModulesBehaviorTests
{
///
/// 初始化日志工厂和全局上下文状态。
///
[SetUp]
public void SetUp()
{
LoggerFactoryResolver.Provider = new ConsoleLoggerFactoryProvider();
GameContext.Clear();
TrackingPipelineBehavior.InvocationCount = 0;
TrackingStreamPipelineBehavior.InvocationCount = 0;
}
///
/// 清理测试过程中写入的全局上下文状态。
///
[TearDown]
public void TearDown()
{
GameContext.Clear();
TrackingPipelineBehavior.InvocationCount = 0;
TrackingStreamPipelineBehavior.InvocationCount = 0;
LegacyBridgePipelineTracker.Reset();
}
///
/// 验证安装模块时会把当前架构实例传给模块,并允许模块在安装阶段注册组件。
///
[Test]
public async Task InstallModule_Should_Invoke_Module_Install_With_Current_Architecture()
{
var module = new TrackingArchitectureModule();
var architecture = new ModuleTestArchitecture(target => target.InstallModule(module));
await architecture.InitializeAsync();
try
{
Assert.Multiple(() =>
{
Assert.That(module.InstalledArchitecture, Is.SameAs(architecture));
Assert.That(module.InstallCallCount, Is.EqualTo(1));
Assert.That(architecture.Context.GetUtility(), Is.Not.Null);
});
}
finally
{
await architecture.DestroyAsync();
}
}
///
/// 验证注册的 CQRS 行为会参与请求管道执行。
///
[Test]
public async Task RegisterCqrsPipelineBehavior_Should_Apply_Pipeline_Behavior_To_Request()
{
var architecture = new ModuleTestArchitecture(target =>
target.RegisterCqrsPipelineBehavior>());
await architecture.InitializeAsync();
try
{
var response = await architecture.Context.SendRequestAsync(new ModuleBehaviorRequest());
Assert.Multiple(() =>
{
Assert.That(response, Is.EqualTo("handled"));
Assert.That(TrackingPipelineBehavior.InvocationCount, Is.EqualTo(1));
});
}
finally
{
await architecture.DestroyAsync();
}
}
///
/// 验证注册的 CQRS stream 行为会参与建流处理流程。
///
[Test]
public async Task RegisterCqrsStreamPipelineBehavior_Should_Apply_Pipeline_Behavior_To_Stream_Request()
{
var architecture = new ModuleTestArchitecture(target =>
target.RegisterCqrsStreamPipelineBehavior>());
await architecture.InitializeAsync();
try
{
var response = await DrainAsync(architecture.Context.CreateStream(new ModuleStreamBehaviorRequest()));
Assert.Multiple(() =>
{
Assert.That(response, Is.EqualTo([7]));
Assert.That(
TrackingStreamPipelineBehavior.InvocationCount,
Is.EqualTo(1));
});
}
finally
{
await architecture.DestroyAsync();
}
}
///
/// 验证默认架构初始化路径会自动扫描 Core 程序集里的 legacy bridge handler,
/// 使旧 SendCommand / SendQuery 入口也能进入统一 CQRS pipeline。
///
[Test]
public async Task InitializeAsync_Should_AutoRegister_LegacyBridgeHandlers_For_Default_Core_Assemblies()
{
LegacyBridgePipelineTracker.Reset();
var architecture = new LegacyBridgeArchitecture();
await architecture.InitializeAsync();
try
{
var query = new LegacyArchitectureBridgeQuery();
var command = new LegacyArchitectureBridgeCommand();
var queryResult = architecture.Context.SendQuery(query);
architecture.Context.SendCommand(command);
Assert.Multiple(() =>
{
Assert.That(queryResult, Is.EqualTo(24));
Assert.That(query.ObservedContext, Is.SameAs(architecture.Context));
Assert.That(command.Executed, Is.True);
Assert.That(command.ObservedContext, Is.SameAs(architecture.Context));
Assert.That(LegacyBridgePipelineTracker.InvocationCount, Is.EqualTo(2));
});
}
finally
{
await architecture.DestroyAsync();
}
}
///
/// 用于测试模块行为的最小架构实现。
///
private sealed class ModuleTestArchitecture(Action registrationAction) : Architecture
{
///
/// 在初始化阶段执行测试注入的模块注册逻辑。
///
protected override void OnInitialize()
{
registrationAction(this);
}
}
///
/// 通过公开初始化入口注册测试 pipeline behavior 的最小架构,
/// 用于验证默认 Core 程序集扫描是否会自动接入 legacy bridge handler。
///
private sealed class LegacyBridgeArchitecture : Architecture
{
///
/// 在容器钩子阶段注册 open-generic pipeline behavior,
/// 以便 bridge request 走真实的架构初始化与 handler 自动扫描链路。
///
public override Action? Configurator => services =>
services.AddSingleton(typeof(IPipelineBehavior<,>), typeof(LegacyBridgeTrackingPipelineBehavior<,>));
///
/// 保持空初始化,让测试只聚焦默认 CQRS 接线与 legacy bridge handler 自动发现。
///
protected override void OnInitialize()
{
}
}
///
/// 记录模块安装调用情况的测试模块。
///
private sealed class TrackingArchitectureModule : IArchitectureModule
{
///
/// 获取模块安装调用次数。
///
public int InstallCallCount { get; private set; }
///
/// 获取最近一次接收到的架构实例。
///
public IArchitecture? InstalledArchitecture { get; private set; }
///
/// 记录安装调用,并在安装阶段注册一个工具验证调用链可用。
///
/// 目标架构实例。
public void Install(IArchitecture architecture)
{
InstallCallCount++;
InstalledArchitecture = architecture;
architecture.RegisterUtility(new InstalledByModuleUtility());
}
}
///
/// 由测试模块安装时注册的简单工具。
///
private sealed class InstalledByModuleUtility : IUtility
{
}
///
/// 物化异步流为只读列表,便于断言 stream pipeline 行为的最终可观察结果。
///
/// 流元素类型。
/// 要物化的异步流。
/// 按枚举顺序收集的元素列表。
private static async Task> DrainAsync(IAsyncEnumerable stream)
{
var results = new List();
await foreach (var item in stream.ConfigureAwait(false))
{
results.Add(item);
}
return results;
}
}