Freebuff CLI 端到端测试实战:基于 tmux 与 Codebuff SDK 的双层测试体系

发布时间:2026/9/15 21:58:42

Freebuff CLI 端到端测试实战:基于 tmux 与 Codebuff SDK 的双层测试体系 Freebuff CLI 端到端测试实战基于 tmux 与 Codebuff SDK 的双层测试体系【免费下载链接】freebuffThe free coding agent项目地址: https://gitcode.com/GitHub_Trending/cod/freebuff本文档是 Freebuff 开源仓库中 CLI 端到端E2E测试体系的完整技术指南。它围绕 freebuff/e2e/README.md 展开详细讲解如何通过 tmux 驱动编译产物进行确定性断言如何使用 Codebuff SDK 让 AI 测试代理自动验证复杂行为以及如何对生产后端执行真实一轮对话的冒烟测试。读完本文你将掌握 Freebuff E2E 测试的完整架构、核心工具类用法、构建运行流程并能够按既有规范新增一条端到端测试。为什么 CLI 需要端到端测试Freebuff 是一个终端交互的编码代理 CLIThe free coding agent其核心体验全部发生在 TUI终端用户界面之中启动时的 ASCII 启动画面、模型选择器、/help等斜杠命令、流式对话输出。单元测试可以覆盖内部逻辑却无法回答编译出的二进制在真实终端里能不能正常启动、按键是否被正确捕获、输出是否如期渲染这类问题。freebuff/e2e/README.md 给出的答案是用 tmux 模拟真实终端会话让测试代码像真实用户一样与编译后的二进制交互——发送文本、发送按键、抓取屏幕输出、断言行为——从而验证 CLI 的端到端正确性。整个 E2E 测试目录结构如下freebuff/e2e/ ├── README.md ├── agent/ │ └── freebuff-tester.ts # SDK 测试代理定义 ├── tests/ # 各特性 E2E 测试 │ ├── ads-behavior.e2e.test.ts │ ├── agent-startup.e2e.test.ts │ ├── code-edit.e2e.test.ts │ ├── help-command.e2e.test.ts │ ├── knowledge-file.e2e.test.ts │ ├── live-turn.e2e.test.ts # 唯一的线上冒烟测试 │ ├── slash-commands.e2e.test.ts │ ├── startup.e2e.test.ts │ ├── terminal-command.e2e.test.ts │ └── version.e2e.test.ts └── utils/ ├── binary-helpers.ts # 二进制路径解析 ├── freebuff-session.ts # 核心会话封装类 ├── index.ts # 统一导出 ├── tmux-custom-tools.ts # SDK 自定义工具 └── tmux-helpers.ts # tmux 脚本底层封装测试架构三种互补的验证方式根据 README 的定义这套体系同时支持三种测试方式覆盖从快速确定性回归到真实后端链路的完整梯度方式核心机制适用场景1. 直接 tmux 测试用FreebuffSession类在 tmux 中启动二进制、发送命令、抓取输出并直接断言快速、确定性的功能回归如启动、版本、帮助命令2. SDK Agent 驱动测试通过 Codebuff SDK 运行一个测试代理代理借助自定义 tmux 工具与 CLI 交互AI 推理式验证复杂行为输出不再是匹配字符串而是理解语义3. 线上冒烟测试使用生产环境变量构建二进制真实调用后端完成一轮对话并结束会话发布前与定时任务中对线上链路的冒烟验证方式一直接 tmux 测试快速、确定性这是最常用的方式。测试代码通过FreebuffSession在 tmux 中启动二进制随后发送命令、捕获输出、断言结果import { describe, test, expect, afterEach } from bun:test import { FreebuffSession, requireFreebuffBinary } from ../utils describe(My Feature, () { let session: FreebuffSession | null null afterEach(async () { if (session) await session.stop() session null }) test(works correctly, async () { const binary requireFreebuffBinary() session await FreebuffSession.start(binary) await session.send(/help) const output await session.capture(2) expect(output).toContain(Shortcuts) }, 60_000) })注意测试运行在bun:test之上与仓库其余测试一致每个测试都声明了超时如60_000毫秒因为真实的终端交互与轮询需要时间。方式二SDK Agent 驱动测试AI 推理式验证当行为过于复杂、无法用简单的字符串包含断言时可以使用 Codebuff SDK 运行一个测试代理。代理通过自定义 tmux 工具与 Freebuff 交互理解CLI 输出并验证复杂行为import { describe, test, expect, afterEach } from bun:test import { CodebuffClient } from codebuff/sdk import { freebuffTesterAgent } from ../agent/freebuff-tester import { createFreebuffTmuxTools, requireFreebuffBinary } from ../utils describe(Agent Test, () { let cleanup: (() Promisevoid) | null null afterEach(async () { if (cleanup) await cleanup() cleanup null }) test(verifies startup, async () { const apiKey process.env.CODEBUFF_API_KEY if (!apiKey) return // Skip if no API key const binary requireFreebuffBinary() const tmuxTools createFreebuffTmuxTools(binary) cleanup tmuxTools.cleanup const client new CodebuffClient({ apiKey }) const result await client.run({ agent: freebuffTesterAgent.id, prompt: Start Freebuff and verify the branding is correct., agentDefinitions: [freebuffTesterAgent], customToolDefinitions: tmuxTools.tools, handleEvent: () {}, }) expect(result.output.type).not.toBe(error) }, 180_000) })无CODEBUFF_API_KEY时该测试直接跳过因此本地未配置密钥也不会阻塞测试套件。方式三线上冒烟测试真实后端链路freebuff/e2e/tests/live-turn.e2e.test.ts 是freebuff/e2e/tests/目录中唯一直接与真实后端通信的文件它在落地页选择器上定位到 DeepSeek V4.1 Flash 模型、启动会话、发送一条提示词、等待回答最后执行/end-session并校验后端不再存在打开的会话。它只有在设置了FREEBUFF_SMOKE_API_KEY或CODEBUFF_API_KEY时才运行否则跳过且需要一个以生产公共环境变量构建的二进制。该测试不在freebuff-e2e.yml矩阵中而是由.github/workflows/prod-smoke.yml按计划schedule以及每次发布前执行说明当前仓库快照的 .github/workflows 目录下仅可见ci.yml与pr-hygiene.ymlREADME 中描述的freebuff-e2e.yml、prod-smoke.yml属于文档记载的 CI 配置。NEXT_PUBLIC_CB_ENVIRONMENTprod NEXT_PUBLIC_CODEBUFF_APP_URLhttps://www.codebuff.com \ NEXT_PUBLIC_FREEBUFF_APP_URLhttps://freebuff.com NEXT_PUBLIC_SUPPORT_EMAILsupportcodebuff.com \ NEXT_PUBLIC_POSTHOG_API_KEYtest NEXT_PUBLIC_POSTHOG_HOST_URLhttp://127.0.0.1:9 \ NEXT_PUBLIC_STRIPE_PUBLISHABLE_KEYtest NEXT_PUBLIC_STRIPE_CUSTOMER_PORTALhttp://127.0.0.1:9 \ NEXT_PUBLIC_WEB_PORT3000 bun freebuff/cli/build.ts 0.0.0-smoke CODEBUFF_API_KEYyour token bun test freebuff/e2e/tests/live-turn.e2e.test.ts --timeout300000两个关键设计细节配置隔离CLI 运行在自己的FREEBUFF_CONFIG_DIR下因此不会触碰本机的真实用户配置。从源码看freebuff/e2e/tests/live-turn.e2e.test.ts测试用fs.mkdtempSync创建临时配置目录写入settings.json设置freebucksIntroSeenAt以跳过首次运行卡片并通过FreebuffSession.start的env选项注入CODEBUFF_API_KEY与FREEBUFF_CONFIG_DIR。不留尾巴afterEach中若仍处于聊天界面且会话未结束会自动发送/end-session防止一次失败的断言在账号上留下长达一小时的开放会话源码注释明确记录了首个 CI 运行曾因此踩坑见 live-turn.e2e.test.ts。测试的提示词也刻意选择了不可靠记忆、但答案唯一的内容Reply with only the English word for the number 7, in lowercase.期望输出seven源码注释解释了为何不用算术题——Flash 曾把 41872359 答成 6536。前置条件运行 E2E 测试前需要准备tmux必须安装macOS 用brew install tmuxUbuntu 用sudo apt-get install tmuxFreebuff 二进制必须先构建bun freebuff/cli/build.ts 0.0.0-devSDK 构建产物仅 Agent 测试需要cd sdk bun run buildCODEBUFF_API_KEY仅 Agent 测试需要设置该环境变量。构建与运行测试先构建二进制bun freebuff/cli/build.ts 0.0.0-dev二进制路径的解析规则见 freebuff/e2e/utils/binary-helpers.ts优先读取环境变量FREEBUFF_BINARY否则回退到cli/bin/freebuffrequireFreebuffBinary()在文件不存在时会抛出带构建提示的错误信息Build with: bun freebuff/cli/build.ts 。运行全部测试bun test freebuff/e2e/tests/运行单个测试bun test freebuff/e2e/tests/version.e2e.test.ts bun test freebuff/e2e/tests/startup.e2e.test.ts bun test freebuff/e2e/tests/help-command.e2e.test.ts bun test freebuff/e2e/tests/agent-startup.e2e.test.ts使用自定义二进制路径FREEBUFF_BINARY/path/to/freebuff bun test freebuff/e2e/tests/核心工具FreebuffSession源码级详解FreebuffSession定义于 freebuff/e2e/utils/freebuff-session.ts是整个体系的基石。它封装了在 tmux 中启动二进制 → 与 TUI 交互 → 抓取输出 → 清理的全过程。API 一览方法说明FreebuffSession.start(binaryPath)在 tmux 中启动二进制返回会话对象session.send(text)发送文本输入默认按下回车session.sendKey(key)发送特殊按键如C-c、Escapesession.capture(waitSec?)抓取终端输出session.captureLabeled(label, waitSec?)抓取并保存到会话日志带标签session.waitForText(pattern, timeoutMs?)轮询直到终端出现指定文本session.stop()停止会话并清理资源start()临时工作目录与安全的密钥注入FreebuffSession.start的源码实现freebuff-session.ts值得仔细阅读创建临时项目目录fs.mkdtempSync在系统临时目录生成freebuff-e2e-*目录并写入一个最小README.md# E2E Test Project让 Freebuff 有真实项目可索引支持预置初始文件通过initialFiles选项可在启动前写入任意相对路径的文件含嵌套目录自动创建环境变量的安全注入env选项如密钥、配置目录被写入一个位于项目目录之外、权限为0600的env.sh文件再由 tmux shellsource加载源码见 freebuff-session.ts。这样密钥既不会落入 CLI 索引的项目目录也不会出现在会话记录的命令行中tmux 启动组装cd tmpDir binaryPath命令并调用tmuxStart默认等待 4 秒、窗口尺寸 120×30。会话内文件操作与轮询除终端交互外FreebuffSession还提供writeFile/readFile/fileExists直接在临时工作目录中读写文件以及waitForFileContent(relativePath, pattern, timeoutMs?)轮询等待某个文件出现指定内容默认超时 60 秒超时后抛出含终端输出的详细错误。这对于验证CLI 是否在项目中实际写出了文件的场景如代码编辑测试非常实用。启动就绪判断waitForReady与waitForBootSignalTUI 的启动存在多种形态源码为此提供了两套判断waitForReady(timeoutMs?, minLines?)轮询终端输出直到非空行数达到阈值默认 5 行表示 TUI 已完成初始渲染waitForBootSignal(timeoutMs?)轮询直到输出命中FREEBUFF_BOOT_SIGNALS中的任意一个已知启动标志。该常量数组freebuff-session.ts包含export const FREEBUFF_BOOT_SIGNALS [ █████╗ ██████╔╝, // ASCII logo (full or small variant) Start coding for free, Enter a coding task, Pick a model to start, Free mode isnt available, Press ENTER to login, Open this URL, will run commands on your behalf, ] as const源码注释解释了原因CI 运行环境经常落在模型选择器的 wordmarkStart coding for free而非完整的 ASCII 大 Logo所以相比只等待单个 Logo 行匹配一组标志更可靠。stop()幂等清理stop()先调用tmuxStop该脚本幂等会话已不存在时静默忽略错误再递归删除临时工作目录与环境目录。tmux 底层封装与脚本层FreebuffSession并不直接操作 tmux而是通过 freebuff/e2e/utils/tmux-helpers.ts 调用仓库根目录scripts/tmux/下的 shell 脚本tmux-start.sh、tmux-send.sh、tmux-capture.sh、tmux-stop.sh函数对应脚本说明tmuxStart(options)tmux-start.sh启动 tmux 会话支持--command、--name、--width、--height、--wait、--plaintmuxSend(session, text, opts?)tmux-send.sh发送文本支持--no-enter不回车、--wait-idle等待空闲、--forcetmuxSendKey(session, key)tmux-send.sh --key发送特殊按键tmuxCapture(session, opts?)tmux-capture.sh抓取输出支持--wait、--label带标签保存日志、--no-savetmuxStop(session)tmux-stop.sh停止会话错误被捕获幂等这些脚本同时被 scripts/tmux 目录下的其他工具复用构成一套独立的终端会话操作基础设施。SDK 自定义工具与测试代理createFreebuffTmuxTools(binaryPath)定义于 freebuff/e2e/utils/tmux-custom-tools.ts返回{ tools, cleanup }tools是四个自定义工具定义输入模式使用zod/v4schema 声明cleanup应在afterEach中调用以兜底停止会话工具名作用关键行为start_freebuff启动 CLI先检查会话是否已存在启动后调用waitForReady()并返回初始输出send_to_freebuff发送文本输入如同用户输入默认按下回车无会话时返回错误信息capture_freebuff_output抓取终端输出可选waitSeconds参数等待后再抓取stop_freebuff停止并清理幂等返回wasRunning状态freebuffTesterAgent专职 QA 测试代理freebuff/e2e/agent/freebuff-tester.ts 定义了测试代理id为freebuff-tester模型为anthropic/claude-sonnet-4.5可用的工具恰好是上述四个 tmux 工具。其系统提示词instructionsPrompt为代理规定了标准的操作流程调用start_freebuff启动 CLI用capture_freebuff_output带waitSeconds查看终端输出用send_to_freebuff输入命令或文本再次抓取输出验证行为完成后务必调用stop_freebuff。同时要求代理重点核查CLI 是否无错误/无崩溃启动、启动画面是否有可见内容、命令是否符合预期、错误信息是否对用户友好并清晰汇报测试项、观察结果与通过/失败结论。这套自定义工具 专用代理 结构化指令的模式正是 Freebuff 用 AI 验证 AI 产品的落地示范。测试用例剖析version.e2e.test.ts版本输出的三个断言freebuff/e2e/tests/version.e2e.test.ts 直接以execFileSync运行二进制不经 tmux验证三点--version输出应匹配/\d\.\d\.\d/semver 形式退出码为 0execFileSync遇非零退出码会抛异常不抛即通过忽略项目bunfig.toml的 preload测试在临时目录写入preload [$config/db]的bunfig.toml后仍能正常输出版本——这验证了--version这类无界面命令不会被项目配置干扰。startup.e2e.test.ts启动画面与优雅退出freebuff/e2e/tests/startup.e2e.test.ts 包含两个典型场景启动画面渲染waitForBootSignal()等待任一启动标志出现随后反向断言排除致命错误标记——输出不得包含Fatal error during startup、Internal error: tree-sitter.wasm not found、FATAL、panic、Segmentation fault。这是一种双重保险策略即便某个竞态导致错误与 Logo 同时出现也会被清晰指出而非埋没在原始输出中CtrlC 优雅退出启动并waitForReady()后发送C-c等待片刻再断言输出不含Unhandled与FATAL——验证 CLI 能干净地处理中断信号。help-command.e2e.test.ts品牌与用法校验freebuff/e2e/tests/help-command.e2e.test.ts 检查--help输出必须包含freebuff忽略大小写、匹配/usage|options|commands/i并且不得出现codebuff字样——后者是品牌正确性的回归测试防止帮助文案中泄露母公司品牌。新增测试的规范流程按 README 的指引新增一条 E2E 测试只需三步在freebuff/e2e/tests/下新建文件命名遵循feature.e2e.test.ts约定将测试名加入.github/workflows/freebuff-e2e.yml的矩阵README 记载的 CI 配置示例片段matrix: test: - version - startup - help-command - agent-startup - your-new-test # -- add here提交后该测试将在 CI 中与其他测试并行运行。CI 工作流设计根据 README 对.github/workflows/freebuff-e2e.yml的描述CI 流程为构建一次Freebuff 二进制linux-x64通过 GitHub Actions 的 matrix 策略并行运行每个测试文件失败时上传 tmux 会话日志用于调试这正是captureLabeled带标签保存日志的意义所在。触发时机包括每晚 PT 时间 6:00与手动触发workflow_dispatch。线上冒烟测试live-turn.e2e.test.ts则独立于矩阵之外由prod-smoke.yml在计划任务与每次发布前执行。最佳实践小结分层选择测试方式确定性行为用直接 tmux 断言快、稳、无需密钥需要语义理解的行为交给 SDK 测试代理线上链路用带密钥的冒烟测试且务必结束会话善用轮询而非固定 sleepwaitForText、waitForBootSignal、waitForFileContent都采用轮询 超时错误报告失败时附上终端输出便于定位注意密钥与配置隔离利用env选项 0600env.sh 独立FREEBUFF_CONFIG_DIR测试永不污染真实用户环境每个测试声明合理超时终端交互类测试通常以 60 秒为基准Agent 测试与线上冒烟可达 180300 秒反向断言防漏网对启动等关键路径除了正向匹配启动标志还应反向断言FATAL、panic等致命标记。至此你可以基于这套框架为 Freebuff 的任意 CLI 功能编写稳定、可并行、可调试的端到端测试并顺畅地融入其 CI 流水线。【免费下载链接】freebuffThe free coding agent项目地址: https://gitcode.com/GitHub_Trending/cod/freebuff创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考
延伸阅读

