news 2026/9/16 17:46:30

workerd 高级 .wd-test 配置实战:Durable Objects、多服务、网络访问与 TypeScript 测试

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
workerd 高级 .wd-test 配置实战:Durable Objects、多服务、网络访问与 TypeScript 测试

workerd 高级 .wd-test 配置实战:Durable Objects、多服务、网络访问与 TypeScript 测试

【免费下载链接】workerdThe JavaScript / Wasm runtime that powers Cloudflare Workers项目地址: https://gitcode.com/GitHub_Trending/wo/workerd

.wd-test是 workerd(Cloudflare Workers 的 JavaScript/Wasm 运行时)测试框架使用的 Cap'n Proto 配置文件格式,用于声明测试 Worker 及其依赖的服务、存储与网络环境。本文基于仓库中 advanced-configs.md 的完整内容,结合 workerd.capnp 的底层 schema 定义与 BUILD.bazel 的真实测试规则,系统讲解 Durable Objects、多服务通信、出站网络访问、外部服务对接与 TypeScript 测试这五类进阶配置模式。读完本文,你将能独立编写覆盖 DO 状态持久化、服务间 fetch 调用、socket/RPC 通信等复杂场景的.wd-test测试配置,并理解每项配置在运行时的真实语义。

一、.wd-test进阶配置概览

基础单服务测试只需要一个services列表、一个模块入口和若干compatibilityFlags;而进阶场景通常需要回答四类问题:

场景需要的配置要素对应 schema 类型
测试 Durable ObjectsdurableObjectNamespaces+durableObjectStorage+ 绑定DurableObjectNamespace(workerd.capnp)
多服务互相调用多个services条目 + service bindingService/ServiceDesignator(workerd.capnp)
测试 Worker 发起出站请求network服务 +allow规则Network(workerd.capnp)
对接 socket / 外部服务external服务条目ExternalServer(workerd.capnp)
用 TypeScript 编写测试.ts-wd-test配置文件构建系统自动编译

这些能力全部由 workerd.capnp 中的Workerd.Configschema 驱动:services是命名的服务列表,每个服务可以是 Worker、networkexternaldisk四种形态之一(见 Service 联合体定义),名称仅供本配置文件内部引用,除非显式配置绑定,否则服务之间互不可见。

二、Durable Objects 测试配置

2.1 基础配置:namespace、storage 与绑定

测试 Durable Objects 时,需要在 Worker 中定义 namespace 与存储,并配一个磁盘服务作为 DO 数据的落盘位置:

