mirror of
https://github.com/GeWuYou/GFramework.git
synced 2026-05-07 17:21:16 +08:00
test(cqrs): 补充 provider gate 合同回归
- 新增 request 与 stream gate 回归,锁定 runtime 合同不完整时不会发射 invoker provider 元数据 - 更新 CQRS 重写恢复点到 RP-072,并记录定向验证与 helper 收敛
This commit is contained in:
parent
dc21188c79
commit
502f65239c
@ -2945,6 +2945,56 @@ public class CqrsHandlerRegistryGeneratorTests
|
||||
});
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 验证当 runtime 缺少 <c>ICqrsRequestInvokerProvider</c> 时,
|
||||
/// 生成器会整体跳过 request invoker provider 元数据发射,而不是输出半套 descriptor 成员。
|
||||
/// </summary>
|
||||
[Test]
|
||||
public void Does_Not_Emit_Request_Invoker_Provider_Metadata_When_Runtime_Lacks_Request_Provider_Interface()
|
||||
{
|
||||
var generatedSource = RunGenerator(RemoveBlock(
|
||||
RequestInvokerProviderSource,
|
||||
"public interface ICqrsRequestInvokerProvider",
|
||||
"public interface IEnumeratesCqrsRequestInvokerDescriptors"));
|
||||
|
||||
Assert.Multiple(() =>
|
||||
{
|
||||
Assert.That(
|
||||
generatedSource,
|
||||
Does.Contain(
|
||||
"internal sealed class __GFrameworkGeneratedCqrsHandlerRegistry : global::GFramework.Cqrs.ICqrsHandlerRegistry"));
|
||||
Assert.That(generatedSource, Does.Not.Contain("ICqrsRequestInvokerProvider"));
|
||||
Assert.That(generatedSource, Does.Not.Contain("IEnumeratesCqrsRequestInvokerDescriptors"));
|
||||
Assert.That(generatedSource, Does.Not.Contain("CqrsRequestInvokerDescriptorEntry("));
|
||||
Assert.That(generatedSource, Does.Not.Contain("InvokeRequestHandler0"));
|
||||
});
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 验证当 runtime 缺少 <c>IEnumeratesCqrsRequestInvokerDescriptors</c> 时,
|
||||
/// 生成器不会只发射 request provider 的部分成员,而是整体保持不生成 provider 元数据。
|
||||
/// </summary>
|
||||
[Test]
|
||||
public void Does_Not_Emit_Request_Invoker_Provider_Metadata_When_Runtime_Lacks_Request_Descriptor_Enumerator()
|
||||
{
|
||||
var generatedSource = RunGenerator(RemoveBlock(
|
||||
RequestInvokerProviderSource,
|
||||
"public interface IEnumeratesCqrsRequestInvokerDescriptors",
|
||||
"public sealed class CqrsRequestInvokerDescriptor"));
|
||||
|
||||
Assert.Multiple(() =>
|
||||
{
|
||||
Assert.That(
|
||||
generatedSource,
|
||||
Does.Contain(
|
||||
"internal sealed class __GFrameworkGeneratedCqrsHandlerRegistry : global::GFramework.Cqrs.ICqrsHandlerRegistry"));
|
||||
Assert.That(generatedSource, Does.Not.Contain("ICqrsRequestInvokerProvider"));
|
||||
Assert.That(generatedSource, Does.Not.Contain("IEnumeratesCqrsRequestInvokerDescriptors"));
|
||||
Assert.That(generatedSource, Does.Not.Contain("CqrsRequestInvokerDescriptorEntry("));
|
||||
Assert.That(generatedSource, Does.Not.Contain("InvokeRequestHandler0"));
|
||||
});
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 验证当 request handler 仍需走 precise reflected 注册时,
|
||||
/// 生成器即使检测到 request invoker provider runtime 合同,也不会错误发射无法稳定表达隐藏请求/响应类型的 provider 元数据。
|
||||
@ -3056,6 +3106,56 @@ public class CqrsHandlerRegistryGeneratorTests
|
||||
});
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 验证当 runtime 缺少 <c>ICqrsStreamInvokerProvider</c> 时,
|
||||
/// 生成器会整体跳过 stream invoker provider 元数据发射,而不是保留孤立的 descriptor 成员。
|
||||
/// </summary>
|
||||
[Test]
|
||||
public void Does_Not_Emit_Stream_Invoker_Provider_Metadata_When_Runtime_Lacks_Stream_Provider_Interface()
|
||||
{
|
||||
var generatedSource = RunGenerator(RemoveBlock(
|
||||
StreamInvokerProviderSource,
|
||||
"public interface ICqrsStreamInvokerProvider",
|
||||
"public interface IEnumeratesCqrsStreamInvokerDescriptors"));
|
||||
|
||||
Assert.Multiple(() =>
|
||||
{
|
||||
Assert.That(
|
||||
generatedSource,
|
||||
Does.Contain(
|
||||
"internal sealed class __GFrameworkGeneratedCqrsHandlerRegistry : global::GFramework.Cqrs.ICqrsHandlerRegistry"));
|
||||
Assert.That(generatedSource, Does.Not.Contain("ICqrsStreamInvokerProvider"));
|
||||
Assert.That(generatedSource, Does.Not.Contain("IEnumeratesCqrsStreamInvokerDescriptors"));
|
||||
Assert.That(generatedSource, Does.Not.Contain("CqrsStreamInvokerDescriptorEntry("));
|
||||
Assert.That(generatedSource, Does.Not.Contain("InvokeStreamHandler0"));
|
||||
});
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 验证当 runtime 缺少 <c>IEnumeratesCqrsStreamInvokerDescriptors</c> 时,
|
||||
/// 生成器不会只发射 stream provider 的局部成员,而是整体保持不生成 provider 元数据。
|
||||
/// </summary>
|
||||
[Test]
|
||||
public void Does_Not_Emit_Stream_Invoker_Provider_Metadata_When_Runtime_Lacks_Stream_Descriptor_Enumerator()
|
||||
{
|
||||
var generatedSource = RunGenerator(RemoveBlock(
|
||||
StreamInvokerProviderSource,
|
||||
"public interface IEnumeratesCqrsStreamInvokerDescriptors",
|
||||
"public sealed class CqrsStreamInvokerDescriptor"));
|
||||
|
||||
Assert.Multiple(() =>
|
||||
{
|
||||
Assert.That(
|
||||
generatedSource,
|
||||
Does.Contain(
|
||||
"internal sealed class __GFrameworkGeneratedCqrsHandlerRegistry : global::GFramework.Cqrs.ICqrsHandlerRegistry"));
|
||||
Assert.That(generatedSource, Does.Not.Contain("ICqrsStreamInvokerProvider"));
|
||||
Assert.That(generatedSource, Does.Not.Contain("IEnumeratesCqrsStreamInvokerDescriptors"));
|
||||
Assert.That(generatedSource, Does.Not.Contain("CqrsStreamInvokerDescriptorEntry("));
|
||||
Assert.That(generatedSource, Does.Not.Contain("InvokeStreamHandler0"));
|
||||
});
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 验证当 stream handler 仍需走 precise reflected 注册时,
|
||||
/// 生成器即使检测到 stream invoker provider runtime 合同,也不会错误发射无法稳定表达隐藏请求/响应类型的 provider 元数据。
|
||||
@ -3129,6 +3229,35 @@ public class CqrsHandlerRegistryGeneratorTests
|
||||
return execution.GeneratedSources[0].content;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 从测试输入源码中移除两个稳定标记之间的整段合同定义,
|
||||
/// 避免回归用例依赖三引号字符串中的精确缩进。
|
||||
/// </summary>
|
||||
/// <param name="source">原始测试源码。</param>
|
||||
/// <param name="startMarker">待移除代码块的起始标记。</param>
|
||||
/// <param name="endMarker">待移除代码块之后紧邻的下一个稳定标记。</param>
|
||||
/// <returns>移除指定代码块后的新源码。</returns>
|
||||
private static string RemoveBlock(string source, string startMarker, string endMarker)
|
||||
{
|
||||
ArgumentNullException.ThrowIfNull(source);
|
||||
ArgumentNullException.ThrowIfNull(startMarker);
|
||||
ArgumentNullException.ThrowIfNull(endMarker);
|
||||
|
||||
var startIndex = source.IndexOf(startMarker, StringComparison.Ordinal);
|
||||
if (startIndex < 0)
|
||||
{
|
||||
throw new InvalidOperationException("The requested start marker was not found in the generator test input.");
|
||||
}
|
||||
|
||||
var endIndex = source.IndexOf(endMarker, startIndex, StringComparison.Ordinal);
|
||||
if (endIndex < 0)
|
||||
{
|
||||
throw new InvalidOperationException("The requested end marker was not found in the generator test input.");
|
||||
}
|
||||
|
||||
return source.Remove(startIndex, endIndex - startIndex);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 统计生成源码中某个固定片段的出现次数,用于锁定程序集级 fallback 特性的发射个数。
|
||||
/// </summary>
|
||||
|
||||
@ -7,7 +7,7 @@ CQRS 迁移与收敛。
|
||||
|
||||
## 当前恢复点
|
||||
|
||||
- 恢复点编号:`CQRS-REWRITE-RP-071`
|
||||
- 恢复点编号:`CQRS-REWRITE-RP-072`
|
||||
- 当前阶段:`Phase 8`
|
||||
- 当前焦点:
|
||||
- 已完成一轮 `CQRS vs Mediator` 只读评估归档,结论已沉淀到 `archive/todos/cqrs-vs-mediator-assessment-rp063.md`
|
||||
@ -71,6 +71,9 @@ CQRS 迁移与收敛。
|
||||
- 已完成一轮 precise reflected invoker provider 合同边界回归:
|
||||
- `GFramework.SourceGenerators.Tests/Cqrs/CqrsHandlerRegistryGeneratorTests.cs` 现新增 request / stream 两条回归,明确当 handler 仍需走 `PreciseReflectedRegistrationSpec` 时,generator 即使检测到 invoker provider runtime 合同,也不会错误发射 descriptor、枚举接口或静态 invoker 桥接
|
||||
- 本轮接受了一条只读 subagent 的“继续评估 precise reflected + provider 发射”候选思路,但主线程复核后确认该候选并不存在可安全放宽的 `typeof(request/response)` 子集,因此收敛为“锁定当前排除边界”的测试批次,而不是修改生产 generator 逻辑
|
||||
- 已完成一轮 invoker provider gate 合同回归:
|
||||
- `GFramework.SourceGenerators.Tests/Cqrs/CqrsHandlerRegistryGeneratorTests.cs` 现新增四条回归,分别锁定 request / stream 在缺少 `ICqrsRequestInvokerProvider`、`IEnumeratesCqrsRequestInvokerDescriptors`、`ICqrsStreamInvokerProvider` 或 `IEnumeratesCqrsStreamInvokerDescriptors` 时,generator 都会整体跳过对应 provider 元数据发射
|
||||
- 本轮最初采用固定源码片段替换来裁剪测试输入,但因三引号字符串缩进差异导致 helper 过脆;当前已收敛为按稳定起止标记移除源码块的 `RemoveBlock(...)` helper,避免 gate 回归依赖精确空格对齐
|
||||
- 当前相对 `origin/main` 的累计 branch diff 为 `24 files / 1754 changed lines`,仍低于本轮 `$gframework-batch-boot 50` 的主要 stop condition,可继续推进下一批低风险切片
|
||||
- 已将 mixed fallback 场景进一步收敛:当 runtime 允许同一程序集声明多个 `CqrsReflectionFallbackAttribute` 实例时,generator 现会把可直接引用的 fallback handlers 与仅能按名称恢复的 fallback handlers 拆分发射
|
||||
- `CqrsReflectionFallbackAttribute` 现允许多实例,以承载 `Type[]` 与字符串 fallback 元数据的组合输出
|
||||
@ -288,6 +291,12 @@ CQRS 迁移与收敛。
|
||||
- `dotnet test GFramework.SourceGenerators.Tests/GFramework.SourceGenerators.Tests.csproj -c Release --filter "FullyQualifiedName~CqrsHandlerRegistryGeneratorTests.Does_Not_Emit_Request_Invoker_Provider_Metadata_For_Precise_Reflected_Request_Registrations|FullyQualifiedName~CqrsHandlerRegistryGeneratorTests.Does_Not_Emit_Stream_Invoker_Provider_Metadata_For_Precise_Reflected_Stream_Registrations|FullyQualifiedName~CqrsHandlerRegistryGeneratorTests.Emits_Request_Invoker_Provider_Metadata_For_Hidden_Implementation_With_Visible_Handler_Interface|FullyQualifiedName~CqrsHandlerRegistryGeneratorTests.Emits_Stream_Invoker_Provider_Metadata_For_Hidden_Implementation_With_Visible_Handler_Interface"`
|
||||
- 结果:通过
|
||||
- 备注:`4/4` passed;串行确认 visible-interface hidden-implementation 仍发射 provider 元数据,而 precise reflected 注册继续保持“不发射 provider descriptor”的当前合同
|
||||
- `dotnet build GFramework.SourceGenerators.Tests/GFramework.SourceGenerators.Tests.csproj -c Release`
|
||||
- 结果:通过
|
||||
- 备注:并行执行 build/test 时出现 `MSB3026` 输出文件竞争噪音;无真实编译错误,后续以串行 test 结果作为本轮 authoritative 行为验证
|
||||
- `dotnet test GFramework.SourceGenerators.Tests/GFramework.SourceGenerators.Tests.csproj -c Release --filter "FullyQualifiedName~CqrsHandlerRegistryGeneratorTests.Does_Not_Emit_Request_Invoker_Provider_Metadata_When_Runtime_Lacks_Request_Provider_Interface|FullyQualifiedName~CqrsHandlerRegistryGeneratorTests.Does_Not_Emit_Request_Invoker_Provider_Metadata_When_Runtime_Lacks_Request_Descriptor_Enumerator|FullyQualifiedName~CqrsHandlerRegistryGeneratorTests.Does_Not_Emit_Stream_Invoker_Provider_Metadata_When_Runtime_Lacks_Stream_Provider_Interface|FullyQualifiedName~CqrsHandlerRegistryGeneratorTests.Does_Not_Emit_Stream_Invoker_Provider_Metadata_When_Runtime_Lacks_Stream_Descriptor_Enumerator|FullyQualifiedName~CqrsHandlerRegistryGeneratorTests.Emits_Request_Invoker_Provider_Metadata_When_Runtime_Contract_Is_Available|FullyQualifiedName~CqrsHandlerRegistryGeneratorTests.Emits_Stream_Invoker_Provider_Metadata_When_Runtime_Contract_Is_Available"`
|
||||
- 结果:通过
|
||||
- 备注:`6/6` passed;锁定 request / stream provider gate 依赖“provider 接口 + descriptor 枚举接口”同时存在,且原有 happy-path 发射仍保持通过
|
||||
- `dotnet build GFramework.Core/GFramework.Core.csproj -c Release`
|
||||
- 结果:通过
|
||||
- 备注:`0 warning / 0 error`;确认 `CqrsRuntimeModule` 接线变更未引入 `GFramework.Core` 模块构建问题
|
||||
@ -321,6 +330,6 @@ CQRS 迁移与收敛。
|
||||
|
||||
## 下一步
|
||||
|
||||
1. 在保持 branch diff 明显低于 `50 files` 的前提下,继续挑选下一批低风险 `dispatch/invoker` 收敛切片,并优先考虑 request / stream provider 的诊断、入口或 runtime / generator 合同测试补强
|
||||
1. 在保持 branch diff 明显低于 `50 files` 的前提下,继续挑选下一批低风险 `dispatch/invoker` 收敛切片,并优先考虑 request / stream provider 的 runtime 失败边界或 generator gate 合同补强
|
||||
2. 基于已落地的 notification publisher seam,评估是否需要第二阶段公开配置面、并行 publisher 或 telemetry decorator
|
||||
3. 单独规划旧 `Command` / `Query` API 的收口顺序;`LegacyICqrsRuntime` compatibility slice 已收口到显式 helper 与专门测试,可暂时移出最高优先级
|
||||
|
||||
@ -2,6 +2,29 @@
|
||||
|
||||
## 2026-04-30
|
||||
|
||||
### 阶段:invoker provider gate 合同回归(CQRS-REWRITE-RP-072)
|
||||
|
||||
- 在 `RP-071` 提交后继续按 `gframework-batch-boot 50` 执行;当前 branch diff 相对 `origin/main` 仍为 `24 files`,未接近主要 stop condition,因此继续追加一轮 test-only generator 合同回归
|
||||
- 本轮接受一条只读 subagent 建议,把下一批进一步收敛为“runtime 合同不完整时不发射 provider 元数据”的单文件测试波次
|
||||
- 主线程已完成:
|
||||
- `GFramework.SourceGenerators.Tests/Cqrs/CqrsHandlerRegistryGeneratorTests.cs` 新增四条 gate 回归,分别锁定 request / stream 在缺少 provider 接口或缺少 descriptor 枚举接口时,都会整体跳过元数据发射
|
||||
- 初版实现曾使用整段源码片段替换来删减测试输入,但因三引号字符串缩进差异导致 helper 匹配失败;随后改为按稳定起止标记移除源码块的 `RemoveBlock(...)` helper,使测试意图与输入格式解耦
|
||||
- 同一组定向验证同时保留 request / stream happy-path 两条既有回归,确认 gate 收紧后不会误伤原本完整合同下的 provider 发射
|
||||
|
||||
### 验证(RP-072)
|
||||
|
||||
- `dotnet build GFramework.SourceGenerators.Tests/GFramework.SourceGenerators.Tests.csproj -c Release`
|
||||
- 结果:通过
|
||||
- 备注:并行执行 build/test 时曾出现 `MSB3026` 输出文件竞争噪音;无真实编译错误,随后以串行 test 结果作为本轮 authoritative 行为验证
|
||||
- `dotnet test GFramework.SourceGenerators.Tests/GFramework.SourceGenerators.Tests.csproj -c Release --filter "FullyQualifiedName~CqrsHandlerRegistryGeneratorTests.Does_Not_Emit_Request_Invoker_Provider_Metadata_When_Runtime_Lacks_Request_Provider_Interface|FullyQualifiedName~CqrsHandlerRegistryGeneratorTests.Does_Not_Emit_Request_Invoker_Provider_Metadata_When_Runtime_Lacks_Request_Descriptor_Enumerator|FullyQualifiedName~CqrsHandlerRegistryGeneratorTests.Does_Not_Emit_Stream_Invoker_Provider_Metadata_When_Runtime_Lacks_Stream_Provider_Interface|FullyQualifiedName~CqrsHandlerRegistryGeneratorTests.Does_Not_Emit_Stream_Invoker_Provider_Metadata_When_Runtime_Lacks_Stream_Descriptor_Enumerator|FullyQualifiedName~CqrsHandlerRegistryGeneratorTests.Emits_Request_Invoker_Provider_Metadata_When_Runtime_Contract_Is_Available|FullyQualifiedName~CqrsHandlerRegistryGeneratorTests.Emits_Stream_Invoker_Provider_Metadata_When_Runtime_Contract_Is_Available"`
|
||||
- 结果:通过,`6/6` passed
|
||||
|
||||
### 当前下一步(RP-072)
|
||||
|
||||
1. 先提交本轮 generator gate 合同回归与恢复点更新
|
||||
2. 重新复算 branch diff 后,再决定是否继续推进 request / stream provider 的 runtime 失败边界测试
|
||||
3. 若继续下一批,优先保持 test-only 或极小写集,避免在接近阈值前扩散到新的生产模块
|
||||
|
||||
### 阶段:precise reflected invoker provider 合同边界回归(CQRS-REWRITE-RP-071)
|
||||
|
||||
- 在 `RP-070` 提交后继续按 `gframework-batch-boot 50` 执行;当前已提交 branch diff 仍为 `24 files`,headroom 充足,因此继续下一批 generator-only 合同收敛
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user