更多相关文章

2026/9/15 21:58:42

告别命令行:nTopology可视化建模快速生成Voronoi泡沫

上周帮朋友调整一个鞋底中底的轻量化结构,他想做的东西很明确:三维Voronoi泡沫——一堆随机的胞元互相连通,看起来像海绵,踩上去又要能回弹。我原本打算用老路子,命令行加减Python脚本去跑scipy.spatial.Voronoi&#…

2026/9/15 21:53:42

Spring Boot+uniapp居民健康数据闭环系统实战

简介:本资源是一套基于Spring Boot后端与uniapp前端的居民健康监测系统源码,面向Java Web开发初学者及小程序全栈实践者,解决社区健康数据采集、用户分级管理与可视化报告等实际场景需求。压缩包共1608个文件,涵盖137个Java后端逻…

2026/9/15 22:38:49

2026国内Docker镜像源加速配置与避坑指南

如果你今天还在因为docker pull卡在 Pulling fs layer 而怀疑人生,那说明你需要这份 2026 年 9 月 13 日更新过的国内 Docker 镜像源加速列表。这篇文章把我最近几天实际测过的镜像加速源、配置方法以及这半年踩过的坑完整整理了一遍,覆盖 Linux Docker …

2026/9/15 22:38:49

Java高并发面试核心知识点全解析:从线程到秒杀系统设计

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

