Wing 云服务(cloud.Service)在模拟器中的令牌(Token)绑定与端到端测试
编程语言编译器云原生语言运行时【免费下载链接】wingA programming language for the cloud ☁️ A unified programming model, combining infrastructure and runtime code into one language ⚡项目地址https://gitcode.com/gh_mirrors/wi/wing点击查看免费下载cloud.Service是 Wing 标准库中用于定义长运行服务的核心资源而“令牌Token”则是 Wing 在编译期无法解析、必须到运行时才能确定的值例如 API 的 URL。本文以 tools/hangar/snapshots/test_corpus/sdk_tests/service/tokens.test.w_test_sim.md 这份 Hangar 测试快照为核心线索深入拆解 Wing 的 Service 资源如何在sim模拟器目标下自动“绑定并使用令牌”并还原其背后cloud.Service、util.waitUntil、令牌解析机制与 Sandbox 沙箱进程的完整实现链路。一、这份快照文档到底在记录什么先看这份快照的完整原文# [tokens.test.w](https://link.gitcode.com/i/8edfcd4c0a5d1b33a81f7d15f21488bd) | test | sim ## stdout.log log pass ─ tokens.test.wsim » root/Default/test:will bind and use tokens Tests 1 passed (1) Snapshots 1 skipped Test Files 1 passed (1) Duration DURATION它由三部分构成 1. **标题行**tokens.test.w | test | sim指明被测源文件是仓库中的 [tests/sdk_tests/service/tokens.test.w](https://link.gitcode.com/i/08063e2d2c1326fafffc4e967c0c663a)执行方式是 wing test目标平台是 sim。 2. **stdout.log 代码块**记录了该测试在模拟器中的标准输出。核心一行是 pass ─ tokens.test.wsim » root/Default/test:will bind and use tokens表示名为 “will bind and use tokens” 的测试用例**通过pass**。 3. **统计信息**Tests 1 passed (1)、Snapshots 1 skipped、Test Files 1 passed (1)、Duration DURATION。其中 Duration 被替换为占位符 DURATION这是 Hangar 快照“规范化sanitize”机制的产物。 ### 快照的生成机制 这份快照不是手写的而是由 [tools/hangar/src/utils.ts](https://link.gitcode.com/i/5856c7ff44000d5500ede71577b634df) 中的 createMarkdownSnapshot() 函数自动生成的 ts const snapPath join( snapshotDir, test_corpus, dirname(relativePath), ${wingFile}_${testCase}_${target}.md ); let md # ${wingFile}}/${wingFile}) | ${testCase} | ${target}\n\n;它会把运行结果按test_corpus/目录/文件名_用例_目标.md的约定落到快照目录并在标题中内嵌指向源码文件的相对链接——这就是快照第一行../../../../../../tests/sdk_tests/service/tokens.test.w的来源。由于快照生成时会对输出做规范化处理见下真正的测试文件位于tests/sdk_tests/service/目录读者应前往该目录查看被测代码原文。DURATION占位符与输出的确定性Hangar 为了保证快照跨平台、跨机器稳定可比在 sanitizeOutput() 中做了一系列输出清洗统一换行符、把 Windows 反斜杠替换为正斜杠去掉 Rust 源码中的行列号src/xxx.rs:LINE:COL、绝对堆栈路径把Duration 1m12.3s这类耗时统一替换为Duration DURATION端口号、IP 地址、时间戳等易变内容分别替换为PORT、IP:PORT、TIMESTAMP。这就是快照中Duration DURATION的由来只有耗时被抹平测试断言本身pass/失败才具备稳定的可比较价值。二、被测源码Service 如何“绑定并使用令牌”快照指向的被测文件是 tests/sdk_tests/service/tokens.test.w其完整内容如下bring cloud; bring util; bring http; // only supported in the sim target for now if target sim { let b new cloud.Bucket(); let api new cloud.Api(); api.get(/, inflight () { return { body: api test, status: 200 }; }); let s new cloud.Service(inflight () { let result http.get(api.url); b.put(service.txt, result.body); }); test will bind and use tokens { util.waitUntil(inflight () { return b.exists(service.txt); }); assert(b.get(service.txt) api test); } }这段代码包含了三个互相咬合的关键点target sim条件编译文件开头就明确注明“目前仅sim目标支持only supported in the sim target for now”所以整个测试体被包在目标判断里只有以-t sim运行时才会生效。Service 的 inflight handler 中使用api.urlapi.url是一个典型的令牌token——API 的真实地址只有在模拟器启动、端口分配之后才能确定编译期无法知晓。Service 在启动时执行http.get(api.url)并把响应体写入 Bucket。测试用例本身不直接“驱动” Servicetest will bind and use tokens只是用util.waitUntil轮询 Bucket 里是否出现了service.txt一旦出现就断言其内容等于api test。Service 是自动启动autoStart 默认 true并在后台运行的测试靠“轮询结果”来验证整条链路是否打通。这正是测试名 “will bind and use tokens” 的含义Service 的 inflight 代码“绑定”了api.url这个令牌并在运行时“使用”它成功发起了 HTTP 请求。为什么要用 waitUntil 轮询而不是直接断言因为 Service 的 handler 是异步、后台执行的测试无法预知它何时完成第一次 HTTP 请求与 Bucket 写入。util.waitUntil提供了确定性的等待语义。它的实现在 packages/winglang/sdk/src/util/util.ts 的Util.waitUntil静态方法中public static async waitUntil( predicate: IPredicateHandler, props: WaitUntilProps {}, ): Promiseboolean { const timeout props.timeout ?? Duration.fromMinutes(1); const interval props.interval ?? Duration.fromSeconds(0.1); const f predicate as any; let elapsed 0; while (elapsed timeout.seconds) { if (await f()) { return true; } elapsed interval.seconds; await this.sleep(interval); } if (props.throws ! false) { throw new Error(Timeout elapsed); } return false; }其行为要点对应 WaitUntilProps 接口参数默认值说明timeout1 分钟轮询总超时超过后抛出Timeout elapsed错误interval0.1 秒两次轮询之间的间隔throwstrue超时后是否抛错传false则改为返回布尔值实现上注意超时统计只累加间隔时长不把谓词本身的执行耗时计入源码注释明确提到这一点因此谓词应保持轻量。测试中谓词b.exists(service.txt)刚好是这种轻量检查。三、令牌机制编译期无法解析的值运行时才落地“绑定并使用令牌”的底层支撑是 Wing SDK 的令牌解析器Token Resolver体系定义在 packages/winglang/sdk/src/core/tokens.tsexport interface ITokenResolver { isToken(value: any): boolean; // 判断一个值是否为令牌 lift(value: any): string; // 把一个令牌提升到 inflight 上下文 onLiftValue(host: IInflightHost, value: any): void; // 把令牌绑定到宿主宿主即 Function/Service 等 inflight host }其设计思路源码注释原话“Tokens values are captured as environment variable, and resolved through the compilation target token mechanism.”——令牌值会被“捕获”为环境变量再通过各编译目标的令牌机制解析。环境变量名由 tokenEnvName() 生成export function tokenEnvName(value: string): string { return WING_TOKEN_${value .replace(/([^a-zA-Z0-9])/g, _) .replace(/_$/, ) .replace(/^_/, ) .toUpperCase()}; }即把令牌字符串中非字母数字的字符替换为下划线并转大写前缀WING_TOKEN_。sim 目标如何解析令牌针对本快照使用的sim目标令牌解析器实现在 packages/winglang/sdk/src/target-sim/tokens.ts 的SimTokens类中isToken对字符串值用SIMULATOR_TOKEN_REGEX正则判断是否是模拟器令牌lift把令牌提升为运行时表达式process.env[WING_TOKEN_...]即从进程环境变量读取onLiftValue把令牌以WING_TOKEN_规范化名为键写入宿主的addEnvironment让 inflight 代码在子进程里能通过环境变量拿到真实值。对照而言Terraform 类目标如tf-aws在 packages/winglang/sdk/src/shared-tf/tokens.ts 中走另一条路令牌本质是 CDKTF 的未解析 Tokenlift生成JSON.parse(process.env[WING_TOKEN_...])onLiftValue则用Fn.jsonencode(value)把值编码成环境变量注入宿主当前实现限定宿主必须是Function。这正好呼应了测试文件里那句“目前仅 sim 目标支持”的注释——令牌绑定到 Service 宿主的路径在不同目标下能力并不一致。四、Service 的绑定链路从 inflight 代码到模拟器沙箱抽象基类 cloud.Servicepackages/winglang/sdk/src/cloud/service.ts 定义了cloud.Service的抽象契约构造签名new cloud.Service(handler: IServiceHandler, props?: ServiceProps)ServiceProps两个可选字段env环境变量默认无与autoStart是否自动启动默认true——这正是测试用例里 Service 后台自动运行的来源inflight 接口IServiceClient提供三个方法start()、stop()、started()。抽象基类的_preSynthesize()service.ts#L113-L144会生成服务入口代码并写入workdir下的assetName.cjs文件同时执行关键的一步Lifting.lift(this.handler, this, [handle]);即把 handler 的 inflight “handle” 方法提升到 Service 宿主上——测试中api.url令牌之所以能被“绑定”到 Service就是通过这套 lift 机制把令牌值写入 Service 的环境变量。模拟器目标 Servicepackages/winglang/sdk/src/target-sim/service.ts 是 sim 目标下的具体实现它把绑定结果转成模拟器资源描述const props: ServiceSchema { environmentVariables: this.env, sourceCodeFile: relative(App.of(this).outdir, this.entrypoint), autoStart: this.autoStart, }; return { type: cloud.SERVICE_FQN, props, policy, };environmentVariables正是SimTokens.onLiftValue写入的那些WING_TOKEN_*环境变量schema 定义见 target-sim/schema-resources.ts#L78-L85。模拟器运行时Sandbox 子进程packages/winglang/sdk/src/target-sim/service.inflight.ts 负责真正的运行时行为init()若autoStart为 true则立刻调用start()——这是测试中 Service 在后台自动跑起来的直接原因start()创建Sandbox子进程packages/winglang/sdk/src/shared/sandbox.ts并把环境变量连同WING_SIMULATOR_URL、WING_SIMULATOR_CALLER注入子进程然后调用沙箱的start入口stop()/started()对应停止与状态查询cleanup()测试结束、模拟器回收资源时调用stop()做清理。Sandbox 的核心机制sandbox.ts#L218-L323 的call()是父进程通过child_process.fork()拉起一个 Node 子进程把{ fn, args }消息发过去子进程执行exportsfn后回传{ type: ok, value }或{ type: error, reason }若调用超时默认无超时除非显式传入timeout或进程异常退出则杀死子进程并拒绝 Promise。于是整条链路闭环了api.url编译期令牌 └─ SimTokens.onLiftValue → WING_TOKEN_* 环境变量写入 Service └─ Service.toSimulator → ServiceSchema.environmentVariables └─ service.inflight.ts start() → Sandbox 子进程注入 env └─ inflight handler 中 http.get(process.env[WING_TOKEN_...]) └─ 请求模拟器内 API → 写入 Bucket → waitUntil 轮询命中 → 断言通过五、从快照回推 Hangar 测试运行器Hangartools/hangar是 Wing 仓库的测试运行器它把tests/sdk_tests/**/*.test.w等语料跑在多个目标上并生成上述快照。以错误用例为例tools/hangar/src/error.test.ts 展示了通用运行模式const platforms [sim]; const args [test]; const out await runWingCommand({ cwd: tmpDir, wingFile: relativeWingFile, platforms, args, expectFailure: true, });底层通过 runWingCommand() 调用 wing CLIconst out await execa( wingBin, [ --no-update-check, --no-analytics, ...options.args, // 即 [test] options.wingFile ?? , // 被测 .w 文件 ...platformOptions, // 即 [-t, sim] ], ... );也就是说执行tokens.test.w的快照对应命令等价于wing --no-update-check --no-analytics test tests/sdk_tests/service/tokens.test.w -t sim而Test Files 1 passed (1)这类汇总行就是wing test在模拟器目标下的测试框架输出Snapshots 1 skipped表示快照比对跳过由 Hangar 的快照策略控制Tests 1 passed (1)则确认用例本身全部通过。读者如需复现可在本仓库根目录安装依赖后对上述wing命令自行验证命令基于 utils.ts 中wingBin解析出的本地 CLI 路径。六、可迁移的实战要点这份快照连同其测试代码为在 Wing 中编写“Service 异步执行 令牌依赖”的用例提供了可直接迁移的范式令牌依赖要放到运行时验证像api.url、资源 ARN 这类编译期未知的值正确姿势是让 inflight 代码“绑定”它再用端到端断言验证运行时行为——测试名 “will bind and use tokens” 本身就是这个意图的注释。异步结果用util.waitUntil收敛后台进程的产物本例是 Bucket 文件不应靠固定sleep等待而应轮询直到出现或超时记得throws默认会在超时抛错适合测试环境直接使用。目标差异要显式声明测试文件用if target sim圈定适用范围并注释说明当前能力边界令牌绑定到 Service 目前仅 sim 目标支持这对多目标仓库的用例组织是一个很好的参照。快照输出应可复现任何 CI 化的快照都应像 Hangar 一样抹平耗时、端口、绝对路径等易变信息DURATION、PORT、ABSOLUTE否则快照会因机器差异频繁误报。需要进一步研究时建议按以下路径深入仓库被测源码tests/sdk_tests/service/tokens.test.w同目录另有 callbacks.test.w、http-server.test.w 等 Service 相关用例可对比Service 抽象契约与 API 文档cloud/service.ts、docs/api/04-standard-library/cloud/service.mdsim 目标实现与沙箱target-sim/service.inflight.ts、shared/sandbox.ts令牌解析器core/tokens.ts、target-sim/tokens.ts、shared-tf/tokens.ts快照生成与运行器tools/hangar/src/utils.ts、tools/hangar/src/error.test.ts。赞分享编程语言编译器云原生语言运行时【免费下载链接】wingA programming language for the cloud ☁️ A unified programming model, combining infrastructure and runtime code into one language ⚡项目地址https://gitcode.com/gh_mirrors/wi/wing点击查看免费下载相关推荐Wing 语言内置测试框架用 wing test 在模拟器与真实云端运行同一套测试Wing 语言内置测试框架用 wing test 在模拟器与真实云端运行同一套测试 Wing 是一门面向云的一体化编程语言其内置的轻量级测试框架围绕 win编程语言编译器云原生语言运行时Wing 语言中的 cloud.Service用 Winglang 定义与管理云上长时运行服务Wing 语言中的 cloud.Service用 Winglang 定义与管理云上长时运行服务 cloud.Service 是 Wing 标准库Wing S编程语言编译器云原生语言运行时Wing 模拟器容器测试全解从 sim.Container 到 hangar 快照的端到端验证Wing 模拟器容器测试全解从 sim.Container 到 hangar 快照的端到端验证 本文围绕 Wing 仓库中 sim.Container 资源在编程语言编译器云原生语言运行时上一篇精通 React 中的 Material UI Select从基础用法到表单集成与高级定制的完整实战指南下一篇使用 dyn Trait 在 Rust 中构建异构数据集合comprehensive-rust 动态分发实战指南创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考

