Chainlink CRE 冒烟测试实战指南:本地环境搭建、套件分桶与 CI 维护
【免费下载链接】chainlinknode of the decentralized oracle network, bridging on and off-chain computation项目地址: https://gitcode.com/GitHub_Trending/ch/chainlink
CRE(Chainlink Runtime Environment)是 Chainlink 节点核心代码库(当前仓库)中承载链下计算、工作流编排与跨链能力的一套运行时体系。本指南围绕仓库中system-tests/tests/smoke/cre的 CRE 冒烟测试套件展开,说明如何基于 Local CRE 环境运行这些测试、理解其环境引导机制、掌握分桶(bucket)选择与并行执行规则,并在 CI 中正确维护和扩展套件。读完本文,你将能够复现官方推荐的本地测试流程、按拓扑与场景精确挑选测试入口,并遵循仓库约定新增一条可被 CI 自动发现的冒烟测试。
CRE 冒烟测试的定位:包级规则与适用边界
system-tests/tests/smoke/cre/README.md首先给出了一条贯穿整套测试的“经验法则”(Rule of Thumb):
Happy-path(正常路径)与 sanity checks(健全性检查)属于
smoke;边缘场景与负向条件属于regression。
这条规则的完整展开见 docs/local-cre/system-tests/index.md:smoke 测试覆盖正常路径与健全性检查行为,而边界情况、负向条件应放在system-tests/tests/regression/cre包中。该边界也在 cre_suite_test.go 的包注释中被代码化:
//////////// SMOKE TESTS ///////////// // target happy path and sanity checks // all other tests (e.g. edge cases, negative conditions) // should go to a `regression` package /////////////////////////////////////从源码结构看,冒烟测试目录 system-tests/tests/smoke/cre 下按链族与能力维度组织了大量场景:EVM 读写、Solana 读写与日志触发、Aptos、Stellar、Vault、HTTP Action、分片(sharding)等,每个子目录通常带独立go.mod与main.go,形成可独立编译运行的分包。这与"套件可发现、可复用、可跨拓扑运行"的设计目标一致。
快速开始:五分钟拉起本地冒烟套件
仓库 README 给出了最小化的快速启动流程,这也是本地验证 CRE 冒烟套件的最短路径:
cd core/scripts/cre/environment go run . env setup go run . env start --with-chip-ingress-stack go test ./system-tests/tests/smoke/cre -timeout 20m -run '^Test_CRE_'命令拆解如下:
go run . env setup:初始化 Local CRE 环境(下载依赖镜像、生成配置文件等准备步骤);go run . env start:启动本地 CRE 环境。--with-chip-ingress-stack会额外拉起 Chip Ingress 观测栈(--with-beholder为已废弃的等价旧参数);go test:以^Test_CRE_前缀正则选中全部 CRE 冒烟测试,并给出20m的整体超时预算。
关于--with-chip-ingress-stack的端口冲突警告
docs/local-cre/system-tests/running-tests.md 特别强调:默认冒烟流程不要开启--with-chip-ingress-stack。原因在于,多数 CRE 冒烟测试会在默认 gRPC 端口50051上启动 ChIP 测试接收端(test sink),而 Chip Ingress 栈同样占用该端口;两者同时使用默认端口时,测试接收端会启动失败。--with-beholder已废弃,其行为与--with-chip-ingress-stack相同。
仅在以下情况才需要开启 Chip Ingress 栈:
- 你正在运行与 Chip Ingress 栈强相关的专项覆盖(如
CronChipIngressStack场景); - 调试时需要借助该栈观测;
- 你通过
--grpc-port将 Chip Ingress 改到别的端口,把默认50051留给测试接收端。
因此,官方推荐的常规本地流程是(见 running-tests.md):
cd core/scripts/cre/environment go run . env setup go run . env start go test ./system-tests/tests/smoke/cre -timeout 20m -run '^Test_CRE_'cre_suite_test.go 的头部注释也记录了同样的执行路径:先在core/scripts/cre/environment下执行go run . env restart --with-chip-ingress-stack(标注 deprecated),再在冒烟包内执行go test -timeout 15m -run "^Test_CRE_"。
测试如何自动引导本地 CRE:CTF_CONFIGS 的切换机制
使用这套套件时,你可以手动先启动 Local CRE 再跑测试,也可以让测试助手替你引导环境。其底层实现位于 system-tests/tests/test-helpers/before_suite.go,核心机制分三步(与 index.md 的描述一一对应):
- 若
CTF_CONFIGS为空,助手将其设置为请求的拓扑配置:setConfigurationIfMissing在CTF_CONFIGS为空时写入EnvironmentConfigPath,并设置默认私钥(before_suite.go#L333-L342); - 若 Local CRE 状态文件不存在,助手自动执行
go run . env start:createEnvironmentIfNotExists检查状态文件,缺失时拼装env start命令并执行(before_suite.go#L344-L360); - 环境创建完成后,
CTF_CONFIGS被切换为本地 CRE 状态文件,使测试消费已部署的环境而非原始拓扑 TOML(before_suite.go#L320-L331)。
func createEnvironment(t *testing.T, testConfig *ttypes.TestConfig, flags ...string) { // 1. 未设置 CTF_CONFIGS 时写入拓扑配置路径 setConfigurationIfMissing(testConfig.EnvironmentConfigPath) // 2. 状态文件不存在则自动 env start createEnvironmentIfNotExists(...) // 3. 切换 CTF_CONFIGS 到 Local CRE 状态文件 os.Setenv("CTF_CONFIGS", envconfig.MustLocalCREStateFileAbsPath(...)) }这就是"手动启动"与"助手自举"两种方式都能跑通的原因。此外,共享环境通过sync.Once保证每个(配置路径 + flags)组合只创建一次环境,同一拓扑下的多个测试复用同一套已部署合约与节点(before_suite.go#L116-L152),这正是下文"架构模式"中"每拓扑创建一次环境"的实现基础。
本地运行细节:超时、调试与 VS Code 配置
超时预算
运行时长与镜像来源强相关(running-tests.md):
- 镜像从源码构建时,预留约20 分钟;
- 使用预构建镜像时,运行时间显著缩短。
调试单个分桶
缩小范围、保留完整拓扑与工作流设置的单测调试模式:
CTF_LOG_LEVEL=debug \ go test ./system-tests/tests/smoke/cre -timeout 20m -run '^Test_CRE_V2_Suite_Bucket_A$'CTF_LOG_LEVEL=debug会输出更详细的框架日志,便于定位环境搭建阶段的失败。
VS Code 调试启动配置
文档同时给出了可直接使用的 VS Code launch 配置(mode: test):
{ "name": "Launch CRE V2 Bucket A", "type": "go", "request": "launch", "mode": "test", "program": "${workspaceFolder}/system-tests/tests/smoke/cre", "args": ["-test.run", "^Test_CRE_V2_Suite_Bucket_A$"] }环境变量速查表
冒烟套件主要依赖以下环境变量(来源:running-tests.md 及对应源码):
| 环境变量 | 作用 | 源码依据 |
|---|---|---|
CTF_CONFIGS | 启动前指向拓扑 TOML;启动后指向生成的 Local CRE 状态文件,本地运行由助手自动切换 | before_suite.go |
TOPOLOGY_NAME | 用于测试名、bucket 标签与日志输出,使结果与所测拓扑绑定 | cre_suite_test.go |
CTF_LOG_LEVEL=debug | 输出更详细的框架日志 | — |
CTF_JD_IMAGE | 固定 Job Distributor 镜像,避免默认本地镜像选择 | running-tests.md |
CTF_CHAINLINK_IMAGE | 固定 Chainlink 节点镜像 | dons.go |
其中CTF_CHAINLINK_IMAGE的消费点可以精确定位:system-tests/lib/cre/environment/dons.go 中的ensureGithubTokenForPrivatePlugins会先检查该变量——若通过环境变量提供了镜像,则无需本地 Docker 构建;否则当节点规格Image为空(需要构建)时,会要求GITHUB_TOKEN存在,缺失时尝试通过gh auth token获取,以便从私有仓库安装插件。
并行执行:默认关闭、按场景放行
并行执行是显式开启的(running-tests.md):
CRE_TEST_PARALLEL_ENABLED=1但该开关只是"允许并行",并不会盲目并行化所有用例。在 cre_suite_test.go 中,每个场景独立判断是否调用t.Parallel():
- 部分场景(如 ProofOfReserve、HTTP Trigger Action、Consensus 等)在
parallelEnabled为真时立即并行; - 部分场景保持串行,因为它们依赖不可共享的基础设施(例如 cre_suite_test.go 中共享同一分片配置的 Sharding 系列测试,显式标注了
//nolint:paralleltest)。
这与 docs/local-cre/system-tests/ci-and-suite-maintenance.md 中"该标志只授权并行,每个测试仍需自行判断是否安全调用t.Parallel()"的说明一致。
拓扑选择:默认拓扑与显式覆盖
默认本地流程使用的拓扑为:
core/scripts/cre/environment/configs/workflow-gateway-capabilities-don.toml对应源码中的默认配置:GetDefaultTestConfig即指向该文件(before_suite.go#L291-L295)。仅在你有意覆盖时(分片、纯网关、特定链族等覆盖)才需要改写CTF_CONFIGS。仓库 configs 目录 中已内置多套可选拓扑:
workflow-gateway-don.toml、workflow-gateway-don-aptos.toml、workflow-gateway-don-stellar.toml:不同链族/网关布局;workflow-gateway-sharded-don.toml、workflow-gateway-sharded-manual.toml、workflow-gateway-sharded-ringocr-overrides.toml:分片及手动分配、OCR 覆盖;workflow-gateway-capabilities-multi-gateway-don.toml:多网关路由;workflow-gateway-capabilities-don-vault-stall-purge.toml、...-vault-workflow-don-binding-enabled.toml:Vault 相关专项拓扑。
分桶测试选择:从超大入口到运行时均衡
较大的 CRE 冒烟套件被拆分为按运行时均衡的多个 bucket,而不是一个超大的测试入口(running-tests.md)。旧版 V2 套件分为三个入口:
Test_CRE_V2_Suite_Bucket_ATest_CRE_V2_Suite_Bucket_BTest_CRE_V2_Suite_Bucket_C
其场景分配定义在 system-tests/tests/smoke/cre/config/bucketing.go:
- suite-bucket-a:
ProofOfReserve、HTTPTriggerAction、DONTime、Consensus - suite-bucket-b:
VaultDON - suite-bucket-c:
CronChipIngressStack、HTTPActionCRUD、HTTPActionMultiGateway(后者除非TOPOLOGY_NAME包含multi-gateway否则跳过)
分桶注册表还带有完整性校验:ValidateSuiteBucketRegistry会检查每个场景是否恰好被分配到一个 bucket、是否存在重复分配或未分配场景(bucketing.go#L100-L126)。runSuiteBucket在启动时即调用该校验(cre_suite_test.go#L48-L55),防止分桶配置漂移。注释中还给出了再平衡的建议:在 CI 跑一次,依据各用例执行时间重新分配,保持 bucket 运行时均衡。
多网关 HTTP Action 路由
使用多网关拓扑并运行对应测试:
TOPOLOGY_NAME=workflow-gateway-capabilities-multi-gateway \ go test ./system-tests/tests/smoke/cre -timeout 20m -run '^Test_CRE_V2_HTTP_Action_Multi_Gateway$'注意TOPOLOGY_NAME需包含multi-gateway,否则该场景会直接跳过(cre_suite_test.go#L154-L164)。
EVM 读套件
EVM 读场景使用独立的 bucket 注册表,位于 system-tests/tests/smoke/cre/evm/evmread/config/bucketing.go,入口为:
Test_CRE_V2_EVM_Read_HeavyCallsTest_CRE_V2_EVM_Read_StateQueriesTest_CRE_V2_EVM_Read_TxArtifacts
何时使用分桶入口
- 本地反馈循环更短;
- CI 运行时长更稳定;
- 套件增长时能以可控方式再平衡各场景的运行时。
测试中的工作流:优先使用共享助手
冒烟测试通常不应自行实现工作流编译、产物拷贝与注册逻辑,而应复用共享助手(docs/local-cre/system-tests/workflows-in-tests.md):
t_helpers.CompileAndDeployWorkflow(...)该助手负责:
- 默认将工作流产物拷贝到工作流 DON;
- 按需支持额外的产物拷贝目标(
WithArtifactCopyDONTypes(...)); - 创建工作流产物;
- 从已部署环境解析工作流注册表;
- 以当前注册表版本注册工作流。
工作流编译规则(源码级)
共享编译器位于 system-tests/lib/cre/workflow/compile.go,其执行规则与文档描述一致:
- 工作流名称必须不少于 10 个字符(compile.go#L37-L39);
- Go 工作流:构建前先执行
go mod tidy(compile.go#L115-L119),并以CGO_ENABLED=0、GOOS=wasip1、GOARCH=wasm交叉编译为 WASM(compile.go#L121-L127); - TypeScript 工作流:通过
bun cre-compile编译(compile.go#L95-L110); - 语言由文件扩展名自动识别:
.ts/.tsx走 TS,.go走 Go(compile.go#L83-L93); - 最终产物为 Brotli 压缩 + base64 编码,输出为
.br.b64文件(compile.go#L137-L174)。
配置、密钥与 YAML 工作流
工作流配置文件是可选的、与具体被测工作流相关。共享工作流包提供密钥支持,会为注册准备针对当前 DON 与能力注册表的加密密钥。该领域还涵盖工作流密钥处理、YAML/DSL 工作流、直接的 JD(Job Distributor)任务提案流程——这些模式只留给确实需要底层控制的测试,标准冒烟路径仍应优先使用CompileAndDeployWorkflow。
环境助手二选一:Per-Test Keys 还是共享 Root Signer
编写测试时,比工作流编译更重要的选择是使用哪个环境助手(workflows-in-tests.md)。
场景一:SetupTestEnvironmentWithPerTestKeys(...)(工作流平面,可并行)
适用于可能并行执行、或执行独立链上写入的工作流平面测试。该路径(实现见 before_suite.go#L177-L248):
- 为测试生成全新的已注资密钥对(注资额为
perTestEVMFundingAmountWei = 1 ETH); - 将 EVM 客户端与部署者密钥切换为该测试专属签名者(通过 seth 新建 per-test 客户端、替换 CLDF deployer key);
- 需要时在 v2 工作流注册表上授权该签名者(
authorizePerTestWorkflowSignerIfNeeded调用UpdateAllowedSigners,且对根签名者 nonce 加锁保护); - 从而避免并行测试之间的 nonce 冲突与共享密钥耦合。
场景二:SetupTestEnvironmentWithConfig(...)(控制平面,共享根签名者)
适用于管理员/控制平面或所有权敏感测试,必须使用共享 root signer。这是以下流程的更安全选择:
- V1 注册表测试;
- 分片与所有权管理操作(如
ShardConfig的 ownership-admin); - 有意以环境所有者身份执行的测试。
经验法则:v2 工作流执行测试默认用SetupTestEnvironmentWithPerTestKeys;仅当测试需要共享所有者权限、或有意避开 per-test 签名者隔离时才用SetupTestEnvironmentWithConfig。二者的差异同样体现在 before_suite.go 的注释与setupTestEnvironmentWithConfigMode实现中。
价格数据源:TrueUSD 与 Fake 的实现差异
Proof-of-Reserve 相关测试使用共享的PriceProvider抽象,包含两种实现(workflows-in-tests.md):
TrueUSDPriceProvider:使用真实 TrueUSD 储备端点,主要校验价格是否变为非零;FakePriceProvider:启动一次共享的 fake HTTP 服务,为每条 feed 生成有界序列的测试价格,强制校验 auth 头,并同时追踪期望价格与实际价格以便严格断言。
Fake 实现的源码位于 system-tests/tests/smoke/cre/por_price_provider.go:通过sync.Once保证 fake 数据提供者只启动一次(避免端口冲突),响应体模拟 TrueUSD 的accountName/totalTrust/ripcord/updatedAt字段,并通过Authorization头校验请求合法性(未授权返回 401)。
使用建议:本地与可重复的冒烟覆盖用 fake provider;仅当场景有意验证与真实数据的集成路径时,才使用 live provider。
CI 与套件维护:自动发现与拓扑矩阵
自动发现机制
ci-and-suite-maintenance.md 描述的高层 CI 流程为:
- CI 自动发现
system-tests/tests/smoke/cre下的测试; - 构建"拓扑 × 测试入口"矩阵;
- 每个测试以适配该拓扑的配置运行。
这意味着新增 CRE 冒烟测试无需手工登记到专属列表。
命名与放置约定
- 测试放在
system-tests/tests/smoke/cre包中; - 函数名以
Test_CRE_前缀开头; - 遵循现有包内的 setup 与助手使用模式。
架构模式:每拓扑建一次环境
套件采用"分离"模式(ci-and-suite-maintenance.md):
- 每个拓扑只创建一次环境;
- 多个测试复用该环境;
- 已部署合约与节点在拓扑运行内共享。
这比每个测试都重建 Local CRE 更便宜、更快——其实现即上文提到的sync.Once共享环境缓存(before_suite.go#L116-L152)。
CI 中的受支持拓扑与逐测试覆盖
默认情况下,CRE 工作流对workflow-gateway-capabilities拓扑运行测试。部分测试必须用显式的逐测试覆盖替换默认拓扑集合,当前示例(在.github/workflows/cre-system-tests.yaml中配置):
Test_CRE_Aptos_Suite→workflow-gateway-aptosTest_CRE_Solana_Suite→workflowTest_CRE_Sharding→workflow-gateway-sharded
关键约束:若新测试只适用于非默认拓扑,仅添加测试代码是不够的,还必须在工作流矩阵中显式添加覆盖,让 CI 以匹配的topology与configs组合运行它。尽量保持测试拓扑无关;仅当工作流确实依赖不同链族或拓扑布局时才使用逐测试拓扑覆盖。
新增一条冒烟测试的七步流程
按照 ci-and-suite-maintenance.md 的清单:
- 将测试放入 smoke 包;
- 遵循现有命名约定(
Test_CRE_前缀); - 优先使用共享助手(
CompileAndDeployWorkflow、环境助手等); - 决定它属于现有 bucket 还是需要新入口;
- 若需要非默认拓扑,添加显式的工作流矩阵覆盖;
- 验证其在预期的拓扑矩阵下正常工作;
- 保持外部依赖显式化。
故障排查清单
测试逻辑启动前失败(running-tests.md)
- 确认
CTF_CONFIGS值正确; - 确认 Local CRE 状态文件有效;
- 确认所需镜像存在;
- 重跑
go run . env setup; - 开启 debug 日志重跑(
CTF_LOG_LEVEL=debug)。
CI 未发现测试(ci-and-suite-maintenance.md)
- 确认函数名以
Test_开头; - 确认文件位于 smoke 包内;
- 确认包可编译;
- 确认测试不依赖 CI 中不存在的本地专属假设。
推荐的本地工作流
综合 index.md 的建议,日常本地验证按以下顺序进行:
- 拉起 Local CRE(
go run . env setup+go run . env start); - 确认目标拓扑(默认
workflow-gateway-capabilities-don.toml,特殊场景按需覆盖); - 运行相关冒烟测试(全量
^Test_CRE_,或精确到分桶/单场景); - 仅在场景确实需要额外信号时,才使用 Chip Ingress 栈或观测能力(并避开默认
50051端口冲突)。
以上内容均基于当前仓库内文档与源码验证:文档骨架来自 system-tests/tests/smoke/cre/README.md 及其链接的 docs/local-cre 长文档,实现细节对照了 cre_suite_test.go、bucketing.go、before_suite.go、compile.go 与 dons.go 等源码文件,读者可沿这些路径继续深入探索。
【免费下载链接】chainlinknode of the decentralized oracle network, bridging on and off-chain computation项目地址: https://gitcode.com/GitHub_Trending/ch/chainlink
创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考