
云原生后端【免费下载链接】crossplaneThe Cloud Native Control Plane项目地址https://gitcode.com/gh_mirrors/cr/crossplane点击查看免费下载本文围绕 Crossplane 仓库中的设计文档 design/one-pager-e2e-tests.md 展开梳理 Crossplane 端到端E2E测试体系的来龙去脉为什么单靠单元测试不够、历史上多次尝试为何未能持续、最终方案如何通过把 E2E 测试搬进主仓库 每个 PR 强制运行 降低编写门槛来落地并结合仓库中 test/e2e 目录下的真实实现讲清测试套件、标签体系、可复用断言函数库与 YAML fixture 的完整用法。读完本文你将理解 Crossplane 的 E2E 测试是如何用e2e-framework Kubernetes YAML 清单组织起来的并能照着示例在自己的改动上新增一条端到端测试。背景为什么单靠单元测试不够Crossplane 高度依赖单元测试来保证质量但单元测试无法证明整个 Crossplane 合在一起能正常工作。在提出这份设计之前仓库长期依赖一套荣誉制度——由贡献者手工运行黑盒测试凭自觉验证自己的改动在真实环境下可用。这类手工测试存在一系列固有缺陷不可重复、不可移植别人很难照着复现环境单一往往只在作者笔记本上的kind集群里跑过一次不防回归后续改动不会重跑这些测试无法发现破坏容易漏掉性能退化之类的问题对小改动习惯性跳过例如看似人畜无害的依赖升级不关注特性间的交互通常只验证被测特性本身基本不覆盖升级场景从旧版本升级到新版本。文档明确指出这些年里发布的若干版本中出现的 issue很多本可以被 E2E 测试拦截文档中引用了 PR #3376、issue #3113、issue #3071 等作为例证。此前的尝试与教训Crossplane 过去多次尝试引入集成/E2E 测试但都没有坚持下来。典型模式是定下一个方案 → 实现前一两个测试 → 之后再无人问津。文档认为主要原因在于依赖 CNCF 实习生启动测试工作实习期结束、贡献者热情消退后测试框架便荒废了。历史上出现过三个有代表性的尝试尝试形态问题integration_tests.sh存活时间最长的黑盒测试脚本随每个 CI 任务每个 PR运行只验证 Crossplane 启动不崩溃覆盖范围极小test/e2e旧版定义在仓库内的 E2E 测试需要有人持续维护crossplane/test独立仓库按固定计划运行混合使用test/e2e中的测试与自身仓库的测试与 PR/发布流程脱钩测试坏了没人注意到其中crossplane/test覆盖的场景包括用 Helm chart 把 Crossplane 从 stable 升级到 master 构建、把 Provider 从一个版本升级到另一个版本、解析 Configuration 包依赖、用最小 Composition无任何 patch/transform创建 claim 等。但它运行在独立仓库、与 PR 和发布无关联因此测试是否还通过无人知晓而且很容易在新增功能时忘记同步更新测试。目标与范围界定设计提案为 E2E 测试体系定下四个目标自动模拟对 Crossplane 全部功能的真实使用在改动合并前捕获单元测试发现不了的那类 bug确保贡献者真的会去添加和维护测试运行可靠不允许 flaky不稳定测试存在。范围上Crossplane仅指 crossplane/crossplane 仓库内定义的功能包管理器、Composition 引擎等测试某个 provider 或 function 扩展是否工作正常不在范围内。文档特别澄清了黑盒的含义黑盒就是本仓库产出的工件——Crossplane 容器镜像和 Helm chart。测试它们与 Kubernetes API server 的集成是不可避免的但目的不是去测试 API server 本身或任何特定客户端比如kubectl并不直接与 Crossplane 交互它只是把 Crossplane 会读取的状态写入 API server。提案把 E2E 测试搬进主仓库每个 PR 强制运行提案的核心动作有四条把所有 E2E 测试代码移入本仓库crossplane/crossplane在每个 PR 上运行全部 E2E 测试失败即构建失败更新贡献指南和 PR 模板鼓励要求贡献者补 E2E 测试努力让 E2E 测试的添加和扩展变得低门槛。文档也预见到随着测试规模扩大每个 PR 全量跑 E2E 会越来越贵、越来越慢但可以留到问题真正出现时再处理——届时可以加一个 GitHub Action 按需触发特定测试或改为周期性运行如每晚跑一次。PR 模板中的测试 Checklist为了让写测试成为强制项提案把 PR 模板更新为如下内容该模板同时删掉了原先请说明你如何手工测试过的段落### Description of your changes !-- Briefly describe what this pull request does, and how it is covered by tests. Be proactive - direct your reviewers attention to anything that needs special consideration. You MUST either [x] check or ~strikethrough~ every item in the checklist below. We love pull requests that fix an open issue. If yours does, use the below line to indicate which issue it fixes, for example Fixes #500. -- Fixes # I have: - [ ] Read and followed Crossplanes [contribution process]. - [ ] Added or updated unit **and** E2E tests for my change. - [ ] Run make reviewable to ensure this PR is ready for review. - [ ] Added backport release-x.y labels to auto-backport this PR if necessary.要点开头注释要求作者说明这次改动是如何被测试覆盖的checklist 新增了关于测试的条目单元测试和E2E 测试移除了手工测试说明段落配合require-checklist-action这类机器人未完成 I have checklist 的 PR 无法被合并。测试编写范式降低门槛是核心设计目标文档对当时流行的两种 E2E 测试形态shell 脚本、基于标准库testingclient-go的重型 Go 测试都不满意提出了一套降低贡献者负担的编写范式用熟悉的 Kubernetes YAML 清单作为测试 fixture构建一套通用、可复用的检查函数库例如这个资源是否达到了期望的 condition尽可能复用现有工具不重复造轮子坚持使用贡献者熟悉、不令人意外的工具。最终目标是绝大多数测试只需要添加/修改 YAML 清单 少量 Go 胶水代码用现成函数去断言 Crossplane 在这些清单被应用后是否正确工作。为此文档明确选型使用 kubernetes-sigs/e2e-framework 编写测试把评估assessment函数即features.Func的实现与测试步骤定义分离到不同 package。选型理由e2e-framework 尽量贴近熟悉的 Go 标准库testing风格是 Kubernetes SIG 项目生态采纳迹象明显专为 E2E 测试Kubernetes 相关的东西而设计内置了应用清单、等待资源就绪等实用工具。仓库落地test/e2e 目录的完整结构提案在仓库中已经完整落地。当前 test/e2e 目录的组织结构正是文档所设想的形态test/e2e/ ├── main_test.go # TestMain环境装配kind/Helm/标签 ├── consts.go # 标签常量与 SSA field manager ├── install_test.go # 安装相关测试 ├── apiextensions_*_test.go # 各领域测试Composition、XRD、MRD 等 ├── pkg_test.go # 包管理Provider/Configuration ├── ops_operations_test.go # Operations 生命周期 ├── protection_*_test.go # Usage 保护 ├── config/ │ └── environment.go # 环境配置flag、测试套件suite注册 ├── funcs/ │ ├── funcs.go # package 声明与文档 │ ├── feature.go # features.Func 断言函数库核心 │ ├── env.go # env.Funckind 集群、Helm、scheme 注册 │ └── collect.go # 关联对象图收集故障诊断用 └── manifests/ # YAML fixture按领域/场景分目录 ├── kind/kind-config.yaml └── apiextensions/composition/basic-namespaced/ ...TestMain一次装配处处可用test/e2e/main_test.go 是所有 E2E 测试的装配入口。它做的工作包括解析命令行 flag 构建 e2e-framework 环境注册默认测试套件base附带 Helm 安装选项——包括 release 名crossplane、命名空间crossplane-system、chart 目录 cluster/charts/crossplane、--wait与5m超时以及通过--set args{--debug}开启调试日志、按--crossplane-image注入镜像、开启 metrics选择运行目标默认用 test/e2e/manifests/kind/kind-config.yaml 创建 kind 集群若已存在集群则复用 kubeconfig把 Crossplane 镜像 load 进 kind 集群、创建命名空间、Helm 安装 Crossplane把 Crossplane 的自定义类型apiextensions、ops、pkg、protection注册进 scheme使测试客户端能读写这些 CR注册finish钩子失败时导出 kind 集群日志、结束后销毁集群用BeforeEachFeature强制要求每个 feature 必须带test-suite标签否则测试直接失败。环境配置与测试套件机制test/e2e/config/environment.go 定义了整套运行时配置。它封装 e2e-framework 环境并暴露一组可命令行覆盖的 flagFlag默认值作用-kind-cluster-name空要使用的 kind 集群名空则随机生成crossplane-e2e-*32 字符-kind-logs-location空失败时 kind 集群日志导出位置-create-kind-clustertrue测试前创建 kind 集群若同名集群不存在并部署 Crossplane-destroy-kind-clustertrue测试完成后销毁 kind 集群-preinstall-crossplanetrue测试前安装 Crossplane-prior-crossplane-version空用于升级测试的上一个 Crossplane 版本-load-images-kind-clustertrue测试前把 Crossplane 镜像 load 进 kind 集群-crossplane-imagecrossplane-e2e/crossplane:latest测试使用的 Crossplane 镜像-test-suitebase选择测试套件决定环境装配与运行哪些测试测试套件suite是本仓库对 e2e-framework 的扩展每个套件可以带自己的 Helm 安装参数、额外的 setup 函数和要选择的 feature 标签未显式排除时都会叠加base套件的安装参数。一个典型例子在 test/e2e/apiextensions_compositions_test.go注册function-response-cache套件它会额外带上--enable-function-response-cache启动参数并选择function-response-cachebase两个标签的测试——也就是用同一套测试覆盖新特性开关。标签体系测试的分类与筛选test/e2e/consts.go 定义了一套贯穿所有测试的标签约定area功能领域如apiextensions、pkg见LabelAreasize耗时规模small通常一分钟内完成或large超过一分钟见LabelSizeSmall/LabelSizeLargestage功能阶段alpha/beta正式功能不加见LabelStageAlpha/LabelStageBetamodify-crossplane-installation标记会改动 Crossplane 安装安装/卸载/升级的测试test-suite测试所属套件见上文由 test/e2e/config/environment.go 定义。此外FieldManager crossplane-e2e-tests是服务端应用SSA时使用的 field manager。实战剖析一个完整的 E2E 测试以 TestBasicCompositionNamespaced 为例看一条测试从 YAML fixture 到 Go 断言的完整链路。第一步准备 YAML fixturefixture 目录 test/e2e/manifests/apiextensions/composition/basic-namespaced 下setup/definition.yaml一个CompositeResourceDefinitionv2定义example.org组的Test资源scope 为 Namespacedspec 需要coolFieldstatus 暴露coolerFieldsetup/composition.yaml、setup/functions.yaml、setup/secret.yaml配套的 Composition、函数function与 Secretxr.yaml被测的复合资源实例apiVersion: example.org/v1alpha1 kind: Test metadata: namespace: default name: basic-xr-namespaced spec: coolField: Im cool! crossplane: compositionRef: name: basic-composition-namespaced第二步用 Go 编排 Setup/Assess/Teardownfunc TestBasicCompositionNamespaced(t *testing.T) { manifests : test/e2e/manifests/apiextensions/composition/basic-namespaced environment.Test(t, features.NewWithDescription(t.Name(), ...). WithLabel(LabelArea, LabelAreaAPIExtensions). WithLabel(LabelSize, LabelSizeSmall). WithLabel(config.LabelTestSuite, config.TestSuiteDefault). WithSetup(CreatePrerequisites, funcs.AllOf( funcs.ApplyResources(FieldManager, manifests, setup/*.yaml), funcs.ResourcesCreatedWithin(30*time.Second, manifests, setup/*.yaml), funcs.ResourcesHaveConditionWithin(1*time.Minute, manifests, setup/definition.yaml, apiextensionsv1.WatchingComposite()), )). Assess(CreateXR, funcs.AllOf( funcs.ApplyResources(FieldManager, manifests, xr.yaml), funcs.ResourcesCreatedWithin(30*time.Second, manifests, xr.yaml), )). Assess(XRIsReady, funcs.ResourcesHaveConditionWithin(1*time.Minute, manifests, xr.yaml, xpv2.Available(), xpv2.ReconcileSuccess())). Assess(XRHasStatusField, funcs.ResourcesHaveFieldValueWithin(1*time.Minute, manifests, xr.yaml, status.coolerField, IM COOLER!)). WithTeardown(DeleteXR, funcs.AllOf( funcs.DeleteResourcesWithPropagationPolicy(manifests, xr.yaml, metav1.DeletePropagationForeground), funcs.ResourcesDeletedWithin(1*time.Minute, manifests, xr.yaml), )). WithTeardown(DeletePrerequisites, funcs.AllOf( funcs.DeleteResourcesWithPropagationPolicy(manifests, setup/*.yaml, metav1.DeletePropagationForeground), funcs.ResourcesDeletedWithin(3*time.Minute, manifests, setup/*.yaml), )). Feature(), ) }这条测试验证了文档所说的核心目标——YAML 清单 少量 Go 胶水代码WithSetup应用setup/*.yaml里的前置资源等待它们创建成功并断言 XRD 达到WatchingComposite条件表示 CRD 已建立、被 Crossplane 接管Assess(CreateXR)应用xr.yaml并等它出现Assess(XRIsReady)等待 XR 达到Available与ReconcileSuccess条件——这正是 Composition 引擎成功编排的证明Assess(XRHasStatusField)用 fieldpath 断言status.coolerField最终等于 Composition 写入的值WithTeardown按 Foreground 传播策略删除 XR 与前置资源并等待删除完成——顺带验证了清理路径。同文件中的其他测试展示了更丰富的场景TestCompositionRevisionSelection验证 Composition 变更后实时选择新 revisionTestCompositionSelection验证 label selector 从 claim 传播到 XR、再反传播TestCompositionValidation用features.Table把合法 Composition 能应用、非法清单必须被拒绝等用例做成数据表驱动其中非法用例用ResourcesFailToApply断言 API server 会拒绝TestCircuitBreaker则以每 50ms 一次的 SSA 更新连续打 60 次验证 50 token 桶被耗尽后熔断器打开。可复用断言函数库funcs 包文档要求的通用可复用检查库正是 test/e2e/funcs/feature.go它实现了大量开箱即用的features.Func绝大多数遵循XxxWithin(duration, ...)的命名约定——在指定时间内完成某状态转换否则失败函数作用ApplyResources(manager, dir, pattern)用服务端应用SSA强制接管字段应用目录下匹配 glob 的清单ResourcesFailToApply断言清单无法被应用成功用于验证校验逻辑ResourcesCreatedWithin/ResourceCreatedWithin等待资源在期限内被创建ResourcesDeletedWithin/ResourceDeletedWithin等待资源在期限内被删除ResourcesHaveConditionWithin/ResourceHasConditionWithin等待资源达到指定 condition比较时忽略 message 字段避免跨运行差异ResourcesHaveFieldValueWithin/ResourceHasFieldValueWithin用 fieldpath 等待某字段等于期望值支持特殊哨兵值NotFound与Any也支持传入FieldValueChecker自定义匹配ResourceValidatedWithin等待对象通过自定义校验函数ReadyToTestWithin等待crossplaneDeployment 变为 Available作为测试可以开始的信号比显式检查 CRD 就绪更快DeploymentBecomesAvailableWithin/DeploymentPodIsRunningMustNotChangeWithinDeployment 可用性 / Pod 稳定性断言ArgExistsWithin/ArgNotExistsWithin断言 Deployment Pod 容器参数存在/不存在用于验证 feature flag 是否生效CompositeResourceHasFieldValueWithin/CompositeResourceMustMatchWithin从 claim 出发定位其 XR再对 XR 做 fieldpath 或自定义断言ClaimUnderTestMustNotChangeWithin/CompositeUnderTestMustNotChangeWithin断言 claim/XR 在指定时间内不被改动回归防护AllOf顺序执行多个函数配合 e2e-framework 的-fail-fast可提前中止InBackground在 goroutine 中执行函数SleepFor固定等待如等待 cron 调度类的时间条件值得注意的实现细节ResourceHasConditionWithin在比较条件时会把期望的ObservedGeneration同步为对象最新 generation并对条件未带 observedGeneration的过渡期做了兼容处理见代码中对 issue #6420 的注释而ApplyHandler通过client.ApplyFieldOwner(manager)ForceOwnership实现 SSA 应用。环境级函数kind 与 Helmtest/e2e/funcs/env.go 提供环境装配层的可复用函数HelmRepo/HelmInstall/HelmUpgrade/HelmUninstall封装 e2e-framework 内置的 Helm 支持AsFeaturesFunc把env.Func适配成features.Func出错即t.FatalAddCrossplaneTypesToScheme/AddCRDsToScheme把 Crossplane 各类 CRD 类型注册进 schemeCreateKindClusterWithConfig按指定配置文件创建 kind 集群ServiceIngressEndPoint根据 kind 端口映射解析 Service 的对外访问地址。故障诊断关联对象图test/e2e/funcs/collect.go 实现了一个颇具价值的诊断工具RelatedObjects通过 discovery 列出集群中所有资源依据 ownerReference、claim→XR 引用、XR→composed resource 引用构建关联对象图再递归收集与失败对象相关的所有对象。当ResourcesDeletedWithin或ResourceHasConditionWithin断言失败时测试输出会附上失败对象及其关联对象的 YAML 与事件kubectl events风格大幅缩短定位问题的路径。升级场景与稳定性验证文档明确把升级场景列为手工测试常缺失的环节。仓库中对应的是 test/e2e/config/environment.go 提供的HelmInstallPriorCrossplane/HelmUpgradePriorCrossplane先从https://charts.crossplane.io/stable添加crossplane-stableHelm 仓库用--prior-crossplane-version指定的旧版本安装或升级到旧版 Crossplane升级到新版时显式使用--reset-values避免旧 install 的 values例如当前构建的镜像 tag覆盖 chart 默认值。这样便能在真实集群里验证从 stable 升级到 master 构建的路径正是文档中crossplane/test曾经覆盖、但脱离主仓库后无人维护的场景。备选方案对比文档记录了对其他主流 E2E 框架的评估详见 PR #4101 的讨论Godog即 Cucumber 的 Go 实现、Terratest、kuttl 都在考虑范围内但最终都未被采纳原因是它们与贴近 Go 标准库testing、贡献者熟悉、不意外的原则存在差距而 e2e-framework 恰好满足全部要求。从设计到实践给贡献者的行动清单结合文档提案与仓库现状如果你想为 Crossplane 新增一条 E2E 测试完整路径如下在 test/e2e/manifests 下按领域/场景/组织 YAML fixturesetup/放前置资源其余放被测对象与断言目标在对应的*_test.go中注册 feature打上area、size、test-suite必要时加stage、modify-crossplane-installation标签用 funcs 里的现成函数拼装Setup/Assess/Teardown若需要特殊启动参数如新的 feature flag在init()里用environment.AddTestSuite注册一个新套件或把测试标到已有套件下本地运行示例# 使用默认 base 套件自动创建 kind 集群、安装 Crossplane、结束后销毁 go test ./test/e2e -run TestBasicCompositionNamespaced -v -timeout 30m # 指定套件、复用已有集群并保留日志 go test ./test/e2e -test-suite function-response-cache -v -timeout 60m \ -create-kind-clusterfalse -destroy-kind-clusterfalse -kind-cluster-name my-cluster提交 PR 时勾选模板中的 Added or updated unitandE2E tests for my change并运行make reviewable。这套体系把每个 PR 都要通过 E2E 回归从口号变成了仓库的强制约定测试代码与产品代码同仓库演进YAML fixture 降低编写门槛可复用断言库避免重复造轮子套件与标签机制让新特性可以复用既有测试矩阵。这正是 design/one-pager-e2e-tests.md 这份设计文档落地后的实际面貌也是 Crossplane 在真实 Kubernetes 环境中持续交付质量的基础设施。赞分享云原生后端【免费下载链接】crossplaneThe Cloud Native Control Plane项目地址https://gitcode.com/gh_mirrors/cr/crossplane点击查看免费下载相关推荐Carbon 设计系统测试指南从 E2E 包验证到 Playwright 组件回归测试Carbon 设计系统测试指南从 E2E 包验证到 Playwright 组件回归测试 本篇技术指南基于 CarbonIBM 开源设计系统仓库中的 doc前端UI组件设计系统waspc e2e 测试基于黑盒 Shell 命令与 Golden 快照的 Wasp CLI 验证体系waspc e2e 测试基于黑盒 Shell 命令与 Golden 快照的 Wasp CLI 验证体系 本篇技术文章以 waspc/e2e tests/REAWeb框架后端前端CLI开发工具终极指南Chat2DB自动化测试体系构建与实践——从端到端测试到回归测试全流程终极指南Chat2DB自动化测试体系构建与实践——从端到端测试到回归测试全流程 Chat2DB作为一款功能强大的数据库管理工具其稳定性与可靠性直接影响用户的数据库客户端AI 应用数据分析上一篇Enatega白标餐饮配送解决方案从零开始搭建自己的外卖平台下一篇VexFlow EasyScore终极教程用简单代码生成专业乐谱的完整指南创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考