相关新闻

大模型之LangGraph多轮对话记忆

大模型之LangGraph多轮对话记忆

用 LangGraph 的 Reducer,轻松搞定多轮对话记忆 做聊天机器人最头疼的是什么?是记不住上文。今天分享一个 LangGraph 的小技巧:用 Reducer 机制优雅地管理对话历史。 核心只有一行代码: messages: Annotated[Sequence[AnyMessa…

2026/10/14 3:07:32 阅读更多 →
免费三步:老 Mac 升级最新 macOS

免费三步:老 Mac 升级最新 macOS

免费三步:老 Mac 升级最新 macOS 【免费下载链接】OpenCore-Legacy-Patcher Experience macOS just like before 项目地址: https://gitcode.com/GitHub_Trending/op/OpenCore-Legacy-Patcher 一台 2015 年的 MacBook Pro,App Store 早就不给推送…

2026/10/14 3:07:32 阅读更多 →
PySide2工具栏与状态栏实战:QToolBar和QStatusBar高效开发指南

PySide2工具栏与状态栏实战:QToolBar和QStatusBar高效开发指南

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

2026/10/14 3:06:32 阅读更多 →

最新新闻

一张图微调YOLOv11:自然栖息地鸟类检测的流程与扩充

一张图微调YOLOv11:自然栖息地鸟类检测的流程与扩充

简介:面向 YOLOv11 模型验证需求,这份精简版鸟类目标检测数据集包含一张真实野外鸟类图像及配套标准标注,可用于快速原型验证、轻量级部署测试与小样本检测基线建立。压缩包共五个文件,包含三张 JPG 图像、一个数据配置文件与一个…

2026/10/14 3:39:38 阅读更多 →
ASP.NET + SQLServer葡萄酒商城源码:从数据库还原到下单事务全攻略

ASP.NET + SQLServer葡萄酒商城源码:从数据库还原到下单事务全攻略

简介:一套基于ASP.NET与SQL Server的葡萄酒网上商城销售系统,面向ASP.NET WebForm学习者、毕业设计学生以及需要搭建在线商城教学演示的开发者。系统围绕普通会员、商户会员和管理员三类角色展开,覆盖商品管理、购物车、订单处理、发货、商户…

2026/10/14 3:39:38 阅读更多 →
LangChain项目代码拆解:Chain、Agent、Memory与Retrieval四大核心组件实战指南

LangChain项目代码拆解:Chain、Agent、Memory与Retrieval四大核心组件实战指南

简介:这是一份LangChain入门与实践的项目代码包,面向正在学习大模型应用开发的Python开发者,旨在帮助读者快速理解LangChain的模块化设计与核心用法。包内共3个文件,包含一个HTML格式的入门讲解页、一个项目运行配置文件以及一个版…

2026/10/14 3:39:38 阅读更多 →
C++学习日记 Day21:C++11(下)lambda表达式和function包装器

C++学习日记 Day21:C++11(下)lambda表达式和function包装器

## 今天学了什么今天学习C11的lambda表达式和function包装器。## 可调用对象概念:在C中有一类对象可像函数一样调用;分类:①函数指针using prt void(*)(int, string); prt f1 fun; f1(1, "函数指针");②仿函数 --有 operator&am…

2026/10/14 3:39:38 阅读更多 →
一人公司AI工作流:6步实现内容生产去体力化

一人公司AI工作流:6步实现内容生产去体力化

1. 一人公司的内容困局与破局思路一个人做内容,最怕的不是没灵感,而是灵感来了却卡在“执行”上。写一篇长文要三小时,做一张配图要半小时,剪一条短视频要一整个下午,排版发布又要来回切换四五个平台。一天下来&#x…

2026/10/14 3:39:38 阅读更多 →
8765平台前后摄DVDD电压不一致排查与修复指南

8765平台前后摄DVDD电压不一致排查与修复指南

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

2026/10/14 3:38:38 阅读更多 →

日新闻

AnyPS5通用适配层设计:兼容性与性能的工程取舍

AnyPS5通用适配层设计:兼容性与性能的工程取舍

1. 从"AnyPS5"这个名字说起:它到底想解决什么问题第一次看到"AnyPS5"这个标题,我脑子里冒出来的第一个念头是:这大概率是一个围绕"跨平台运行"或者"通用适配"做文章的项目。名字里的"Any"…

2026/10/14 0:00:41 阅读更多 →
Flutter跨平台开发实战:二手交易应用与HarmonyOS适配

Flutter跨平台开发实战:二手交易应用与HarmonyOS适配

1. 项目概述:Flutter跨平台二手交易应用开发作为一名长期从事移动应用开发的工程师,我最近完成了一个基于Flutter框架的二手物品交易平台项目。这个项目最吸引我的地方在于它完美结合了Flutter的跨平台优势与HarmonyOS的生态特性,实现了"…

2026/10/14 0:00:41 阅读更多 →
DFS算法解决飞机降落调度问题实战

DFS算法解决飞机降落调度问题实战

1. 项目背景与核心思路飞机降落问题是一个经典的调度优化场景,也是算法竞赛和面试中的高频题目。这个题目要求我们合理安排多架飞机的降落顺序和时间,确保所有飞机都能安全着陆而不发生冲突。在实际航空管制中,这类问题直接关系到飞行安全和机…

2026/10/14 0:00:41 阅读更多 →

周新闻

流感时间序列预测实战:ARIMA/LSTM全流程拆解与避坑指南

流感时间序列预测实战:ARIMA/LSTM全流程拆解与避坑指南

简介:基于 ARIMA、LSTM、Transformer 等模型的流感时间序列预测 Python 源码,面向计算机相关专业课程设计与期末大作业学生,以及项目实战学习者。内容覆盖预处理、平稳性检验、定阶、残差分析、多模型对比预测的完整时序建模流程,…

2026/10/14 3:30:28 阅读更多 →
影刀RPA新手教程:键盘模拟输入实战——输入文本与模拟按键的区别

影刀RPA新手教程:键盘模拟输入实战——输入文本与模拟按键的区别

影刀RPA新手教程:键盘模拟输入实战——输入文本与模拟按键的区别 做影刀RPA自动化,十个新手有八个栽在"往输入框里填东西"这件事上:要么填不进去,要么填了一半,要么直接把原来内容追加在后面。这背后的根因&…

2026/10/13 16:22:04 阅读更多 →
影刀RPA新手教程:阅文起点小说数据采集实战——书籍信息与章节内容

影刀RPA新手教程:阅文起点小说数据采集实战——书籍信息与章节内容

影刀RPA新手教程:阅文起点小说数据采集实战——书籍信息与章节内容 1. 认识影刀:什么场景该用RPA采小说数据 起点中文网的页面结构相对稳定——分类榜单、书籍详情、章节内容三块独立页面,跳转链路清晰。这种场景非常适合影刀自动化&#x…

2026/10/14 3:29:58 阅读更多 →

月新闻

我发现了一个新思路:用 Remotion + Claude Code 像写代码一样自动化生成短视频

我发现了一个新思路:用 Remotion + Claude Code 像写代码一样自动化生成短视频

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

2026/10/13 22:01:27 阅读更多 →
Windows下 Codex 中 Chrome 和 Computer Use 插件不可用问题排查及解决参考方式:TaoToken 统一 Key 配置与验证

Windows下 Codex 中 Chrome 和 Computer Use 插件不可用问题排查及解决参考方式:TaoToken 统一 Key 配置与验证

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

2026/10/13 14:57:39 阅读更多 →
黑夜航拍船只数据集训练YOLOV5模型全流程解析

黑夜航拍船只数据集训练YOLOV5模型全流程解析

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

2026/10/12 18:11:17 阅读更多 →