2026/9/15 22:38:49

三维角色服装制作:MakeHuman与MakeClothes从代理物体到导出

1. 为什么是 MakeHuman MakeClothes:谈谈这套小众流程的取舍开始写教程正文前,得先聊聊我为什么会在形形色色的人物建模软件里,最终把 MakeHuman 这套流程留作常驻工具。市面上做人物建模的主流方案并不少,ZBrush、Blender 自带的…

2026/9/15 22:33:49

MRMR与ReliefF特征选择:MATLAB实现与MEX编译实战

简介:面向机器学习与数据挖掘场景的MATLAB特征选择工具包,提供MRMR(最大相关最小冗余)与ReliefF(基于近邻的实例权重评估)两种经典算法,适用于高维数据降维、分类或回归模型预处理等任务&#x…

2026/9/15 4:54:30

拯救者Y7000黑屏故障排查与维修实战指南

1. 项目概述:一台黑屏的拯救者Y7000,到底卡在哪一步? 联想拯救者Y7000系列笔记本,从2018年第一代搭载i5-8300H开始,到后来的i7-9750H、i7-10750H、i5-11400H,再到2023年款的R7-7840HS,它始终是学…

2026/9/15 0:01:16

AI英语单词APP开发:自适应学习算法与移动端优化实践

1. 项目概述 作为一名在移动应用开发领域摸爬滚打多年的老手,我最近完成了一个AI英语单词APP的开发项目。这个项目将传统单词记忆方法与现代AI技术相结合,打造了一款能够智能适应不同用户学习习惯的英语学习工具。 市面上大多数单词APP都存在一个通病&a…