const unitTests :Workerd.Config = ( services = [ ( name = "do-test", worker = ( modules = [(name = "worker", esModule = embed "do-test.js")], compatibilityDate = "2024-01-01", durableObjectNamespaces = [ (className = "MyDurableObject", uniqueKey = "210bd0cbd803ef7883a1ee9d86cce06e"), ], durableObjectStorage = (localDisk = "TEST_TMPDIR"), bindings = [ (name = "MY_DO", durableObjectNamespace = "MyDurableObject"), ], ), ), # Disk service for DO storage (name = "TEST_TMPDIR", disk = (writable = true)), ], );

配置要点拆解:

  • className:实现 Durable Object 的导出类名,必须与 JS 模块中的export class MyDurableObject一致。
  • uniqueKey:唯一标识 namespace 的十六进制字符串。schema 注释明确说明"该字符串用于确保该类对象的标识符与其他一切地方都不冲突"(workerd.capnp),同时指出"只要uniqueKey保持不变,修改类名不会破坏与既有存储的兼容性"。测试场景下使用任意 32 字符十六进制串即可,关键是保证不同测试之间不重复。
  • durableObjectStorage:DO 状态存储位置。(localDisk = "TEST_TMPDIR")表示状态持久化到磁盘,"TEST_TMPDIR"必须是一个disk类型服务名。
  • 绑定bindings中的(name = "MY_DO", durableObjectNamespace = "MyDurableObject")让测试代码通过env.MY_DO拿到 namespace 并get()具体对象。

2.2 localDisk 与 inMemory:两种存储语义

如果测试不需要跨请求持久化,可以用内存存储替代磁盘:

durableObjectStorage = (inMemory = void),

两种模式在 workerd.capnp 中有明确语义:

  • inMemorystate.storageAPI 只存在内存中,数据在整个进程生命周期内有效,进程退出即丢失;单个对象空闲时仍会正常关闭,只有通过state.storage接口写入的数据才随进程存活。schema 注释明确标注"此模式面向本地测试目的"。
  • localDisk:DO 数据存储于本地磁盘目录,字段值是一个DiskDirectory服务名。对每个 DO 类,会以uniqueKey为名创建子目录,对象数据以<id>.<ext>命名存放,目前主存储文件后缀为.sqlite,特定情况下还会出现.sqlite-wal.sqlite-shm文件(对应 SQLite 的 WAL 机制)。该字段被标注为EXPERIMENTAL,可能发生不兼容变更

据此可以总结选型建议:单测追求隔离性与速度选inMemory;需要验证数据持久化、重启恢复等行为时选localDisk。另外注意 workerd.capnp 中的 TODO 注释:目前对象始终运行在单实例运行时上,尚不支持跨集群分布。

2.3 磁盘服务(DiskDirectory)说明

(name = "TEST_TMPDIR", disk = (writable = true))中的disk形态对应DiskDirectory(workerd.capnp):它把磁盘目录暴露为 HTTP 服务,支持基础的 GET/PUT,但 schema 注释强调它非常简陋,不猜测Content-Type,对目录的 GET 会返回 JSAN 格式的目录列表,通常不适合直接对外服务,一般要再包一层 Worker 补充元数据。在测试配置中它的职责就是给 DO 的localDisk存储提供一个可写目录。

三、多服务配置:通过 service binding 联调

3.1 多服务互相调用

测试中经常需要模拟"主 Worker 调用后端"的拓扑,此时只需在services中并列声明多个 Worker 服务,并在主 Worker 上用 service binding 指过去:

const unitTests :Workerd.Config = ( services = [ ( name = "main-test", worker = ( modules = [(name = "worker", esModule = embed "main-test.js")], compatibilityDate = "2024-01-01", bindings = [ (name = "BACKEND", service = "backend"), ], ), ), ( name = "backend", worker = ( modules = [(name = "worker", esModule = embed "backend.js")], compatibilityDate = "2024-01-01", ), ), ], );

测试 JS 中即可通过env.BACKEND.fetch('http://example.com/')触发对backend服务的调用(URL 的 host 在 service binding 场景下只作为占位符,请求总是路由到绑定指向的服务)。这正是 SKILL.md 中 bindings 章节所述"Service binding — env.OTHER_SERVICE is a fetch-able service"的落地形态。

service binding 还支持指定 entrypoint,例如(name = "MY_RPC", service = (name = "my-service", entrypoint = "MyClass")),用于访问另一个服务中特定导出类的 RPC 接口——这在 Durable Objects 与多服务 RPC 联测中很常见。

3.2 大型配置:用命名常量因子化 Worker

当配置变得庞大时,可以把每个 Worker 定义抽成顶层命名常量,services中只留一行引用,避免层层嵌套难以维护:

const unitTests :Workerd.Config = ( services = [ (name = "main", worker = .mainWorker), (name = "helper", worker = .helperWorker), ], ); const mainWorker :Workerd.Worker = ( modules = [(name = "worker", esModule = embed "main.js")], compatibilityDate = "2024-01-01", bindings = [(name = "HELPER", service = "helper")], ); const helperWorker :Workerd.Worker = ( modules = [(name = "worker", esModule = embed "helper.js")], compatibilityDate = "2024-01-01", );

worker = .mainWorker中的前导点号是 Cap'n Proto 的顶层作用域引用语法,指向同文件内定义的const mainWorker。这种写法让每个 Worker 的模块、兼容性与绑定一目了然,也便于多个测试常量复用同一份 Worker 定义。

四、出站网络访问:Network 服务

4.1 基础配置

需要测试 Worker 发起真实出站请求时,声明一个network类型的服务,并在 Worker 中通过 service binding 或全局出站配置引用它:

( name = "internet", network = ( allow = ["private"], tlsOptions = ( trustedCertificates = [ embed "test-cert.pem", ], ), ) ),

allow可取["private"](回环 / 局域网)或["public"](公网),绝大多数测试使用"private"

4.2 allow/deny 的底层语义

workerd.capnp 对Network给出了精确的访问控制语义,这是理解配置行为的关键:

  • allowdeny都是 CIDR 记法(IPv4 与 IPv6 皆可)的列表,如"192.0.2.0/24""2001:db8::/32";流量放行的条件是:地址命中 allow 列表至少一项,且不命中 deny 列表任何一项
  • 除 CIDR 外还支持四个特殊字符串:
    • "private":匹配标准保留的私网地址,如10.0.0.0/8192.168.0.0/16,是"local"的超集;
    • "public""private"的反面;
    • "local":匹配仅本机可访问的地址,如127.0.0.0/8或 Unix 域套接字;
    • "network""local"的反面。
  • allow的默认值是["public"]:默认只允许访问公网可路由地址,正是为了防止 SSRF。schema 注释建议优先使用ExternalServer绑定来精确放行特定后端,而不是放开整段内网。

因此allow = ["private"]意味着测试 Worker 的fetch()可以打到本机回环与局域网服务(例如测试期间由测试 harness 在本地启动的 mock 服务)。

4.3 TLS 信任配置

tlsOptions.trustedCertificatesembed内嵌 PEM 证书,使 Worker 在发起 TLS 连接时信任测试用自签名证书——适用于测试 HTTPS 后端。embedmodules中内嵌文件语义一致:构建期把文件内容直接写入配置。

五、外部服务:socket 与 RPC 通信

对于基于 socket 的 RPC 或与外部服务通信的测试,使用external形态的服务:

( name = "my-external", external = ( address = "loopback:my-external", http = (capnpConnectHost = "cappy") ) ),

ExternalServer在 workerd.capnp 中的语义是:把来自绑定的所有fetch()请求无条件转发到指定服务器,无论 URL 中的 hostname 或协议是否与真实服务器匹配——这正是反向代理的典型用法,后端通常没有真实公网主机名,只能通过代理访问,且转发后请求保留原始 host。address = "loopback:my-external"使用loopback:前缀指定一个本地 Unix 域套接字地址,http.capnpConnectHost则用于配置 Cap'n Proto RPC 连接时的目标 host 名(例如"cappy"),从而在测试中模拟经 socket 通信的 RPC 服务。此类配置常与 sample 目录中的 RPC 示例(如 samples/extensions 的 binding/RPC 模式)配合理解。

六、TypeScript 测试:.ts-wd-test

6.1 配置与构建规则

TypeScript 测试的配置文件使用.ts-wd-test扩展名,但embed的模块必须是编译后的.js产物

配置文件(my-test.ts-wd-test):

using Workerd = import "/workerd/workerd.capnp"; const unitTests :Workerd.Config = ( services = [( name = "my-test", worker = ( modules = [(name = "worker", esModule = embed "my-test.js")], compatibilityDate = "2024-01-01", ), )], );

BUILD.bazel 中引用.ts源文件:

wd_test( src = "my-test.ts-wd-test", args = ["--experimental"], data = ["my-test.ts"], )

构建系统会把data中的.ts源码自动编译为.js,供配置文件中embed "my-test.js"使用。仓库内 src/workerd/api/tests/BUILD.bazel 是.ts-wd-test的实际使用处,可作为参考。

6.2 与普通.wd-test的差异

维度普通测试TypeScript 测试
配置扩展名my-test.wd-testmy-test.ts-wd-test
src指向.wd-test配置文件.ts-wd-test配置文件
data内容.js测试文件与 fixture.ts源文件(构建期自动编译)
embed 的模块my-test.js编译产物my-test.js(仍写.js

无论哪种形式,测试 JS/TS 的结构一致:每个具名导出对象含test()方法即是一个用例,异步用例的签名是async test(ctrl, env),其中env携带.wd-test配置中的所有 bindings(详见 SKILL.md)。

七、把进阶配置跑起来:BUILD.bazel 与运行命令

7.1 标准 wd_test 规则形态

仓库中真实测试规则的典型写法(见 src/workerd/api/tests/BUILD.bazel):

wd_test( src = "stdio-writesync-reentry-uaf-test.wd-test", args = ["--experimental"], data = ["stdio-writesync-reentry-uaf-test.js"], )
  • src.wd-test(或.ts-wd-test)配置文件;
  • args = ["--experimental"]:启用实验特性所必需;
  • data:测试 JS/TS 文件与 fixture(如fixtures/cert.pemfixtures/key.pem)。

7.2 三种自动生成的测试变体

每个wd_test()会自动生成三个变体(见 SKILL.md),分别覆盖不同的兼容性配置:

目标后缀兼容日期说明
@2000-01-01默认变体,使用最老的兼容日期
@all-compat-flags2999-12-31启用全部兼容标志
@all-autogates2000-01-01启用全部自动门控

运行特定变体:

just stream-test //src/workerd/api/tests:my-test@ just stream-test //src/workerd/api/tests:my-test@all-compat-flags

编写包含 Durable Objects 或多服务的进阶配置时,建议至少把@all-compat-flags变体跑一遍,验证配置在各兼容标志组合下均不失效。

7.3 脚手架命令

just new-test可以自动生成新测试的三件套——.wd-test配置、.js测试文件,并把wd_test()规则追加到对应BUILD.bazel

just new-test //src/workerd/api/tests:my-test

生成后再按本文的进阶模式补充 DO、多服务、网络等配置即可。

八、进阶配置速查与自检清单

编写高级.wd-test配置时,建议逐项自检:

  1. Durable ObjectsuniqueKey是否为全局唯一的 32 字符十六进制串?存储选择inMemory(进程内、易失)还是localDisk(落盘 SQLite、需配套disk服务)?绑定名是否与 JS 中env.MY_DO一致?
  2. 多服务:所有services条目是否有唯一name?service binding 指向的服务名是否拼写一致?大配置是否已用顶层const常量因子化?
  3. 网络访问allow是否收窄到测试所需的最小范围(通常["private"])?是否误用了默认的["public"]?是否需要deny进一步收紧、是否需要tlsOptions.trustedCertificates信任自签证书?
  4. 外部服务external.address的 socket 地址与capnpConnectHost是否正确对应测试 harness 启动的 mock 服务?
  5. TypeScript:配置扩展名是否为.ts-wd-testembed是否指向编译产物.jsBUILD.bazeldata是否列出了.ts源文件?
  6. 运行wd_test()是否带args = ["--experimental"]?三个自动变体(@@all-compat-flags@all-autogates)是否都通过?

掌握上述模式后,你便可以在 workerd 仓库中编写覆盖 Durable Objects 持久化、服务间 RPC、真实出站请求与 TypeScript 场景的高质量测试——其背后每一处语义(存储模式、SSRF 防护、请求转发规则)都能在 workerd.capnp 中找到对应注释作为依据。

【免费下载链接】workerdThe JavaScript / Wasm runtime that powers Cloudflare Workers项目地址: https://gitcode.com/GitHub_Trending/wo/workerd

创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考

版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/9/16 17:45:01

52单片机无源蜂鸣器音乐播放实现原理与工程实践

简介&#xff1a;本资源是一套面向嵌入式专业本科生的毕业设计完整实现方案&#xff0c;聚焦室内智能园艺场景&#xff0c;基于STC89C52单片机开发全自动浇花系统&#xff0c;涵盖硬件控制、传感器采集、蜂鸣器报警与CX9音乐播放功能&#xff0c;适合作为课程设计、毕设选题及单…

作者头像 李华
网站建设 2026/9/16 17:44:26

从复位到main():STM32链接脚本与启动文件全解析

很多用 CubeMX 的兄弟&#xff0c;点一下生成就能得到一套能跑的工程&#xff0c;从来没想过一个问题&#xff1a;复位之后&#xff0c;CPU 是怎么一步步走到main()的&#xff1f;又是谁告诉链接器把代码放 Flash、把全局变量放 RAM 的&#xff1f;我自己也是在第一次做 IAP Bo…

作者头像 李华
网站建设 2026/9/16 17:44:13

TinyMCE 5.10.3 集成 PowerPaste 实战:解决 Word 粘贴排版错乱

简介&#xff1a;面向TinyMCE 5.10.3的PowerPaste插件资源包&#xff0c;专为需要从Word、Excel等文档复制内容至在线编辑器的开发者准备&#xff0c;解决粘贴后样式丢失、排版错乱等痛点。压缩包仅117KB&#xff0c;共5个文件&#xff0c;包含3个JavaScript脚本&#xff08;主…

作者头像 李华
网站建设 2026/9/16 17:39:06

OptiScaler:换超分,中端卡拿到高端帧率

OptiScaler&#xff1a;换超分&#xff0c;中端卡拿到高端帧率 【免费下载链接】OptiScaler OptiScaler bridges upscaling/frame gen across GPUs. Supports DLSS2/XeSS/FSR2 inputs, replaces native upscalers, enables FSR-FG/XeFG on non-FG titles. Supports Nukem mod f…

作者头像 李华
网站建设 2026/9/16 17:38:47

WebView文字选择改造:ActionMode拦截与JSBridge交互实践

简介&#xff1a;面向Android开发者的一套开源源码包&#xff0c;针对WebView组件在网页浏览场景中文字选取范围受限、操作菜单单一的问题&#xff0c;给出了较为完整的增强方案。通过自定义选择器与JavaScript接口&#xff0c;开发者可实现连续或非连续文本的多选&#xff0c;…

作者头像 李华
网站建设 2026/9/16 17:37:42

三相异步电动机MATLAB仿真:从dq建模到SPWM调速

简介&#xff1a;这是一套面向电机控制与电力电子方向学习者的三相异步电动机Matlab/Simulink仿真资源&#xff0c;覆盖异步电机起动、制动、调速、发电机运行及不同坐标系下的仿真建模&#xff0c;适合正在学习电机拖动、从事变频调速研究或进行课程设计的新手与中级开发人员对…

作者头像 李华