Skip to content
bitzorcas
中EN

Guide

Consumer 合同测试

用隔离 Feed 和仓库外项目验证 BitzOrcas 包闭包、模板边界、Generator 资产与 Release 发布。

Last updated

Consumer 合同测试回答一个朴素问题:如果客户看不到产品仓库,只拿到模板和私有 Feed,项目还能不能构建和发布?

为什么普通集成测试不够

产品仓库里的 Host 可以直接引用项目,也能看到本机 NuGet 缓存。这样的测试容易掩盖三类问题:

  • 某个 packable 包漏了依赖;
  • Generator 只在产品仓库中偶然可见;
  • Consumer 模板偷偷引用或复制了产品源码。

Consumer Contract 把这些便利拿走,再验证一次。

本地合同流程

读取商业包目录
→ pack 候选包到临时 Feed
→ 创建外部 Consumer 项目
→ 写入带 <clear /> 和 Package Source Mapping 的 NuGet.Config
→ 隔离 NuGet、HTTP、plugin 与 CLI cache
→ restore / build / test / Release publish
→ 检查包资产与源码暴露

运行:

Terminal window
dotnet test tests/BitzOrcas.Framework.ConsumerContract.Tests \
--configuration Release \
--blame-hang-timeout 12m

必须通过的断言

  • Consumer 没有产品仓库 ProjectReference;
  • 输出不包含 Framework、Platform、Licensing 核心源码;
  • 所有 BitzOrcas.* 包来自映射 Feed;
  • Profile 的包闭包完整且版本一致;
  • Generator 以 analyzer 资产进入正确 Host;
  • build、test、Release publish 通过;
  • 客户业务模块只能引用公开 Contracts/SDK seam。

典型失败

症状可能原因优先检查
NU1101 找不到包包未 pack、目录漏项或 Source Mapping 不匹配临时 Feed 内容、catalog、NuGet.Config
编译期扩展方法缺失Generator 未作为 analyzer 进入目标 HostProfile 的 generator/hostRoles 投影
本机通过、CI 失败命中了本机全局缓存隔离变量和缓存目录
publish 失败运行时资产、RID 或包依赖声明不正确首个 publish 错误与包依赖图
发现产品源码模板复制了禁止目录模板内容和源码暴露断言

与正式 GA 的差别

本地合同从当前源码重新 pack,适合 PR 和开发反馈。正式 GA 不允许这样做:它必须下载可信发布产生的不可变包,从认证 HTTPS Feed 还原,并验证签名、provenance、SBOM 和策略证据。

当前覆盖矩阵

维度本地 Consumer Contract正式 Commercial GA
包来源当前源码 pack 到临时目录 Feedrelease workflow 的不可变 nupkg
Consumer 位置系统临时目录release artifact 中的仓库外 Solution
Feed本地隔离 Feed + source mapping认证 HTTPS Feed + 短期只读凭据
缓存NuGet/HTTP/plugin/CLI 隔离同样使用空隔离缓存
签名不作为本地合同结论dotnet nuget verify --all + 指纹集合
provenance/SBOM不验证正式证据schema、hash、策略和豁免到期检查
publishmini-api:PublishTrimmed=false;default-business:追加 Mediator 裁剪发布Release publish;目标项目设置决定裁剪

隔离为何要覆盖四类缓存

只清 NUGET_PACKAGES 不够。测试同时隔离:

  • NUGET_PACKAGES:全局包缓存;
  • NUGET_HTTP_CACHE_PATH:HTTP 元数据和包响应;
  • NUGET_PLUGINS_CACHE_PATH:Credential Provider/plugin 缓存;
  • DOTNET_CLI_HOME:CLI 首次运行、模板和其他用户级状态。

测试 NuGet.Config 使用 <clear />,并把 BitzOrcas.* 映射到隔离 Feed。这样产品包不能从 nuget.org 或未声明的本机 source 偶然恢复。

Terminal window
# 运行完整合同集合;fixture 只 pack 一次,再由用例复制只读基线 Feed。
dotnet test tests/BitzOrcas.Framework.ConsumerContract.Tests \
--configuration Release \
--blame-hang-timeout 12m \
--logger 'console;verbosity=normal'
# 只诊断 Mini API 外部消费主路径。
dotnet test tests/BitzOrcas.Framework.ConsumerContract.Tests \
--configuration Release \
--filter 'FullyQualifiedName~Profile_Mini_Api_Should_Restore_Build_And_Publish'

删除测试证明什么

正向 Restore 通过仍可能遇到“Profile 元包为空壳、Consumer 实际没有依赖它”的假阳性。合同因此复制 Feed、删除 Profile 包或闭包中的传递依赖,然后断言空缓存 Restore 必须失败。

删除测试回答“这个包是否真正承载依赖责任”。它不证明每个公共 API 都被客户使用;公开 API 兼容仍需要 API diff、编译夹具或客户场景测试。

包内容安全检查

合同会解压 nupkg 并拒绝产品核心 .cs、非模板 .csproj、PDB、Source Link 配置、本机绝对路径、私钥和常见 Credential 标记。模板包允许 Consumer 壳源码,但不允许 Framework、Platform 或 Licensing 核心 namespace。

这是一条交付隔离线,不是源码保密的唯一机制。还需要包签名、Feed 权限、最小公开 API、法律合同和发布审计共同工作。

新增 Profile 时怎样扩展合同

  1. 在机器可读 commercial catalog 登记 packable 项目;
  2. 在 Profile closure 声明完整包、Host role、Generator 和 License Feature;
  3. 为 Profile 创建外部 Consumer,引用元包而不是产品项目;
  4. 验证空缓存 Restore、Release Build、Test 和 Publish;
  5. 删除 Profile 包及关键传递依赖,断言 Restore 失败;
  6. 检查模板输出和 nupkg 内容没有产品实现源码;
  7. 把目标 Host 的 Generator/analyzer 资产纳入断言;
  8. 若声明 trim/AOT 支持,新增单独的裁剪发布合同。

合同批次的验收证据

  • 测试日志记录提交、SDK 与配置;
  • 临时 Feed 包集合与 catalog 投影一致;
  • 所有 Consumer 只用 PackageReference;
  • 四类缓存隔离且 NuGet source mapping 生效;
  • 正向流程和删除测试都按预期;
  • 包内容扫描没有源码、路径或 Secret 泄漏;
  • 每个 Profile 的 publish 是否裁剪在交付结论中逐条记录;
  • 正式发布仍转交 GA workflow 验证不可变 artifact。

另见

100%

滚轮或按钮缩放 · 放大后拖动画面 · 双击切换 100% / 200%