2026/9/15 0:01:16

Flutter与OpenHarmony结合开发手语学习APP实战

1. 项目背景与核心价值作为一名同时接触过Flutter和OpenHarmony的开发者,最近我完成了一个基于Flutter for OpenHarmony的手语学习APP实战项目。这个项目最大的特点在于实现了跨平台框架与国产操作系统深度结合的创新实践——用Flutter开发的应用能完美运行在OpenHa…

2026/9/15 0:01:16

六个月成为机器人工程师:从ROS2到SLAM的实战路径

1. 六个月的紧迫感从哪来:先搞清楚你要成为哪种机器人工程师说实话,六个月的期限并不是一个宽松的时间线。市面上任何一本正经的机器人学教材都超过五百页,ROS2的官方文档可以翻到你怀疑人生,再加上ABB、KUKA这些工业机器人厂家动…

2026/9/15 14:22:53

USB Type-C PCB布局分区设计:电源、高速信号与PD协议全攻略

做硬件这行,Type-C接口算是典型的“看着简单,做起来全坑”的东西。光引脚就24个,高低速信号、电源、控制线全部塞在一个小小的连接器里,如果PCB布局不做规划,打样回来基本就是“插上没反应”、“高速掉线”、“静电一打…

2026/9/15 21:31:11

系统编程学习原型如何补齐稳定性边界

系统编程学习原型如何补齐稳定性边界预算有限时&#xff0c;我先优化明显多余的复制&#xff0c;而不是猜测性地换容器。用借用传递只读数据通常就能减少分配&#xff1a; fn parse(line: &str) -> Result<Item, Error> { /* ... */ }用基准确认热点确实在分配&am…

2026/9/15 11:42:23

雨花区哪家财务公司代理记账比较好?

在雨花区&#xff0c;企业处理财税事务常常面临诸多挑战&#xff0c;选择一家靠谱的财务公司至关重要。湖南巨勤财务管理咨询有限公司就是本地正规实体财税服务机构&#xff0c;深耕本地工商财税行业多年&#xff0c;熟悉当地工商局、税务局最新政策与申报流程。主营公司注册、…

还想了解更多?直接咨询顾问

免费诊断 + 免费方案 + 透明报价。

全国咨询热线400-8866-253
免费获取方案
咨询二维码