Chainlink 本地 CRE E2E 实战指南:环境生命周期、冒烟/回归测试与自定义拓扑
【免费下载链接】chainlinknode of the decentralized oracle network, bridging on and off-chain computation项目地址: https://gitcode.com/GitHub_Trending/ch/chainlink
本文面向需要在chainlink仓库中本地开发、调试 CRE(Chainlink Runtime Environment,链上/链下工作流运行时)的开发者和测试工程师,系统讲解如何在本地拉起完整的 CRE 环境、运行 CRE 冒烟/回归端到端测试,以及通过自定义拓扑覆盖 limits、feature flags、capability 配置与user_config_overrides的完整方法。读完本文,你将掌握从env stop到env start的完整环境生命周期操作、默认拓扑下的测试执行套路,以及基于CTF_CONFIGS+ 拓扑 TOML 灵活定制测试场景的实战技能。
本文的核心依据是仓库内 Agent Skill 文档 docs/local-cre/agent-skills/local-cre-e2e/SKILL.md,并辅以 Local CRE 环境 CLI 与 CRE 冒烟测试套件 的源码佐证。
适用范围与基本假设
这个 Skill 解决什么问题
local-cre-e2e是一个面向 Agent 与开发者的操作技能说明,适用于以下场景:
- 启动、停止或重启本地 CRE 环境;
- 在默认拓扑上运行 CRE 冒烟(smoke)或回归(regression)端到端测试;
- 针对特定拓扑运行测试;
- 创建自定义拓扑,以覆盖 limits、flags、capability 配置或
user_config_overrides。
需要特别注意的是,它面向的是Local CRE 系统级测试工作流,不适用于普通单元测试。
运行前提假设
根据 SKILL.md,使用该工作流需满足四个前提:
- 仓库根目录是
chainlink的检出目录(即当前仓库根); - 本地 CRE 命令统一在
core/scripts/cre/environment目录下执行; - CRE E2E 测试命令统一在
system-tests/tests目录下执行; - 除非明确知道 harness 支持隔离,否则同一时间只应有一个活动的本地 CRE 环境——这是避免状态串扰的关键纪律。
从源码看,CLI 入口位于 core/scripts/cre/environment/main.go,它把env、topology、examples、bs、obs五组子命令挂到根命令root.RootCmd上,因此所有环境操作都通过go run . <command> [subcommand]的统一形态调用。
默认工作流:从清理到启动一次本地 CRE
第一步:停止可能存在的旧环境
每次开始前,先彻底停止可能残留的本地 CRE 环境,避免新环境与旧状态的端口、容器、状态文件冲突:
cd core/scripts/cre/environment go run . env stop -a-a(--all)会连同所有额外服务一起停止。对应源码见 environment.go 中stop子命令的定义,其提示信息明确写道:"All extra services: stop withgo run . env stop --all"。
第二步:一次性准备环境
如果环境尚未准备过(或需要重新拉取/构建依赖镜像),先执行一次设置:
cd core/scripts/cre/environment go run . env setupenv setup由configs/setup.toml驱动,负责确保 Job Distributor、Chip Router、Chip Ingress、Chip Config 等托管镜像就绪。它也可以显式指定配置并跳过交互提示:
go run . env setup --config configs/setup.toml --no-prompt如果需要重建或重新拉取全部前置依赖,env setup支持--purge;需要计费(billing)资产时可加--with-billing(详见 docs/local-cre/getting-started/index.md)。
提示:
env setup并非每次都要跑。镜像已经就位、只改拓扑 TOML 的情况下,直接env start即可。SKILL.md 强调它是"环境尚未准备时的一次性步骤"。
第三步:启动默认拓扑
cd core/scripts/cre/environment go run . env startenv start默认读取CTF_CONFIGS指向的拓扑 TOML;未设置时使用默认拓扑workflow-gateway-capabilities-don.toml。对应源码见 environment.go,其中还包含对 Job Distributor 镜像的存在性检查(environment.go),若镜像缺失会提示先执行go run . env setup。
快速上手时也可以一步到位使用--auto-setup:
go run . env start --auto-setup第四步(可选):启动可观测性组件
go run . obs up当你需要日志、追踪或面板来调试工作流事件时,用obs up拉起 observability 辅助栈。SKILL.md 特别指出:
- 当测试依赖真实 ChIP Ingress 栈,或你想用Red Panda Console调试工作流事件时,在
env start上加--with-chip-ingress-stack; --with-beholder已废弃(deprecated),等价行为请改用--with-chip-ingress-stack。
为什么默认冒烟流程不建议开--with-chip-ingress-stack?docs/local-cre/system-tests/running-tests.md 给出了实现层面的原因:大多数 CRE 冒烟测试会在默认 gRPC 端口50051上启动 ChIP 测试 sink(test sink),而 Chip Ingress 栈的 ChIP ingress 也绑定同一端口。两者抢同一端口会导致测试 sink 启动失败。因此仅在以下情况才启用该栈:
- 你在跑 Chip Ingress 栈专属的覆盖场景;
- 你需要用它做调试;
- 你通过
--grpc-port给它换一个端口,把默认50051留给测试 sink。
Chip 相关组件的默认端口布局(来自 docs/local-cre/environment/index.md):
50050:Chip Router admin API;50051:Chip Router ingress gRPC;50052:chip-config;50053:真实 ChIP / Chip Ingress 栈 gRPC。
补充:本地源码构建模式
在默认拓扑基础上,如果你正在开发 node 或某个 capability,docs/local-cre/environment/index.md 还提供了两个高频扩展 flag:
# 节点 + 全部 capability 都用本地工作树构建(含 observability) go run . env start --with-observability --local-node --local-capabilities all # 节点用固定镜像,仅 cron + evm 用本地构建覆盖 go run . env start --local-capabilities cron,evm--local-node:在宿主机交叉编译本地 checkout 的 Chainlink 节点并烘焙进最小镜像,覆盖拓扑中的docker_ctx/image;--local-capabilities <names|all>:从本地源码构建指定 CRE capability 并注入节点,未列出的 capability 保留镜像内版本;--capabilities-path <dir>:本地 capabilities 仓库位置(默认$CRE_CAPABILITIES_PATH,否则为~/go/src/github.com/smartcontractkit/capabilities);--local-build-platform <os/arch>:本地构建目标平台(默认linux/<宿主机架构>);--local-node-image <tag>:本地构建节点的镜像标签(默认cre-node:local)。
在默认拓扑上运行 E2E 测试
环境起来后,切到测试目录执行测试。测试命令必须在system-tests/tests下运行(这一目录本身是一个独立的 Go module,见 system-tests/tests/go.mod)。
常规 CRE 冒烟套件
cd system-tests/tests go test ./smoke/cre -timeout 20m -run '^Test_CRE_'仅 V2 冒烟套件
cd system-tests/tests go test ./smoke/cre -timeout 15m -run '^Test_CRE_V2'回归测试
cd system-tests/tests go test ./regression/cre -timeout 20m -run '^Test_CRE_'smoke 与 regression 的划分规则
SKILL.md 给出的经验法则与源码注释完全一致:
smoke面向 happy path 与 sanity 覆盖;regression面向边界条件与负向场景。
这一点在测试入口文件 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 /////////////////////////////////////测试与环境的衔接机制
你可能好奇:为什么先启动 Local CRE 再跑测试就能对上?这依赖system-tests/tests/test-helpers/before_suite.go中的 helper 逻辑(before_suite.go):
- 如果
CTF_CONFIGS为空,helper 会把它设置为请求的配置; - 如果本地 CRE 状态文件(Local CRE state file)不存在,helper 会自动执行
go run . env start把环境拉起来; - 环境创建完成后,
CTF_CONFIGS会被切换为指向本地 CRE 状态文件,而不是原始拓扑 TOML,从而让测试使用已部署的环境。
因此两种工作方式都成立:手动先起环境再跑测试,或直接让 helper 帮你引导环境。
运行特定测试或桶
用窄正则调试单个场景
当你在排查单个场景或某个桶时,使用收窄的正则表达式,并配合-count=1防止测试缓存带来的假结果:
cd system-tests/tests go test ./smoke/cre -timeout 20m -run '^Test_CRE_V2_Suite_Bucket_B$' -count=1 -v按场景子路径过滤
V2 套件内部按场景组织子测试,可以用/继续下钻:
cd system-tests/tests go test ./smoke/cre -timeout 20m -run 'Test_CRE_V2_Suite_Bucket_B/.*/Vault' -count=1 -vcd system-tests/tests go test ./regression/cre -timeout 20m -run '^Test_CRE_V2_Consensus_Regression$' -count=1 -vSKILL.md 强调:重跑易 flaky 或带状态(stateful)的 CRE 场景时,务必加-count=1,跳过 Go 测试缓存,确保从头执行。
桶(Bucket)结构与场景分配
较大的 CRE 冒烟套件按运行时均衡拆分为多个桶,而不是一个巨型测试入口。旧的 V2 套件拆分为:
Test_CRE_V2_Suite_Bucket_ATest_CRE_V2_Suite_Bucket_BTest_CRE_V2_Suite_Bucket_C
入口定义在 cre_suite_test.go,每个入口都会先校验桶注册表再执行场景。桶到场景的分配定义在 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,否则跳过) |
suiteBucketRegistry是旧 V2 套件场景分配桶的唯一登记处,新增场景时应在此添加,并通过 CI 实测时间重新均衡各桶运行时(bucketing.go 的注释给出了这一维护流程)。
EVM 读取套件还有一套独立的桶注册表,位于 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 运行时长,以及在套件增长时可控地再平衡场景运行时。
本地调试的 VS Code 配置
docs/local-cre/system-tests/running-tests.md 提供了一个可直接套用的 VS Code launch 配置模板:
{ "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$"] }配合 debug 日志跑一个窄测试的常见形态是:
CTF_LOG_LEVEL=debug \ go test ./system-tests/tests/smoke/cre -timeout 20m -run '^Test_CRE_V2_Suite_Bucket_A$'CTF_LOG_LEVEL=debug会让框架在 setup 与测试执行阶段输出更详细的日志,而窄化的-run保证仍走与完整套件相同的拓扑与工作流 setup。
使用特定拓扑
当测试需要特定的 DON 布局、链或功能配置时,使用非默认拓扑。
流程:停旧环境 → 指定拓扑启动 → 跑目标测试
# 1. 停止现有环境 cd core/scripts/cre/environment go run . env stop -a # 2. 用 CTF_CONFIGS 指定拓扑文件启动 cd core/scripts/cre/environment CTF_CONFIGS=./configs/workflow-gateway-capabilities-don.toml go run . env start # 3. 运行目标测试(TOPOLOGY_NAME 可选) cd system-tests/tests TOPOLOGY_NAME=workflow-gateway-capabilities \ go test ./smoke/cre -timeout 20m -run '^Test_CRE_V2_Suite_Bucket_B$' -count=1 -vTOPOLOGY_NAME的作用
TOPOLOGY_NAME是可选但很有用的环境变量。为什么有用?因为大量 CRE 套件测试会把拓扑名包含进子测试名、桶标签与日志输出,让结果始终与所测拓扑挂钩。实现上,套件入口在 cre_suite_test.go 直接读取该变量:
var ( parallelEnabled = t_helpers.ParallelEnabled() // topology is used in test names topology = os.Getenv("TOPOLOGY_NAME") )典型例子:多网关 HTTP action 路由场景需要启动configs/workflow-gateway-capabilities-multi-gateway-don.toml,然后执行:
TOPOLOGY_NAME=workflow-gateway-capabilities-multi-gateway \ go test ./system-tests/tests/smoke/cre -timeout 20m -run '^Test_CRE_V2_HTTP_Action_Multi_Gateway$'测试助手的拓扑衔接细节
docs/local-cre/system-tests/running-tests.md 汇总了冒烟套件使用的核心环境变量:
CTF_CONFIGS:启动前指向拓扑 TOML,启动后被 helper 自动切换为生成的 Local CRE 状态文件(本地运行由before_suite.go完成切换);TOPOLOGY_NAME:进入测试名、桶标签与日志输出;CTF_LOG_LEVEL=debug:启用更详细的框架日志;CTF_JD_IMAGE:固定 Job Distributor 镜像,避免默认本地镜像选择;CTF_CHAINLINK_IMAGE:固定 Chainlink 节点镜像,system-tests/lib/cre/environment/dons.go 在选择节点镜像时直接检查该变量。
并行执行(可选)
并行测试是显式开启的,设置环境变量即可:
CRE_TEST_PARALLEL_ENABLED=1注意冒烟套件并不会盲目地对所有用例开t.Parallel()——runner 在cre_suite_test.go中只对确定可以安全共存的场景启用并行。
创建自定义拓扑
当你想覆盖以下内容时,就需要创建自定义拓扑:
- limits;
- feature flags;
- capability 配置;
- DON 组成;
- 额外的数据源;
user_config_overrides。
工作流
- 从
core/scripts/cre/environment/configs/里挑一个最接近现有需求的拓扑; - 复制为同目录下的新文件;
- 只改场景需要的字段;
- 用
CTF_CONFIGS=<新拓扑>启动本地 CRE; - 先只跑相关测试。
示例:
cd core/scripts/cre/environment/configs cp workflow-gateway-capabilities-don.toml workflow-gateway-capabilities-don-my-override.toml然后启动并测试:
cd ../ CTF_CONFIGS=./configs/workflow-gateway-capabilities-don-my-override.toml go run . env startcd ../../../system-tests/tests TOPOLOGY_NAME=workflow-gateway-capabilities-my-override \ go test ./smoke/cre -timeout 20m -run '^Test_CRE_V2_Suite_Bucket_B$' -count=1 -v默认拓扑长什么样
理解默认拓扑是定制的基础。workflow-gateway-capabilities-don.toml(configs/workflow-gateway-capabilities-don.toml)是一个 multi-don 拓扑,包含 3 个 nodeset:
workflow:4 个节点,don_types = ["workflow"],capabilities 含cron、http-action、http-trigger、consensus、don-time、evm-1337,同时连接 1337/2337 两条 anvil 链(注释解释:即使不用 2337 上的 capability,bootstrap 节点上仍要创建 capability DON 的 bootstrap job);capabilities:4 个节点,don_types = ["capabilities"],exposes_remote_capabilities = true,capabilities 含vault、evm-2337(连接 1337 是为了用链上节点地址在 gateway 配置中标识节点,这是 vault 与 gateway 型 HTTP capability 的要求);bootstrap-gateway:1 个节点,don_types = ["bootstrap", "gateway"],override_mode = "each",通过custom_ports = ["5002:5002","15002:15002"]暴露 web API capabilities 端口(5002)与 vault 端口(15002)。
其他公共段包括[chip_router]、两条[[blockchains]](anvil 1337/2337)、[jd](Job Distributor 镜像与 CSA 加密密钥)、[fake]/[fake_http](mock 服务端口)、[infra](docker 或 kubernetes)。
仓库现有拓扑的全量清单可参考 core/scripts/cre/environment/docs/TOPOLOGIES.md(该文件由go run . topology generate自动生成),涵盖:
workflow-don-solana.toml(multi-don,3 DON)workflow-gateway-capabilities-multi-gateway-don.toml(multi-don,4 DON)workflow-gateway-don-aptos.toml(single-don,2 DON)workflow-gateway-don-cache-test.toml/workflow-gateway-don-cache-soak-test.tomlworkflow-gateway-don-grpc-source.tomlworkflow-gateway-don.toml(single-don,2 DON)workflow-gateway-sharded-5-dons.toml(sharded,7 DON)workflow-gateway-sharded-don.toml(sharded,3 DON)
快速查看清单可运行go run . topology list。
覆盖指南
制作自定义拓扑时的纪律(SKILL.md 原文要点):
- 保持 diff 小而目的明确;
- 优先复制最近似的拓扑,而不是从零新建;
- 使用能表明改动内容的描述性文件名;
- 除非测试需要,不要改动无关的镜像、链或 capability;
- 如果拓扑只用于一次性本地检查,保留在本地,避免加进 CI。
典型的覆盖点包括:
nodesets.capability_configs(capability 配置覆盖);nodesets.user_config_overrides(节点用户配置覆盖);- CRE feature flags;
- 额外的 mock 或支持服务端点。
capability_configs 的完整覆盖语义
仓库提供了一个专门讲解覆盖写法的示例拓扑 configs/examples/workflow-don-overrides.toml,其中对capability_configs的关键语义写得很清楚:
覆盖某个 capability 配置时,必须提供该 capability 的全部值——不支持部分覆盖。如果你指定了某个 key,整个
CapabilityConfig会原样使用,不会与默认值合并;默认值只对完全没有配置的 capability 生效。
示例(链级 EVM 覆盖,LogTriggerPollInterval以纳秒为单位):
[nodesets.capability_configs.evm-1337.values] LogTriggerPollInterval = 2500000000 # 2.5s in nanoseconds # 其他 capability 同样可覆盖,例如: # [nodesets.capability_configs.http-action] # binary_name = "http_action" # [nodesets.capability_configs.http-action.values] # IncomingGlobalBurst = 20user_config_overrides 的边界与写法
同一示例还演示了user_config_overrides的用法,并给出一个重要的实现约束:[Telemetry]、[Billing]、[Metering]是框架托管的段,会被框架拒绝(validateUserConfigOverrides,位于system-tests/lib),因为框架会自己生成这些配置,把遥测指向 chip-router 以便下游订阅者(如 CI test sink)看到全部事件。要启用 metering,应设置 nodeset 的enable_metering = true。
[[nodesets.node_specs]] roles = ["plugin"] # override_mode = "all" 时,DON 内所有节点都是 plugin 角色 [nodesets.node_specs.node] image = "chainlink-tmp:latest" user_config_overrides = """ [Log] Level = 'debug' JSONConsole = true # 删掉这段可以让工作流从远程源下载 [CRE.WorkflowFetcher] URL = "file:///home/chainlink/workflows" """重启与清理
干净重启
当改动拓扑或底层配置时,优先完整 stop/start,不要假设运行中的环境会自动收敛:
cd core/scripts/cre/environment go run . env stop -a CTF_CONFIGS=./configs/<topology>.toml go run . env start这也是 SKILL.md 故障排查的第一条:如果测试意外使用了错误的拓扑,停止 Local CRE 并按预期的CTF_CONFIGS重启。
用完后清理
cd core/scripts/cre/environment go run . env stop -a彻底重置
当保存的状态或缓存产物看起来不一致时,使用 purge:
go run . env state purgestate子命令组定义在 environment.go,包含list(列出环境中所有状态文件)与purge(清空所有状态与缓存文件)。Local CRE 把环境状态持久化到仓库本地的状态文件中,这正是冒烟测试 helper 能检测到已存在环境、避免重复创建的原因(详见 docs/local-cre/environment/index.md)。需要完全重置时,先 purge 状态,再重新 setup/start。
故障排除
SKILL.md 的四条速查
- 测试意外使用了错误拓扑→ 停止 Local CRE,按预期的
CTF_CONFIGS重启; - 套件似乎在复用陈旧状态→ 用
-count=1重跑; - 测试依赖日志、追踪或面板→ 执行
go run . obs up; - 拓扑相关的失败看似与测试无关→ 先确认环境确实是以预期拓扑启动的。
测试逻辑尚未执行就失败的清单
docs/local-cre/system-tests/running-tests.md 给出了"测试还没跑到测试逻辑就失败"时的五步检查:
- 确认
CTF_CONFIGS; - 确认 Local CRE 状态文件有效;
- 确认所需镜像存在;
- 重跑
go run . env setup; - 用 debug 日志重跑。
环境启动阶段的高频故障
docs/local-cre/environment/index.md 归纳了环境侧最常见的四类失败:
- Chainlink 节点数据库迁移失败;
- Docker 镜像找不到;
- Docker 无法下载所需公共镜像;
gh缺失或未认证(构建需要私有插件访问的镜像时必需)。
对应的处理顺序:重跑go run . env setup→ 确认镜像访问与认证 → 状态陈旧则 purge 状态 → 需要更多信号则带 observability 或 Chip Ingress 栈重启。
超时经验
实践中的超时经验(来自 docs/local-cre/system-tests/running-tests.md):
- 从源码构建镜像时,给约20 分钟的预算;
- 使用预构建镜像时运行时长会短得多。
深入参考
本文基于的 SKILL 文档还推荐了以下仓库内资料,供深入阅读:
- docs/local-cre/index.md:Local CRE 文档总览与导航;
- docs/local-cre/system-tests/index.md:CRE 系统测试的结构、smoke/regression 划分与 helper 衔接机制;
- docs/local-cre/system-tests/running-tests.md:本地、Kubernetes 与 CI 视角下的运行细节、环境变量与桶化选择;
- docs/local-cre/getting-started/index.md:从干净 checkout 到跑起第一个环境的最短路径;
- docs/local-cre/environment/index.md:环境生命周期命令、
env start全部 flag 与 Chip 端口布局; - core/scripts/cre/environment:环境 CLI 源码(
main.go命令注册、environment/生命周期实现、configs/拓扑目录); - system-tests/tests/smoke/cre:冒烟套件源码(
cre_suite_test.go桶入口、config/bucketing.go桶注册表)。
【免费下载链接】chainlinknode of the decentralized oracle network, bridging on and off-chain computation项目地址: https://gitcode.com/GitHub_Trending/ch/chainlink
创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考