mirror of
https://github.com/GeWuYou/GFramework.git
synced 2026-05-07 00:39:00 +08:00
test(cqrs-tests): 补充 hidden implementation generated invoker 回归
- 新增 hidden implementation request provider runtime 集成回归,验证 registrar 与 dispatcher 会继续消费 generated metadata - 新增 hidden implementation stream provider runtime 集成回归,覆盖可见 handler interface 下的流式 dispatch 路径 - 补充对应测试替身 registry 与隐藏 handler 容器,保持现有 generated invoker 测试风格
This commit is contained in:
parent
eb30388267
commit
5a77e2fb33
@ -57,6 +57,25 @@ internal sealed class CqrsGeneratedRequestInvokerProviderTests
|
|||||||
Is.EqualTo([typeof(GeneratedRequestInvokerProviderRegistry)]));
|
Is.EqualTo([typeof(GeneratedRequestInvokerProviderRegistry)]));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 验证当实现类型隐藏、但 request handler interface 仍可直接表达时,
|
||||||
|
/// registrar 仍会把 generated request invoker provider 注册到容器中。
|
||||||
|
/// </summary>
|
||||||
|
[Test]
|
||||||
|
public void RegisterHandlers_Should_Register_Generated_Request_Invoker_Provider_For_Hidden_Implementation()
|
||||||
|
{
|
||||||
|
var generatedAssembly = CreateHiddenImplementationGeneratedRequestInvokerAssembly();
|
||||||
|
var container = new MicrosoftDiContainer();
|
||||||
|
|
||||||
|
CqrsTestRuntime.RegisterHandlers(container, generatedAssembly.Object);
|
||||||
|
|
||||||
|
var providers = container.GetAll<ICqrsRequestInvokerProvider>();
|
||||||
|
|
||||||
|
Assert.That(
|
||||||
|
providers.Select(static provider => provider.GetType()),
|
||||||
|
Is.EqualTo([typeof(HiddenImplementationGeneratedRequestInvokerProviderRegistry)]));
|
||||||
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// 验证 registrar 激活 generated registry 后,会把 stream invoker provider 注册到容器中。
|
/// 验证 registrar 激活 generated registry 后,会把 stream invoker provider 注册到容器中。
|
||||||
/// </summary>
|
/// </summary>
|
||||||
@ -75,6 +94,25 @@ internal sealed class CqrsGeneratedRequestInvokerProviderTests
|
|||||||
Is.EqualTo([typeof(GeneratedStreamInvokerProviderRegistry)]));
|
Is.EqualTo([typeof(GeneratedStreamInvokerProviderRegistry)]));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 验证当实现类型隐藏、但 stream handler interface 仍可直接表达时,
|
||||||
|
/// registrar 仍会把 generated stream invoker provider 注册到容器中。
|
||||||
|
/// </summary>
|
||||||
|
[Test]
|
||||||
|
public void RegisterHandlers_Should_Register_Generated_Stream_Invoker_Provider_For_Hidden_Implementation()
|
||||||
|
{
|
||||||
|
var generatedAssembly = CreateHiddenImplementationGeneratedStreamInvokerAssembly();
|
||||||
|
var container = new MicrosoftDiContainer();
|
||||||
|
|
||||||
|
CqrsTestRuntime.RegisterHandlers(container, generatedAssembly.Object);
|
||||||
|
|
||||||
|
var providers = container.GetAll<ICqrsStreamInvokerProvider>();
|
||||||
|
|
||||||
|
Assert.That(
|
||||||
|
providers.Select(static provider => provider.GetType()),
|
||||||
|
Is.EqualTo([typeof(HiddenImplementationGeneratedStreamInvokerProviderRegistry)]));
|
||||||
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// 验证 dispatcher 在首次创建 request binding 时,会优先消费 generated request invoker provider。
|
/// 验证 dispatcher 在首次创建 request binding 时,会优先消费 generated request invoker provider。
|
||||||
/// </summary>
|
/// </summary>
|
||||||
@ -92,6 +130,25 @@ internal sealed class CqrsGeneratedRequestInvokerProviderTests
|
|||||||
Assert.That(response, Is.EqualTo("generated:payload"));
|
Assert.That(response, Is.EqualTo("generated:payload"));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 验证当实现类型隐藏、但 request handler interface 仍可直接表达时,
|
||||||
|
/// dispatcher 仍会消费 generated request invoker descriptor。
|
||||||
|
/// </summary>
|
||||||
|
[Test]
|
||||||
|
public async Task SendAsync_Should_Use_Generated_Request_Invoker_For_Hidden_Implementation_When_Provider_Is_Registered()
|
||||||
|
{
|
||||||
|
var generatedAssembly = CreateHiddenImplementationGeneratedRequestInvokerAssembly();
|
||||||
|
var container = new MicrosoftDiContainer();
|
||||||
|
|
||||||
|
CqrsTestRuntime.RegisterHandlers(container, generatedAssembly.Object);
|
||||||
|
container.Freeze();
|
||||||
|
|
||||||
|
var context = new ArchitectureContext(container);
|
||||||
|
var response = await context.SendRequestAsync(
|
||||||
|
new HiddenImplementationRequestInvokerContainer.VisibleRequest("payload"));
|
||||||
|
Assert.That(response, Is.EqualTo("generated-hidden:payload"));
|
||||||
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// 验证 dispatcher 在首次创建 stream binding 时,会优先消费 generated stream invoker provider。
|
/// 验证 dispatcher 在首次创建 stream binding 时,会优先消费 generated stream invoker provider。
|
||||||
/// </summary>
|
/// </summary>
|
||||||
@ -109,6 +166,25 @@ internal sealed class CqrsGeneratedRequestInvokerProviderTests
|
|||||||
Assert.That(results, Is.EqualTo([30, 31]));
|
Assert.That(results, Is.EqualTo([30, 31]));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 验证当实现类型隐藏、但 stream handler interface 仍可直接表达时,
|
||||||
|
/// dispatcher 仍会消费 generated stream invoker descriptor。
|
||||||
|
/// </summary>
|
||||||
|
[Test]
|
||||||
|
public async Task CreateStream_Should_Use_Generated_Stream_Invoker_For_Hidden_Implementation_When_Provider_Is_Registered()
|
||||||
|
{
|
||||||
|
var generatedAssembly = CreateHiddenImplementationGeneratedStreamInvokerAssembly();
|
||||||
|
var container = new MicrosoftDiContainer();
|
||||||
|
|
||||||
|
CqrsTestRuntime.RegisterHandlers(container, generatedAssembly.Object);
|
||||||
|
container.Freeze();
|
||||||
|
|
||||||
|
var context = new ArchitectureContext(container);
|
||||||
|
var results = await DrainAsync(
|
||||||
|
context.CreateStream(new HiddenImplementationStreamInvokerContainer.VisibleStreamRequest(3)));
|
||||||
|
Assert.That(results, Is.EqualTo([300, 301]));
|
||||||
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// 创建带有 generated request invoker registry 元数据的程序集替身。
|
/// 创建带有 generated request invoker registry 元数据的程序集替身。
|
||||||
/// </summary>
|
/// </summary>
|
||||||
@ -139,6 +215,36 @@ internal sealed class CqrsGeneratedRequestInvokerProviderTests
|
|||||||
return generatedAssembly;
|
return generatedAssembly;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 创建带有 hidden implementation request invoker registry 元数据的程序集替身。
|
||||||
|
/// </summary>
|
||||||
|
private static Mock<Assembly> CreateHiddenImplementationGeneratedRequestInvokerAssembly()
|
||||||
|
{
|
||||||
|
var generatedAssembly = new Mock<Assembly>();
|
||||||
|
generatedAssembly
|
||||||
|
.SetupGet(static assembly => assembly.FullName)
|
||||||
|
.Returns("GFramework.Cqrs.Tests.Cqrs.HiddenGeneratedRequestInvokerAssembly, Version=1.0.0.0");
|
||||||
|
generatedAssembly
|
||||||
|
.Setup(static assembly => assembly.GetCustomAttributes(typeof(CqrsHandlerRegistryAttribute), false))
|
||||||
|
.Returns([new CqrsHandlerRegistryAttribute(typeof(HiddenImplementationGeneratedRequestInvokerProviderRegistry))]);
|
||||||
|
return generatedAssembly;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 创建带有 hidden implementation stream invoker registry 元数据的程序集替身。
|
||||||
|
/// </summary>
|
||||||
|
private static Mock<Assembly> CreateHiddenImplementationGeneratedStreamInvokerAssembly()
|
||||||
|
{
|
||||||
|
var generatedAssembly = new Mock<Assembly>();
|
||||||
|
generatedAssembly
|
||||||
|
.SetupGet(static assembly => assembly.FullName)
|
||||||
|
.Returns("GFramework.Cqrs.Tests.Cqrs.HiddenGeneratedStreamInvokerAssembly, Version=1.0.0.0");
|
||||||
|
generatedAssembly
|
||||||
|
.Setup(static assembly => assembly.GetCustomAttributes(typeof(CqrsHandlerRegistryAttribute), false))
|
||||||
|
.Returns([new CqrsHandlerRegistryAttribute(typeof(HiddenImplementationGeneratedStreamInvokerProviderRegistry))]);
|
||||||
|
return generatedAssembly;
|
||||||
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// 清空 registrar 静态缓存。
|
/// 清空 registrar 静态缓存。
|
||||||
/// </summary>
|
/// </summary>
|
||||||
|
|||||||
@ -0,0 +1,93 @@
|
|||||||
|
using System.Reflection;
|
||||||
|
using GFramework.Core.Abstractions.Logging;
|
||||||
|
using GFramework.Core.Ioc;
|
||||||
|
using GFramework.Core.Logging;
|
||||||
|
using GFramework.Cqrs.Abstractions.Cqrs;
|
||||||
|
|
||||||
|
namespace GFramework.Cqrs.Tests.Cqrs;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 模拟 generated registry 在实现类型隐藏、但 request handler interface 可见时,仍提供 request invoker 元数据。
|
||||||
|
/// </summary>
|
||||||
|
internal sealed class HiddenImplementationGeneratedRequestInvokerProviderRegistry :
|
||||||
|
ICqrsHandlerRegistry,
|
||||||
|
ICqrsRequestInvokerProvider,
|
||||||
|
IEnumeratesCqrsRequestInvokerDescriptors
|
||||||
|
{
|
||||||
|
private static readonly Type HandlerContractType =
|
||||||
|
typeof(IRequestHandler<HiddenImplementationRequestInvokerContainer.VisibleRequest, string>);
|
||||||
|
|
||||||
|
private static readonly CqrsRequestInvokerDescriptor Descriptor = new(
|
||||||
|
HandlerContractType,
|
||||||
|
typeof(HiddenImplementationGeneratedRequestInvokerProviderRegistry).GetMethod(
|
||||||
|
nameof(InvokeGenerated),
|
||||||
|
BindingFlags.NonPublic | BindingFlags.Static)!);
|
||||||
|
|
||||||
|
private static readonly CqrsRequestInvokerDescriptorEntry DescriptorEntry = new(
|
||||||
|
typeof(HiddenImplementationRequestInvokerContainer.VisibleRequest),
|
||||||
|
typeof(string),
|
||||||
|
Descriptor);
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 通过可见 handler interface 把隐藏实现类型注册进目标服务集合,模拟 generator 的 reflected-implementation 路径。
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="services">承载处理器映射的服务集合。</param>
|
||||||
|
/// <param name="logger">用于记录注册诊断的日志器。</param>
|
||||||
|
public void Register(IServiceCollection services, ILogger logger)
|
||||||
|
{
|
||||||
|
ArgumentNullException.ThrowIfNull(services);
|
||||||
|
ArgumentNullException.ThrowIfNull(logger);
|
||||||
|
|
||||||
|
var implementationType = HiddenImplementationRequestInvokerContainer.HiddenHandlerType;
|
||||||
|
services.AddTransient(HandlerContractType, implementationType);
|
||||||
|
logger.Debug(
|
||||||
|
$"Registered CQRS handler {implementationType.FullName} as {HandlerContractType.FullName}.");
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 尝试返回指定 request/response 类型对对应的 generated invoker 描述符。
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="requestType">请求运行时类型。</param>
|
||||||
|
/// <param name="responseType">响应运行时类型。</param>
|
||||||
|
/// <param name="descriptor">命中时返回的描述符。</param>
|
||||||
|
/// <returns>若类型对匹配当前测试请求则返回 <see langword="true" />。</returns>
|
||||||
|
public bool TryGetDescriptor(
|
||||||
|
Type requestType,
|
||||||
|
Type responseType,
|
||||||
|
out CqrsRequestInvokerDescriptor? descriptor)
|
||||||
|
{
|
||||||
|
if (requestType == typeof(HiddenImplementationRequestInvokerContainer.VisibleRequest)
|
||||||
|
&& responseType == typeof(string))
|
||||||
|
{
|
||||||
|
descriptor = Descriptor;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
descriptor = null;
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 返回当前 registry 暴露的全部 generated request invoker 描述符。
|
||||||
|
/// </summary>
|
||||||
|
/// <returns>单条 hidden implementation request invoker 描述符条目。</returns>
|
||||||
|
public IReadOnlyList<CqrsRequestInvokerDescriptorEntry> GetDescriptors()
|
||||||
|
{
|
||||||
|
return [DescriptorEntry];
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 模拟 generated request invoker 在隐藏实现类型场景下直接执行后的返回值。
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="handler">当前请求处理器实例。</param>
|
||||||
|
/// <param name="request">当前测试请求。</param>
|
||||||
|
/// <param name="cancellationToken">取消令牌。</param>
|
||||||
|
/// <returns>带有 hidden generated 前缀的结果,便于断言 dispatcher 命中了 generated provider 路径。</returns>
|
||||||
|
private static ValueTask<string> InvokeGenerated(object handler, object request, CancellationToken cancellationToken)
|
||||||
|
{
|
||||||
|
_ = handler as IRequestHandler<HiddenImplementationRequestInvokerContainer.VisibleRequest, string>
|
||||||
|
?? throw new InvalidOperationException("Generated invoker received an incompatible hidden handler instance.");
|
||||||
|
var typedRequest = (HiddenImplementationRequestInvokerContainer.VisibleRequest)request;
|
||||||
|
return ValueTask.FromResult($"generated-hidden:{typedRequest.Value}");
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -0,0 +1,105 @@
|
|||||||
|
using System.Reflection;
|
||||||
|
using GFramework.Core.Abstractions.Logging;
|
||||||
|
using GFramework.Core.Ioc;
|
||||||
|
using GFramework.Cqrs.Abstractions.Cqrs;
|
||||||
|
|
||||||
|
namespace GFramework.Cqrs.Tests.Cqrs;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 模拟 generated registry 在实现类型隐藏、但 stream handler interface 可见时,仍提供 stream invoker 元数据。
|
||||||
|
/// </summary>
|
||||||
|
internal sealed class HiddenImplementationGeneratedStreamInvokerProviderRegistry :
|
||||||
|
ICqrsHandlerRegistry,
|
||||||
|
ICqrsStreamInvokerProvider,
|
||||||
|
IEnumeratesCqrsStreamInvokerDescriptors
|
||||||
|
{
|
||||||
|
private static readonly Type HandlerContractType =
|
||||||
|
typeof(IStreamRequestHandler<HiddenImplementationStreamInvokerContainer.VisibleStreamRequest, int>);
|
||||||
|
|
||||||
|
private static readonly CqrsStreamInvokerDescriptor Descriptor = new(
|
||||||
|
HandlerContractType,
|
||||||
|
typeof(HiddenImplementationGeneratedStreamInvokerProviderRegistry).GetMethod(
|
||||||
|
nameof(InvokeGenerated),
|
||||||
|
BindingFlags.NonPublic | BindingFlags.Static)!);
|
||||||
|
|
||||||
|
private static readonly CqrsStreamInvokerDescriptorEntry DescriptorEntry = new(
|
||||||
|
typeof(HiddenImplementationStreamInvokerContainer.VisibleStreamRequest),
|
||||||
|
typeof(int),
|
||||||
|
Descriptor);
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 通过可见 stream handler interface 把隐藏实现类型注册进目标服务集合,模拟 generator 的 reflected-implementation 路径。
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="services">承载处理器映射的服务集合。</param>
|
||||||
|
/// <param name="logger">用于记录注册诊断的日志器。</param>
|
||||||
|
public void Register(IServiceCollection services, ILogger logger)
|
||||||
|
{
|
||||||
|
ArgumentNullException.ThrowIfNull(services);
|
||||||
|
ArgumentNullException.ThrowIfNull(logger);
|
||||||
|
|
||||||
|
var implementationType = HiddenImplementationStreamInvokerContainer.HiddenHandlerType;
|
||||||
|
services.AddTransient(HandlerContractType, implementationType);
|
||||||
|
logger.Debug(
|
||||||
|
$"Registered CQRS handler {implementationType.FullName} as {HandlerContractType.FullName}.");
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 尝试返回指定 stream request/response 类型对对应的 generated invoker 描述符。
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="requestType">流式请求运行时类型。</param>
|
||||||
|
/// <param name="responseType">流式响应元素类型。</param>
|
||||||
|
/// <param name="descriptor">命中时返回的描述符。</param>
|
||||||
|
/// <returns>若类型对匹配当前测试流式请求则返回 <see langword="true" />。</returns>
|
||||||
|
public bool TryGetDescriptor(
|
||||||
|
Type requestType,
|
||||||
|
Type responseType,
|
||||||
|
out CqrsStreamInvokerDescriptor? descriptor)
|
||||||
|
{
|
||||||
|
if (requestType == typeof(HiddenImplementationStreamInvokerContainer.VisibleStreamRequest)
|
||||||
|
&& responseType == typeof(int))
|
||||||
|
{
|
||||||
|
descriptor = Descriptor;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
descriptor = null;
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 返回当前 registry 暴露的全部 generated stream invoker 描述符。
|
||||||
|
/// </summary>
|
||||||
|
/// <returns>单条 hidden implementation stream invoker 描述符条目。</returns>
|
||||||
|
public IReadOnlyList<CqrsStreamInvokerDescriptorEntry> GetDescriptors()
|
||||||
|
{
|
||||||
|
return [DescriptorEntry];
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 模拟 generated stream invoker 在隐藏实现类型场景下直接执行后的返回值。
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="handler">当前流式请求处理器实例。</param>
|
||||||
|
/// <param name="request">当前测试流式请求。</param>
|
||||||
|
/// <param name="cancellationToken">取消令牌。</param>
|
||||||
|
/// <returns>带有 hidden generated 语义的异步流,便于断言 dispatcher 命中了 generated provider 路径。</returns>
|
||||||
|
private static object InvokeGenerated(object handler, object request, CancellationToken cancellationToken)
|
||||||
|
{
|
||||||
|
_ = handler as IStreamRequestHandler<HiddenImplementationStreamInvokerContainer.VisibleStreamRequest, int>
|
||||||
|
?? throw new InvalidOperationException("Generated stream invoker received an incompatible hidden handler instance.");
|
||||||
|
var typedRequest = (HiddenImplementationStreamInvokerContainer.VisibleStreamRequest)request;
|
||||||
|
return StreamResultsAsync(typedRequest.Start, cancellationToken);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 构造供测试断言使用的固定异步流结果。
|
||||||
|
/// </summary>
|
||||||
|
private static async IAsyncEnumerable<int> StreamResultsAsync(
|
||||||
|
int start,
|
||||||
|
[EnumeratorCancellation] CancellationToken cancellationToken)
|
||||||
|
{
|
||||||
|
yield return start * 100;
|
||||||
|
await Task.Yield();
|
||||||
|
cancellationToken.ThrowIfCancellationRequested();
|
||||||
|
yield return start * 100 + 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -0,0 +1,38 @@
|
|||||||
|
using GFramework.Cqrs.Abstractions.Cqrs;
|
||||||
|
|
||||||
|
namespace GFramework.Cqrs.Tests.Cqrs;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 为 hidden implementation request invoker 回归提供“可见请求 + 隐藏实现类型”的测试替身容器。
|
||||||
|
/// </summary>
|
||||||
|
internal static class HiddenImplementationRequestInvokerContainer
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// 用于验证 generated request invoker metadata 在隐藏实现类型场景下仍可被 dispatcher 消费的请求。
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="Value">用于断言 generated 返回值的请求负载。</param>
|
||||||
|
internal sealed record VisibleRequest(string Value) : IRequest<string>;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 供 registrar 通过可见 handler interface 注册、但自身保持隐藏的 request handler 实现。
|
||||||
|
/// </summary>
|
||||||
|
private sealed class HiddenHandler : IRequestHandler<VisibleRequest, string>
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// 返回 runtime 路径专用结果,便于与 generated invoker 路径区分。
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="request">当前测试请求。</param>
|
||||||
|
/// <param name="cancellationToken">取消令牌。</param>
|
||||||
|
/// <returns>runtime handler 生成的响应字符串。</returns>
|
||||||
|
public ValueTask<string> Handle(VisibleRequest request, CancellationToken cancellationToken)
|
||||||
|
{
|
||||||
|
ArgumentNullException.ThrowIfNull(request);
|
||||||
|
return ValueTask.FromResult($"runtime-hidden:{request.Value}");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 返回当前隐藏 request handler 实现类型,供 generated registry 以反射注册语义模拟 hidden implementation 场景。
|
||||||
|
/// </summary>
|
||||||
|
internal static Type HiddenHandlerType => typeof(HiddenHandler);
|
||||||
|
}
|
||||||
@ -0,0 +1,51 @@
|
|||||||
|
using GFramework.Cqrs.Abstractions.Cqrs;
|
||||||
|
|
||||||
|
namespace GFramework.Cqrs.Tests.Cqrs;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 为 hidden implementation stream invoker 回归提供“可见请求 + 隐藏实现类型”的测试替身容器。
|
||||||
|
/// </summary>
|
||||||
|
internal static class HiddenImplementationStreamInvokerContainer
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// 用于验证 generated stream invoker metadata 在隐藏实现类型场景下仍可被 dispatcher 消费的流式请求。
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="Start">用于构造 generated stream 输出的起始值。</param>
|
||||||
|
internal sealed record VisibleStreamRequest(int Start) : IStreamRequest<int>;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 供 registrar 通过可见 stream handler interface 注册、但自身保持隐藏的流式 handler 实现。
|
||||||
|
/// </summary>
|
||||||
|
private sealed class HiddenHandler : IStreamRequestHandler<VisibleStreamRequest, int>
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// 返回 runtime 路径专用异步流,便于与 generated invoker 路径区分。
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="request">当前测试流式请求。</param>
|
||||||
|
/// <param name="cancellationToken">取消令牌。</param>
|
||||||
|
/// <returns>runtime handler 生成的异步流结果。</returns>
|
||||||
|
public IAsyncEnumerable<int> Handle(VisibleStreamRequest request, CancellationToken cancellationToken)
|
||||||
|
{
|
||||||
|
ArgumentNullException.ThrowIfNull(request);
|
||||||
|
return StreamResultsAsync(request.Start, cancellationToken);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 生成用于区分 runtime 路径的固定异步流结果。
|
||||||
|
/// </summary>
|
||||||
|
private static async IAsyncEnumerable<int> StreamResultsAsync(
|
||||||
|
int start,
|
||||||
|
[EnumeratorCancellation] CancellationToken cancellationToken)
|
||||||
|
{
|
||||||
|
yield return start;
|
||||||
|
await Task.Yield();
|
||||||
|
cancellationToken.ThrowIfCancellationRequested();
|
||||||
|
yield return start + 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 返回当前隐藏 stream handler 实现类型,供 generated registry 以反射注册语义模拟 hidden implementation 场景。
|
||||||
|
/// </summary>
|
||||||
|
internal static Type HiddenHandlerType => typeof(HiddenHandler);
|
||||||
|
}
|
||||||
Loading…
x
Reference in New Issue
Block a user