Codex 系统手册

顶层 codex CLI 命令验证

stage-23.3.214 个文件

这一阶段像是给 codex 命令行入口做总验收,属于系统跑起来后面向用户的外壳检查。它会实际敲各种命令,看反应对不对:app-server、exec-server 要能拦住写错的配置;delete、update、debug 命令不能走错流程;features 检查功能开关和配置提示;plugin 和 marketplace 测插件安装源的增删升级;MCP 命令要正确读写服务器配置;最后还有少量真人真机测试,确认真连服务时也能跑通。

本阶段的文件14

入口点验证

这些测试验证顶层和服务器式 CLI 入口点的严格配置处理和基本命令界面行为。

cli/tests/app_server.rs源码 ↗
testtest run

这个测试文件模拟了一个很常见的出错场景:用户在配置文件里写了一个程序不认识的配置项,比如 foo = "bar"。如果程序只是装作没看见,用户以后排查问题会很痛苦。所以这里创建了一个临时的 CODEX_HOME 目录,往里面写入一份带错误字段的 config.toml,然后启动 codex app-server --strict-config --listen off--strict-config 的意思是“严格检查配置”,发现陌生字段就报错;--listen off 则让服务不要真的开始监听网络端口,方便测试只检查配置阶段。测试最后确认命令运行失败,并且错误信息里包含“unknown configuration field”。简单说,它像是在门口放了一个检查员:配置单上有看不懂的项目,就不让程序继续启动。

函数细节2
codex_command7–11 ↗
fn codex_command(codex_home: &Path) -> Result<assert_cmd::Command>

作用:这个辅助函数用来准备一条可以运行 codex 程序的测试命令。它还会把 CODEX_HOME 指到测试专用目录,避免测试碰到真实用户的配置。

数据流:输入是一条临时目录路径,也就是测试用的家目录。函数先找到测试环境里编译好的 codex 可执行文件,再创建一个命令对象,并给它设置环境变量 CODEX_HOME。输出是一条准备好的命令,后面的测试可以继续给它加参数并运行。

调用关系:它被 strict_config_rejects_unknown_config_fields_for_app_server 调用。测试主体不直接手写启动命令,而是把“找到 codex 并设置测试家目录”这件重复且容易出错的活交给它。它内部使用外部库提供的 cargo_bin 找到可执行文件,再用 assert_cmd::Command::new 创建命令。

调用图:被 1 处调用(strict_config_rejects_unknown_config_fields_for_app_server);外部调用 2 个(new, cargo_bin)。

strict_config_rejects_unknown_config_fields_for_app_server14–30 ↗
fn strict_config_rejects_unknown_config_fields_for_app_server() -> Result<()>

作用:这个测试确认:当 app-server 使用严格配置模式启动时,配置文件里出现未知字段会导致启动失败。这样可以保证错误配置不会被静默忽略。

数据流:开始时它创建一个全新的临时目录,作为假的 CODEX_HOME。接着在这个目录里写入 config.toml,内容只有一个程序不认识的字段 foo。然后它通过 codex_command 准备好 codex 命令,追加 app-server --strict-config --listen off 参数并运行。最后它检查结果:命令必须失败,并且标准错误输出里必须包含 unknown configuration field 这句话。

调用关系:这是这个文件里的核心测试,由 Rust 测试框架在跑测试时自动调用。它先用 TempDir::new 建临时目录,用 std::fs::write 写配置文件,再调用 codex_command 得到可运行的命令。运行后,它借助 contains 这个断言工具检查报错文字,确保失败原因正是未知配置字段。

调用图:调用 1 个内部函数(codex_command);外部调用 3 个(new, contains, write)。

cli/tests/delete.rs源码 ↗
testtest run

这个文件是一个自动化测试。它像一个假用户一样启动 codex delete <会话ID> 命令,但先准备一个空的临时目录当作 CODEX_HOME,也就是程序存放会话数据的家目录。因为这个目录是空的,所以指定的会话肯定不存在。测试期望程序运行失败,并且错误信息里要说找不到匹配的活动或归档会话。同时,它还特别检查错误信息里不能出现 cannot confirm。这点很重要:如果程序连会话都没找到,就不应该进入“确认删除”这一步。可以把它想成去仓库销毁一箱货,系统应该先确认这箱货存在;如果货号不存在,就直接说找不到,而不是问你“确定要销毁吗”。

函数细节1
missing_session_fails_before_delete_confirmation4–17 ↗
fn missing_session_fails_before_delete_confirmation() -> anyhow::Result<()>

作用:这个测试确认:删除一个不存在的会话时,codex 命令会先因为找不到会话而失败,不会走到删除确认流程。它保护的是删除命令的错误顺序,避免给用户一个误导性的确认失败提示。

数据流:进去的是一个临时创建的空目录,以及一个固定的假会话 ID。函数把空目录设成 CODEX_HOME,再启动 codex delete 命令。出来的结果应该是命令失败;标准错误输出里包含“找不到匹配会话”的提示,并且不包含 cannot confirm。测试过程中会创建临时目录,但不会改动真实用户的配置或数据。

调用关系:它在测试运行时由 Rust 测试框架自动调用。它先通过 tempdir 准备干净的假环境,通过 cargo_bin 找到要测试的 codex 可执行文件,再用 assert_cmd::Command::new 像用户一样运行命令,最后用 contains 这类断言工具检查输出文字是否符合预期。

调用图:外部调用 4 个(new, cargo_bin, contains, tempdir)。

cli/tests/exec_server.rs源码 ↗
testtest run

这个测试文件模拟了一个很常见的出错场景:用户在配置文件里写了一个程序不认识的字段,比如 foo = "bar"。如果程序只是默默跳过它,用户很难发现自己配错了。所以这里先建一个临时的 CODEX_HOME 目录,相当于给测试准备一个干净的小房间;再往里面写入 config.toml;然后启动 codex exec-server,并加上 --strict-config,意思是“配置必须严格检查”。测试期望程序启动失败,并且在错误输出里看到 “unknown configuration field”。这样可以保证 exec-server 这条命令也遵守严格配置规则,而不是只在别的命令里生效。

函数细节2
codex_command7–11 ↗
fn codex_command(codex_home: &Path) -> Result<assert_cmd::Command>

作用:这个函数帮测试创建一个可以运行 codex 命令的对象,并把它的 CODEX_HOME 指向测试准备的目录。这样每个测试都能在自己的临时环境里运行,不会碰到用户真实的配置。

数据流:输入是一个目录路径,也就是测试想让 codex 当作家目录使用的位置。函数先找到测试用的 codex 可执行程序,再创建命令对象,然后给这个命令设置 CODEX_HOME 环境变量。输出是准备好的命令对象;如果找不到程序或创建失败,就返回错误。

调用关系:它是测试里的小帮手。strict_config_rejects_unknown_config_fields_for_exec_server 在真正运行命令前会调用它,拿到一个已经设置好环境的 codex 命令;它内部依赖外部库来创建命令对象并找到 cargo 构建出来的 codex 程序。

调用图:被 1 处调用(strict_config_rejects_unknown_config_fields_for_exec_server);外部调用 2 个(new, cargo_bin)。

strict_config_rejects_unknown_config_fields_for_exec_server14–35 ↗
fn strict_config_rejects_unknown_config_fields_for_exec_server() -> Result<()>

作用:这个测试确认:当 exec-server 使用严格配置模式时,配置文件里出现不认识的字段会让命令失败。它保护的是“配置写错要立刻报错”这个重要行为。

数据流:一开始它创建一个临时目录,作为假的 CODEX_HOME。接着在这个目录里写入一个带有未知字段 fooconfig.toml。然后它通过 codex_command 创建 codex 命令,传入 exec-server--strict-config 和监听地址参数。最后它检查结果:命令必须失败,并且标准错误输出里必须包含 “unknown configuration field”。测试结束后临时目录会自动清理。

调用关系:这是这个文件里的主测试,会被 Rust 测试框架在测试运行时自动执行。它先调用 codex_command 准备命令,再借助外部测试库执行命令、断言失败结果,并用字符串匹配工具检查错误信息是否说到了未知配置字段。

调用图:调用 1 个内部函数(codex_command);外部调用 3 个(new, contains, write)。

cli/tests/update.rs源码 ↗
testtest

这个测试文件解决的是一个很具体的问题:在调试版,也就是给开发者本地跑的版本里,codex update 不应该真的进入更新流程,更不应该启动一个等人输入的交互提示。测试会先造一个临时的 CODEX_HOME 目录,相当于给这次测试准备一个干净的“用户家目录”,避免碰到真实电脑上的配置。然后它启动 codex update 命令,检查命令必须失败,并且错误信息里要写清楚:调试版不支持这个命令。这样做的价值是,哪怕以后有人改了命令行入口,也能及时发现“调试版误进更新流程”这种问题。文件里的小工具 codex_command 负责把要运行的 codex 程序和临时环境变量准备好,真正的测试函数则负责发出命令并核对结果。

函数细节2
codex_command6–10 ↗
fn codex_command(codex_home: &Path) -> Result<assert_cmd::Command>

作用:这个函数帮测试准备一个可以运行的 codex 命令对象。它还会把 CODEX_HOME 指向测试用的临时目录,避免测试读写真实用户的数据。

数据流:进去的是一个目录路径,表示这次测试要假装使用的 Codex 主目录。函数先找到当前构建出来的 codex 可执行程序,再创建一个命令对象,并给它加上 CODEX_HOME 环境变量。出来的是准备好的命令对象,后面的测试可以继续给它加参数并运行。

调用关系:它是测试里的准备步骤,被 update_does_not_start_interactive_prompt 调用。它自己借助外部工具找到 codex 程序并创建命令对象,把“怎么启动命令”的细节藏起来,让测试主体只关心要验证的行为。

调用图:被 1 处调用(update_does_not_start_interactive_prompt);外部调用 2 个(new, cargo_bin)。

update_does_not_start_interactive_prompt14–24 ↗
async fn update_does_not_start_interactive_prompt() -> Result<()>

作用:这个测试确认在调试版中运行 codex update 会直接报错,而不是进入交互式更新提示。这样可以防止开发版本表现得像正式更新器一样。

数据流:开始时它创建一个临时目录,作为这次测试专用的 CODEX_HOME。接着它通过 codex_command 准备好 codex 命令,加上 update 参数后执行。最后它检查结果:命令必须失败,而且标准错误输出里必须包含“调试版不支持 codex update”这类提示;测试本身如果都符合预期,就返回成功。

调用关系:这是这个文件的核心测试函数,只在启用了调试断言的构建中运行,也就是通常的开发调试版。它先调用 codex_command 搭好命令,再用外部断言工具检查退出状态和错误文本,确保更新命令没有走到不该走的交互流程。

调用图:调用 1 个内部函数(codex_command);外部调用 2 个(new, contains)。

调试与功能命令

这些测试覆盖面向维护的调试命令和功能管理 CLI,包括输出格式、持久化和警告。

cli/tests/debug_clear_memories.rs源码 ↗
testtest run

这个测试文件像一次“清洁检查”。它先造一个临时的 CODEX_HOME,也就是程序自己的家目录,然后故意往里面塞一些假的记忆数据:有数据库里的记忆摘要、后台任务记录,也有磁盘上的记忆文件。接着它运行真正的 codex debug clear-memories 命令,看命令是否成功,并检查结果是不是符合预期:记忆数据库里的相关表被清空,记忆目录还在但里面没有旧文件。文件还额外测试一种更麻烦的情况:主状态数据库已经不见了,只剩记忆数据库时,清理命令也不能崩溃,仍然要把记忆数据库清干净。这里用到 SQLite 数据库(一种本地文件数据库)和临时目录,目的不是模拟用户界面,而是尽量贴近真实运行环境,保证这个调试命令在实际机器上可靠。

函数细节3
codex_command11–15 ↗
fn codex_command(codex_home: &Path) -> Result<assert_cmd::Command>

作用:这个小工具函数用来准备一次要运行的 codex 命令。它会指定这次命令使用哪个临时的 CODEX_HOME,避免测试污染真实用户的数据。

数据流:进去的是一个临时目录路径 → 它找到测试用的 codex 可执行程序,并把环境变量 CODEX_HOME 指向这个目录 → 出来的是一个已经配置好的命令对象,后面的测试可以直接给它加参数并运行。

调用关系:两个测试函数都会先调用它来拿到一条可执行的 codex 命令。它自己把找二进制文件和创建命令对象的活交给外部工具完成,让测试主体只关心要运行什么参数。

调用图:被 2 处调用(debug_clear_memories_resets_memories_db_without_state_db, debug_clear_memories_resets_state_and_removes_memory_dir);外部调用 2 个(new, cargo_bin)。

debug_clear_memories_resets_state_and_removes_memory_dir18–138 ↗
async fn debug_clear_memories_resets_state_and_removes_memory_dir() -> Result<()>

作用:这个测试验证最完整的清理场景:当主状态数据库、记忆数据库、记忆文件夹里都已经有旧数据时,debug clear-memories 能把记忆相关内容清掉。

数据流:开始时它创建一个临时 CODEX_HOME,并初始化程序状态 → 往主状态数据库里插入一条会话线程记录,往记忆数据库里插入记忆摘要和记忆任务记录,还在磁盘上写入一个旧的记忆文件 → 然后运行 codex debug clear-memories → 最后重新打开数据库检查:记忆摘要数量变成 0,记忆任务数量变成 0,记忆目录仍存在但里面已经空了。

调用关系:这是对清理命令的主流程验收测试。它先借助状态初始化函数和数据库连接函数搭好真实环境,再通过 codex_command 启动真正的命令行程序,最后用断言检查命令是否完成了该做的清理。

调用图:调用 2 个内部函数(codex_command, init);外部调用 12 个(connect, new, assert!, assert_eq!, memories_db_path, state_db_path, format!, contains, query, query_scalar (+2 more))。

debug_clear_memories_resets_memories_db_without_state_db141–189 ↗
async fn debug_clear_memories_resets_memories_db_without_state_db() -> Result<()>

作用:这个测试验证一个边界情况:如果主状态数据库文件已经被删掉,清理记忆的命令也应该能正常工作,而不是因为缺少主库就失败。

数据流:开始时它创建临时 CODEX_HOME 并初始化数据库 → 只往记忆数据库里插入一条旧记忆数据 → 关闭数据库连接后,故意删除主状态数据库文件 → 然后运行 codex debug clear-memories → 最后检查记忆数据库里的旧记录已经清空,同时主状态数据库文件没有被偷偷重新创建。

调用关系:这个测试补充覆盖异常但现实可能发生的情况。它同样通过 codex_command 运行真实命令,但重点不是检查目录文件,而是确认命令在没有主状态数据库时仍能只清理记忆数据库,并保持缺失的主库继续缺失。

调用图:调用 2 个内部函数(codex_command, init);外部调用 11 个(connect, new, assert!, assert_eq!, memories_db_path, state_db_path, format!, contains, query, query_scalar (+1 more))。

cli/tests/debug_models.rs源码 ↗
testtest execution

这个文件是一组自动测试。它要防止一个很实际的问题:用户运行 codex debug models 时,程序如果崩了、输出不是 JSON,或者模型列表是空的,其他工具和人就没法可靠地查看可用模型。测试会先创建一个临时的 CODEX_HOME,也就是给程序准备一个一次性的“家目录”,避免碰到用户真实配置。然后它启动真正的 codex 命令行程序,分别测试两种用法:一种带 --bundled,表示查看程序自带的模型信息;另一种不带这个参数,表示默认查看模型信息,而且不要求用户已经认证登录。每个测试都会检查命令成功退出,把输出从字节转成文字,再按 JSON 解析,最后确认 models 字段是数组并且不是空的。

函数细节3
codex_command6–10 ↗
fn codex_command(codex_home: &Path) -> Result<assert_cmd::Command>

作用:这个函数帮测试准备一个可以运行的 codex 命令。它还会把 CODEX_HOME 指到临时目录,让测试不使用也不污染用户真实的本地数据。

数据流:输入是一个临时目录路径,代表这次测试专用的程序家目录。函数先找到编译好的 codex 可执行文件,再创建一个命令对象,并给它设置 CODEX_HOME 环境变量。输出是准备好的命令对象;如果找不到程序或创建失败,就返回错误。

调用关系:两个测试函数都会先调用它,拿到一个干净、可控的 codex 命令。它内部把寻找可执行文件和创建命令对象的活儿交给外部库完成,自己主要负责把测试环境隔离好。

调用图:被 2 处调用(debug_models_bundled_prints_json, debug_models_default_prints_json_without_auth);外部调用 2 个(new, cargo_bin)。

debug_models_bundled_prints_json13–25 ↗
fn debug_models_bundled_prints_json() -> Result<()>

作用:这个测试确认 codex debug models --bundled 会成功运行,并打印出可解析的 JSON。这里的 --bundled 可以理解为“只看程序自带的模型清单”。

数据流:它先创建一个临时目录,再通过 codex_command 得到一条测试用命令。接着给命令加上 debug models --bundled 参数并运行。运行结束后,它检查退出状态是成功的,把标准输出从原始字节变成字符串,再按 JSON 解析,最后确认里面的 models 是一个非空数组。

调用关系:这是测试套件中的一个具体场景。它依赖 codex_command 来准备干净的命令环境,然后调用真实的命令行程序;后面的断言负责把“程序能跑”和“输出内容像预期”都检查一遍。

调用图:调用 1 个内部函数(codex_command);外部调用 4 个(from_utf8, new, assert!, from_str)。

debug_models_default_prints_json_without_auth28–40 ↗
fn debug_models_default_prints_json_without_auth() -> Result<()>

作用:这个测试确认直接运行 codex debug models 也能成功输出 JSON,而且不需要提前登录或准备认证信息。它保证调试查看模型列表这个功能足够轻量、容易使用。

数据流:它先新建一个临时 CODEX_HOME,这意味着里面没有用户登录资料。然后通过 codex_command 创建命令,运行 debug models。它拿到输出后,检查命令成功结束,把输出转成文字并解析成 JSON,再确认 models 字段是一个非空数组。

调用关系:这个测试和带 --bundled 的测试形成对照:一个测显式查看内置模型,一个测默认行为。它同样先借助 codex_command 搭好隔离环境,再把验证重点放在“没有认证也能得到有效模型 JSON”上。

调用图:调用 1 个内部函数(codex_command);外部调用 4 个(from_utf8, new, assert!, from_str)。

cli/tests/features.rs源码 ↗
testtest run

这个文件把 codex 当成一个真实命令来运行,而不是只测试内部函数。每个测试都会先建一个临时的 CODEX_HOME 目录,相当于给程序准备一个干净的新用户家目录,避免碰到开发者电脑上的真实配置。然后它启动 codex,传入不同参数,看程序是成功还是失败、终端输出里有没有该有的文字、配置文件 config.toml 有没有被正确写入。这里重点覆盖两类行为:一类是严格配置模式,遇到未知配置时要报错,而且 codex cloud 不支持这个模式时也要说清楚;另一类是 features 子命令,启用或关闭功能时要写入配置,启用还在开发中的功能时要警告,列出功能时要按字母排序。它像一套验收清单,确保用户真正敲命令时看到的结果可靠。

函数细节7
codex_command8–12 ↗
fn codex_command(codex_home: &Path) -> Result<assert_cmd::Command>

作用:这个辅助函数专门用来创建一个能运行 codex 程序的测试命令。它还会把 CODEX_HOME 指到测试用的临时目录,避免测试读写真实用户配置。

数据流:输入是一个临时目录路径 → 它找到测试环境里编译好的 codex 可执行文件,创建一个命令对象,并给这个命令加上 CODEX_HOME 环境变量 → 输出是一个准备好的命令对象,后面的测试可以继续给它加参数并运行。

调用关系:所有测试都会先调用它来拿到“干净隔离”的 codex 命令。它把创建命令这件重复工作集中起来,后面的测试只关心自己要验证的参数和输出。

调用图:被 6 处调用(features_disable_writes_feature_flag_to_config, features_enable_under_development_feature_prints_warning, features_enable_writes_feature_flag_to_config, features_list_is_sorted_alphabetically_by_feature_name, strict_config_is_not_supported_for_cloud_command, strict_config_rejects_unknown_config_override);外部调用 2 个(new, cargo_bin)。

strict_config_rejects_unknown_config_override15–25 ↗
fn strict_config_rejects_unknown_config_override() -> Result<()>

作用:这个测试确认:开启严格配置模式后,如果用户用 -c foo=bar 传了一个程序不认识的配置项,命令必须失败并明确提示“未知配置字段”。这样可以防止拼错配置名时程序默默忽略,造成用户以为设置生效了。

数据流:开始时创建一个空的临时配置目录 → 用 codex_command 准备命令,再传入 --strict-config -c foo=bar mcp-server → 运行后期望命令失败,并检查错误输出里包含 unknown configuration field

调用关系:它依赖 codex_command 搭好独立测试环境,然后把实际检查交给命令断言工具完成。它验证的是命令行入口在严格配置场景下的外部表现。

调用图:调用 1 个内部函数(codex_command);外部调用 2 个(new, contains)。

strict_config_is_not_supported_for_cloud_command28–40 ↗
fn strict_config_is_not_supported_for_cloud_command() -> Result<()>

作用:这个测试确认:codex cloud 这类云相关命令不支持 --strict-config 时,要直接失败并给出清楚提示。它避免用户把本地配置校验选项误用到云命令上却不知道原因。

数据流:开始时创建临时目录 → 准备一个隔离的 codex 命令 → 传入 --strict-config -c foo=bar cloud list 并运行 → 结果应该失败,错误输出中应该说明 --strict-config 不支持 codex cloud

调用关系:它和其他命令行测试一样先通过 codex_command 建命令。这个测试专门覆盖 cloud list 路径,确保主程序在分发到云命令前或分发时能拦住不支持的选项。

调用图:调用 1 个内部函数(codex_command);外部调用 2 个(new, contains)。

features_enable_writes_feature_flag_to_config43–57 ↗
async fn features_enable_writes_feature_flag_to_config() -> Result<()>

作用:这个测试确认:用户运行 codex features enable unified_exec 后,程序会真的把这个功能开关写进配置文件,并告诉用户启用成功。它保证“启用功能”不是只在屏幕上说说,而是会持久保存。

数据流:先创建一个空的临时 CODEX_HOME → 启动 codex features enable unified_exec → 检查命令成功,标准输出里有启用成功的提示 → 再读取临时目录里的 config.toml,确认里面有 [features] 段落,并且写了 unified_exec = true

调用关系:它使用 codex_command 启动真实命令,再用文件读取检查命令留下的结果。它把终端输出和磁盘配置一起验证,覆盖了用户最关心的完整效果。

调用图:调用 1 个内部函数(codex_command);外部调用 4 个(new, assert!, contains, read_to_string)。

features_disable_writes_feature_flag_to_config60–74 ↗
async fn features_disable_writes_feature_flag_to_config() -> Result<()>

作用:这个测试确认:用户运行 codex features disable shell_tool 后,程序会把对应功能写成关闭状态。它保证关闭功能也会被保存到配置文件里,之后再启动程序时仍然有效。

数据流:先准备一个空临时目录 → 运行 codex features disable shell_tool → 检查命令成功,输出中说明已禁用 → 读取生成的 config.toml,确认有 [features],并且包含 shell_tool = false

调用关系:它通过 codex_command 获得隔离命令,然后运行功能关闭子命令。它和启用功能的测试成对存在,一个验证写入 true,一个验证写入 false

调用图:调用 1 个内部函数(codex_command);外部调用 4 个(new, assert!, contains, read_to_string)。

features_enable_under_development_feature_prints_warning77–89 ↗
async fn features_enable_under_development_feature_prints_warning() -> Result<()>

作用:这个测试确认:启用仍在开发中的功能时,程序虽然允许成功,但必须在错误输出里给出警告。这样用户会知道这个功能可能还不稳定,不是普通成熟功能。

数据流:先建立临时配置目录 → 运行 codex features enable runtime_metrics → 期望命令成功 → 同时检查错误输出里包含 Under-development features enabled: runtime_metrics. 这句警告。

调用关系:它仍然使用 codex_command 来隔离环境。这个测试关注的不是配置文件内容,而是启用特殊功能时,命令行界面是否把风险提示给用户看见。

调用图:调用 1 个内部函数(codex_command);外部调用 2 个(new, contains)。

features_list_is_sorted_alphabetically_by_feature_name92–119 ↗
async fn features_list_is_sorted_alphabetically_by_feature_name() -> Result<()>

作用:这个测试确认:codex features list 打印出来的功能名是按字母顺序排列的。排序稳定很重要,因为用户更容易查找,也能避免输出顺序随机导致脚本或文档难以依赖。

数据流:先创建临时目录并准备命令 → 运行 codex features list 并拿到标准输出 → 把输出按行拆开,再从每行取出功能名 → 复制一份功能名列表并按字母排序 → 比较原列表和排序后的列表,二者相同就说明原输出已经排好序。

调用关系:它通过 codex_command 运行真实的列表命令,然后自己解析输出格式并用相等断言检查顺序。它验证的是展示给用户看的列表是否整齐、可预期。

调用图:调用 1 个内部函数(codex_command);外部调用 3 个(from_utf8, new, assert_eq!)。

插件市场流程

这些测试检验插件和市场命令行为,涵盖从广泛的列表/安装流程,到市场来源的添加、移除和升级路径。

cli/tests/plugin_cli.rs源码 ↗
testtest run

插件功能会读配置文件、扫描本地目录、解析市场清单,还会把插件下载安装到缓存里。只测单个小函数不够,因为真正容易出错的是这些步骤连在一起时的行为。这个测试文件会先在临时目录里造出一个干净的 CODEX_HOME、HOME 和假的插件市场,再启动真实的 codex 命令行程序。它检查市场列表、插件列表、JSON 输出、安装、移除、错误提示等场景。这里还特意覆盖了坏情况,比如市场清单缺失、JSON 写坏、市场名非法、插件已缓存但市场已移除。这样可以保证用户在命令行看到的结果稳定、清楚,也能防止配置文件被错误改坏。

函数细节50
marketplace_list_row16–22 ↗
fn marketplace_list_row(marketplace_name: &str, root: &Path) -> String

作用:拼出市场列表里一行应该长什么样,方便测试拿它和命令输出对比。它主要保证列宽、空格和路径显示格式都一致。

数据流:输入市场名字和根目录路径 → 按表格列宽把名字左对齐,再接上路径文字 → 输出一整行预期文本,不改动任何文件。

调用关系:几个检查 plugin marketplace list 普通表格输出的测试会先用它做出标准答案,然后交给断言去看命令输出里有没有这一行。

调用图:被 3 处调用(marketplace_list_includes_home_marketplace_when_present, marketplace_list_includes_root_when_plugins_are_filtered_out, marketplace_list_shows_configured_marketplace_names);外部调用 1 个(format!)。

codex_command24–29 ↗
fn codex_command(codex_home: &Path) -> Result<assert_cmd::Command>

作用:创建一个准备好运行 codex 二进制程序的测试命令。它会把 CODEX_HOME 和 HOME 指到临时目录,避免测试污染用户真实电脑。

数据流:输入一个临时的 codex_home 路径 → 找到测试构建出来的 codex 程序,并设置环境变量 → 输出一个可继续加参数、可执行的命令对象。

调用关系:大多数测试都通过它启动真实 CLI;codex_command_in 也先调用它,再额外设置当前工作目录。

调用图:被 29 处调用(codex_command_in, marketplace_list_fails_when_configured_local_marketplace_source_is_missing, marketplace_list_fails_when_configured_marketplace_name_is_invalid, marketplace_list_fails_when_configured_marketplace_snapshot_is_malformed, marketplace_list_fails_when_configured_marketplace_snapshot_is_missing, marketplace_list_fails_when_home_marketplace_is_malformed, marketplace_list_includes_home_marketplace_when_present, marketplace_list_includes_root_when_plugins_are_filtered_out, marketplace_list_json_includes_configured_git_marketplace_source, marketplace_list_json_keys_configured_source_by_root (+15 more));外部调用 2 个(new, cargo_bin)。

codex_command_in31–35 ↗
fn codex_command_in(codex_home: &Path, current_dir: &Path) -> Result<assert_cmd::Command>

作用:创建一个会在指定目录里运行的 codex 测试命令。它用于模拟用户站在某个项目目录里敲命令。

数据流:输入 CODEX_HOME 和当前目录 → 先用 codex_command 建好基础命令,再设置工作目录 → 输出可执行的命令对象。

调用关系:专门服务于“仓库里有本地市场但没有配置”的测试,帮助验证 CLI 不会误把当前目录里的市场当成已授权市场。

调用图:调用 1 个内部函数(codex_command);被 2 处调用(plugin_add_rejects_unconfigured_repo_local_marketplaces, plugin_list_excludes_unconfigured_repo_local_marketplaces)。

configured_local_marketplace37–46 ↗
fn configured_local_marketplace(source: &str) -> MarketplaceConfigUpdate<'_>

作用:生成一份“本地插件市场”的配置更新内容。测试用它把某个临时目录登记成用户配置里的市场来源。

数据流:输入市场源目录字符串 → 填入固定更新时间、来源类型 local、源路径等字段 → 输出一个可写入配置的 MarketplaceConfigUpdate 结构。

调用关系:多个 setup 函数会调用它,然后交给 record_user_marketplace 写进配置,形成测试所需的已配置市场。

调用图:被 6 处调用(setup_configured_marketplace_with_malformed_manifest, setup_configured_marketplace_without_manifest, setup_custom_marketplace_under_implicit_system_root, setup_local_marketplace, setup_local_marketplace_with_explicit_empty_products, setup_local_marketplace_with_implicit_system_roots)。

write_plugins_enabled_config48–56 ↗
fn write_plugins_enabled_config(codex_home: &Path) -> Result<()>

作用:写入一个最小配置文件,把插件功能开关打开。没有这一步,很多插件命令可能不会进入被测试的功能路径。

数据流:输入 CODEX_HOME 路径 → 在里面写入 config.toml,内容包含 [features] plugins = true → 磁盘上出现启用插件的配置文件。

调用关系:几乎所有搭建测试环境的函数都会先调用它,之后命令行测试才运行插件相关子命令。

调用图:被 11 处调用(marketplace_list_fails_when_home_marketplace_is_malformed, marketplace_list_includes_home_marketplace_when_present, marketplace_list_json_includes_configured_git_marketplace_source, marketplace_list_json_keys_configured_source_by_root, plugin_list_json_includes_configured_git_marketplace_source, setup_configured_marketplace_with_malformed_manifest, setup_configured_marketplace_without_manifest, setup_custom_marketplace_under_implicit_system_root, setup_local_marketplace, setup_local_marketplace_with_explicit_empty_products (+1 more));外部调用 2 个(join, write)。

write_marketplace_source_with_manifest58–77 ↗
fn write_marketplace_source_with_manifest(source: &Path, marketplace_manifest: &str) -> Result<()>

作用:在磁盘上造一个假的插件市场,并允许测试指定市场清单内容。它是搭建各种正常或特殊市场的底层工具。

数据流:输入市场根目录和一段 marketplace.json 内容 → 创建清单目录、插件目录和 plugin.json → 输出结果是磁盘上多了一套可被 CLI 扫描的市场文件。

调用关系write_marketplace_sourcewrite_marketplace_source_with_explicit_empty_products 都把具体清单交给它写,测试不直接重复造目录细节。

调用图:被 2 处调用(write_marketplace_source, write_marketplace_source_with_explicit_empty_products);外部调用 3 个(join, create_dir_all, write)。

write_marketplace_source79–95 ↗
fn write_marketplace_source(source: &Path) -> Result<()>

作用:创建一个标准的测试插件市场,里面有一个叫 sample 的插件。大多数正常路径测试都用它。

数据流:输入市场根目录 → 准备一份默认 marketplace.json,并交给 write_marketplace_source_with_manifest 写入 → 得到一个含 sample 插件的本地市场。

调用关系:它被普通市场列表、插件列表、Git 来源展示和默认 setup 函数复用,是这个测试文件里的基础假数据来源。

调用图:调用 1 个内部函数(write_marketplace_source_with_manifest);被 6 处调用(marketplace_list_includes_home_marketplace_when_present, marketplace_list_json_includes_configured_git_marketplace_source, marketplace_list_json_keys_configured_source_by_root, plugin_list_json_includes_configured_git_marketplace_source, setup_local_marketplace, setup_unconfigured_local_marketplace)。

write_marketplace_source_with_explicit_empty_products97–116 ↗
fn write_marketplace_source_with_explicit_empty_products(source: &Path) -> Result<()>

作用:创建一个特殊市场:插件存在,但策略里明确写了空的 products 列表。测试用它确认即使插件被产品过滤掉,市场根目录仍会显示。

数据流:输入市场根目录 → 准备带空 products 策略的清单 → 交给 write_marketplace_source_with_manifest 写成真实目录和文件。

调用关系:只被 setup_local_marketplace_with_explicit_empty_products 调用,用于市场列表过滤相关测试。

调用图:调用 1 个内部函数(write_marketplace_source_with_manifest);被 1 处调用(setup_local_marketplace_with_explicit_empty_products)。

setup_local_marketplace118–130 ↗
fn setup_local_marketplace() -> Result<(TempDir, TempDir)>

作用:搭建一个最常用的测试环境:插件功能已开启,本地市场已写好,也已登记到用户配置里。

数据流:无业务输入 → 创建两个临时目录,分别当 CODEX_HOME 和市场源;写配置、写市场文件、登记市场 → 返回这两个临时目录给测试使用。

调用关系:大量安装、移除、列表和 JSON 输出测试都从它开始,因为它代表一个正常用户已经配置好插件市场的状态。

调用图:调用 3 个内部函数(configured_local_marketplace, write_marketplace_source, write_plugins_enabled_config);被 15 处调用(marketplace_list_json_prints_configured_marketplaces, marketplace_list_shows_configured_marketplace_names, plugin_add_and_remove_updates_installed_plugin_config, plugin_add_json_prints_install_outcome, plugin_add_reinstalls_from_configured_marketplace_snapshot, plugin_add_rejects_cached_plugins_without_authorizing_marketplace_snapshot, plugin_list_available_requires_json, plugin_list_hides_version_for_cached_but_unconfigured_plugin, plugin_list_json_prints_available_plugins_when_requested, plugin_list_json_prints_installed_plugins (+5 more));外部调用 2 个(new, record_user_marketplace)。

setup_unconfigured_local_marketplace132–138 ↗
fn setup_unconfigured_local_marketplace() -> Result<(TempDir, TempDir)>

作用:搭建一个“目录里有市场文件,但用户没有登记它”的环境。它用来验证 CLI 不会偷偷信任未配置的本地市场。

数据流:无业务输入 → 创建 CODEX_HOME 和市场源目录,开启插件功能并写入市场文件,但不写市场登记配置 → 返回两个临时目录。

调用关系:被拒绝未配置仓库市场的列表和安装测试使用,通常配合 codex_command_in 模拟用户在该市场目录里运行命令。

调用图:调用 2 个内部函数(write_marketplace_source, write_plugins_enabled_config);被 2 处调用(plugin_add_rejects_unconfigured_repo_local_marketplaces, plugin_list_excludes_unconfigured_repo_local_marketplaces);外部调用 1 个(new)。

setup_local_marketplace_with_explicit_empty_products140–152 ↗
fn setup_local_marketplace_with_explicit_empty_products() -> Result<(TempDir, TempDir)>

作用:搭建一个已配置市场,但其中插件策略把产品列表设为空的环境。它测试市场本身是否仍会出现在列表里。

数据流:无业务输入 → 创建临时 CODEX_HOME 和市场源,写启用配置,写特殊市场清单,并登记这个市场 → 返回两个临时目录。

调用关系:只服务于检查“插件被过滤但市场根目录还要显示”的市场列表测试。

调用图:调用 3 个内部函数(configured_local_marketplace, write_marketplace_source_with_explicit_empty_products, write_plugins_enabled_config);被 1 处调用(marketplace_list_includes_root_when_plugins_are_filtered_out);外部调用 2 个(new, record_user_marketplace)。

setup_configured_marketplace_without_manifest154–165 ↗
fn setup_configured_marketplace_without_manifest() -> Result<(TempDir, TempDir)>

作用:搭建一个配置里有市场、但市场目录里没有清单文件的坏环境。它用来测试错误提示是否清楚。

数据流:无业务输入 → 创建 CODEX_HOME 和空市场目录,开启插件功能,把空目录登记成市场 → 返回两个临时目录。

调用关系:市场列表和插件列表的失败测试会用它,然后检查 CLI 是否报告“市场根目录没有支持的清单”。

调用图:调用 2 个内部函数(configured_local_marketplace, write_plugins_enabled_config);被 2 处调用(marketplace_list_fails_when_configured_marketplace_snapshot_is_missing, plugin_list_fails_when_configured_marketplace_snapshot_is_missing);外部调用 2 个(new, record_user_marketplace)。

setup_configured_marketplace_with_malformed_manifest167–187 ↗
fn setup_configured_marketplace_with_malformed_manifest() -> Result<(TempDir, TempDir)>

作用:搭建一个市场清单文件存在但内容不是合法 JSON 的坏环境。JSON 可以理解为一种机器可读的文本格式,这里故意写坏。

数据流:无业务输入 → 创建临时目录,开启插件功能,写入内容损坏的 marketplace.json,并登记市场 → 返回 CODEX_HOME 和市场源。

调用关系:添加插件和列市场的失败测试会调用它,验证 CLI 能把解析失败原因显示给用户。

调用图:调用 2 个内部函数(configured_local_marketplace, write_plugins_enabled_config);被 2 处调用(marketplace_list_fails_when_configured_marketplace_snapshot_is_malformed, plugin_add_fails_when_configured_marketplace_snapshot_is_malformed);外部调用 4 个(new, record_user_marketplace, create_dir_all, write)。

setup_local_marketplace_with_implicit_system_roots189–221 ↗
fn setup_local_marketplace_with_implicit_system_roots() -> Result<(TempDir, TempDir, TempDir)>

作用:搭建一个正常用户市场,再额外造两个系统默认位置的市场根目录但不放清单。它测试系统内置路径缺清单时是否应被安静忽略。

数据流:无业务输入 → 先调用 setup_local_marketplace,再创建 bundled 和 runtime 两类系统路径并登记它们 → 返回 CODEX_HOME、正常市场和缓存目录。

调用关系:被插件列表测试使用,用来确认 CLI 仍能列出正常市场,同时不因为系统默认空目录而报错。

调用图:调用 2 个内部函数(configured_local_marketplace, setup_local_marketplace);被 1 处调用(plugin_list_ignores_implicit_system_marketplace_roots_without_manifests);外部调用 3 个(new, record_user_marketplace, create_dir_all)。

setup_custom_marketplace_under_implicit_system_root223–241 ↗
fn setup_custom_marketplace_under_implicit_system_root() -> Result<(TempDir, std::path::PathBuf)>

作用:搭建一个名字像自定义市场、但路径放在系统默认根目录下面且没有清单的环境。它测试这种情况不能被当作可忽略的系统市场。

数据流:无业务输入 → 创建 CODEX_HOME,开启插件功能,创建 custom-marketplace 空目录并登记 → 返回 CODEX_HOME 和这个自定义根目录。

调用关系:被插件列表失败测试调用,用来验证只有真正的隐式系统市场能被忽略,自定义配置仍必须有有效清单。

调用图:调用 2 个内部函数(configured_local_marketplace, write_plugins_enabled_config);被 1 处调用(plugin_list_fails_for_custom_marketplace_under_system_root);外部调用 3 个(new, record_user_marketplace, create_dir_all)。

remove_installed_plugin_config243–265 ↗
fn remove_installed_plugin_config(codex_home: &Path, plugin_key: &str) -> Result<()>

作用:从配置文件里手动删掉某个已安装插件的配置段。它模拟“缓存里还有插件文件,但配置里已经不承认它”的状态。

数据流:输入 CODEX_HOME 和插件键名 → 读取 config.toml,跳过对应 [plugins."..."] 段落,再写回文件 → 配置中该插件记录消失,其他内容保留。

调用关系:只被“缓存插件但未配置时隐藏版本号”的测试使用,用来制造正常命令很难产生的边界状态。

调用图:被 1 处调用(plugin_list_hides_version_for_cached_but_unconfigured_plugin);外部调用 5 个(join, new, format!, read_to_string, write)。

setup_configured_local_marketplace_with_missing_source267–279 ↗
fn setup_configured_local_marketplace_with_missing_source() -> Result<TempDir>

作用:创建一个市场配置缺少 source 路径的坏配置。它用来确认 CLI 能指出配置不完整,而不是崩掉或误读。

数据流:无业务输入 → 创建临时 CODEX_HOME,写入启用插件和 marketplaces.debug,但只写 source_type 不写 source → 返回这个 CODEX_HOME。

调用关系:市场列表失败测试会用它启动 CLI,并检查错误里是否包含“本地市场 source 缺失或为空”。

调用图:被 1 处调用(marketplace_list_fails_when_configured_local_marketplace_source_is_missing);外部调用 2 个(new, write)。

setup_configured_local_marketplace_with_invalid_name281–294 ↗
fn setup_configured_local_marketplace_with_invalid_name() -> Result<TempDir>

作用:创建一个市场名非法的坏配置,比如名字里带斜杠。它测试程序是否拒绝可能造成路径混乱的市场名。

数据流:无业务输入 → 创建临时 CODEX_HOME,写入启用插件和名为 bad/name 的市场配置 → 返回这个 CODEX_HOME。

调用关系:市场列表失败测试会用它,然后通过 assert_marketplace_failure 检查错误信息是否点名这个坏市场名。

调用图:被 1 处调用(marketplace_list_fails_when_configured_marketplace_name_is_invalid);外部调用 2 个(new, write)。

assert_configured_marketplace_snapshot_failure296–309 ↗
fn assert_configured_marketplace_snapshot_failure(
    assert: assert_cmd::assert::Assert,
    source: &Path,
    detail: &str,
)

作用:封装一组常见断言,专门检查“已配置市场快照加载失败”的错误输出。这样多个测试不用重复写同样检查。

数据流:输入命令执行结果、市场路径和期望错误细节 → 要求命令失败,并检查 stderr 是否包含固定标题、市场名、路径和细节 → 不返回业务数据,只在不符合时让测试失败。

调用关系:插件列表和插件添加的坏清单测试会调用它,统一验证错误信息格式。

调用图:被 2 处调用(plugin_add_fails_when_configured_marketplace_snapshot_is_malformed, plugin_list_fails_when_configured_marketplace_snapshot_is_missing);外部调用 3 个(failure, display, contains)。

assert_marketplace_failure311–323 ↗
fn assert_marketplace_failure(
    assert: assert_cmd::assert::Assert,
    marketplace_name: &str,
    source: &Path,
    detail: &str,
)

作用:封装市场加载失败时的错误输出检查。它让测试重点关注场景本身,而不是反复写字符串匹配。

数据流:输入命令执行结果、市场名、源路径和错误细节 → 断言命令失败,并检查 stderr 里包含这些关键信息 → 若缺任何一项,测试失败。

调用关系:多个 marketplace list 失败测试把命令结果交给它,用同一套规则确认报错对用户有帮助。

调用图:被 3 处调用(marketplace_list_fails_when_configured_marketplace_name_is_invalid, marketplace_list_fails_when_configured_marketplace_snapshot_is_malformed, marketplace_list_fails_when_configured_marketplace_snapshot_is_missing);外部调用 4 个(failure, display, format!, contains)。

marketplace_list_shows_configured_marketplace_names326–339 ↗
async fn marketplace_list_shows_configured_marketplace_names() -> Result<()>

作用:测试普通文本模式下,已配置的市场会出现在市场列表里。它还确认输出不是用制表符乱排版。

数据流:先搭建正常本地市场 → 运行 plugin marketplace list → 检查命令成功、表头存在、debug 这一行和路径存在、输出没有 tab。

调用关系:它使用 setup_local_marketplace 准备环境,用 marketplace_list_row 生成预期行,再通过 codex_command 运行真实 CLI。

调用图:调用 3 个内部函数(codex_command, marketplace_list_row, setup_local_marketplace);外部调用 1 个(contains)。

marketplace_list_json_prints_configured_marketplaces342–370 ↗
async fn marketplace_list_json_prints_configured_marketplaces() -> Result<()>

作用:测试市场列表的 JSON 输出是否准确。JSON 是给程序读取的结构化文本,所以字段名和值必须稳定。

数据流:搭建正常本地市场 → 运行 plugin marketplace list --json → 把 stdout 解析成 JSON,并和预期对象逐字段比较。

调用关系:它验证 CLI 给自动化工具看的输出;环境来自 setup_local_marketplace,命令由 codex_command 启动。

调用图:调用 2 个内部函数(codex_command, setup_local_marketplace);外部调用 2 个(assert_eq!, from_slice)。

marketplace_list_json_includes_configured_git_marketplace_source373–417 ↗
async fn marketplace_list_json_includes_configured_git_marketplace_source() -> Result<()>

作用:测试当市场来源是 Git 仓库时,JSON 里会显示原始 Git 来源,而不是只显示本地缓存路径。Git 可以理解为代码仓库地址。

数据流:创建缓存式市场目录并写入清单 → 把配置登记为 git 来源 → 运行市场 JSON 列表 → 检查 root 是规范化本地路径,marketplaceSource 是 Git URL。

调用关系:它自己搭建较特殊的 Git 配置,调用写配置、写市场和路径规范化工具,再通过 CLI 输出验证来源信息没有丢。

调用图:调用 3 个内部函数(codex_command, write_marketplace_source, write_plugins_enabled_config);外部调用 5 个(new, assert_eq!, record_user_marketplace, canonicalize_existing_preserving_symlinks, from_slice)。

marketplace_list_json_keys_configured_source_by_root420–471 ↗
async fn marketplace_list_json_keys_configured_source_by_root() -> Result<()>

作用:测试当 HOME 目录和配置缓存目录里都有同名市场时,配置来源信息只挂到正确的根目录上。

数据流:创建两个同名 debug 市场,一个在 HOME,一个在配置缓存根 → 登记 Git 来源的配置市场 → 运行 JSON 列表 → 检查 HOME 市场没有 marketplaceSource,缓存市场才有。

调用关系:它覆盖容易混淆的同名市场场景,确保 CLI 按根目录识别来源,而不是只按市场名粗暴匹配。

调用图:调用 3 个内部函数(codex_command, write_marketplace_source, write_plugins_enabled_config);外部调用 5 个(new, assert_eq!, record_user_marketplace, canonicalize_existing_preserving_symlinks, from_slice)。

marketplace_list_includes_home_marketplace_when_present474–491 ↗
async fn marketplace_list_includes_home_marketplace_when_present() -> Result<()>

作用:测试用户 HOME 目录下存在市场清单时,市场列表会自动包含它。

数据流:创建临时 CODEX_HOME 和 HOME,在 HOME 写市场文件并开启插件 → 运行市场列表 → 检查输出包含 HOME 里的 debug 市场行。

调用关系:它直接调用写市场和写配置工具,再用 codex_command 覆盖 HOME 环境变量模拟用户目录。

调用图:调用 4 个内部函数(codex_command, marketplace_list_row, write_marketplace_source, write_plugins_enabled_config);外部调用 2 个(new, contains)。

marketplace_list_includes_root_when_plugins_are_filtered_out494–506 ↗
async fn marketplace_list_includes_root_when_plugins_are_filtered_out() -> Result<()>

作用:测试即使市场里的插件因为产品策略被过滤掉,市场根目录本身仍会显示在市场列表里。

数据流:搭建带空 products 策略的已配置市场 → 运行市场列表 → 检查表头和 debug 市场路径仍在输出中。

调用关系:它依赖 setup_local_marketplace_with_explicit_empty_products 制造特殊清单,关注市场发现逻辑而不是插件可用性。

调用图:调用 3 个内部函数(codex_command, marketplace_list_row, setup_local_marketplace_with_explicit_empty_products);外部调用 1 个(contains)。

marketplace_list_fails_when_configured_marketplace_snapshot_is_missing509–522 ↗
async fn marketplace_list_fails_when_configured_marketplace_snapshot_is_missing() -> Result<()>

作用:测试配置里登记了市场,但对应目录没有清单时,市场列表会失败并说明原因。

数据流:搭建缺少 manifest 的市场 → 运行 plugin marketplace list → 把结果交给公共断言,检查失败标题、市场名、路径和缺清单说明。

调用关系:它用 setup_configured_marketplace_without_manifest 制造坏状态,再用 assert_marketplace_failure 统一检查报错。

调用图:调用 3 个内部函数(assert_marketplace_failure, codex_command, setup_configured_marketplace_without_manifest)。

marketplace_list_fails_when_configured_marketplace_name_is_invalid525–538 ↗
async fn marketplace_list_fails_when_configured_marketplace_name_is_invalid() -> Result<()>

作用:测试市场名非法时,市场列表不会继续装作正常,而是明确失败。

数据流:写入带 bad/name 市场名的配置 → 运行市场列表 → 检查错误中包含这个名字、无效配置来源和“市场名”相关提示。

调用关系:它调用坏配置 setup,再把 CLI 结果交给 assert_marketplace_failure

调用图:调用 3 个内部函数(assert_marketplace_failure, codex_command, setup_configured_local_marketplace_with_invalid_name);外部调用 1 个(new)。

marketplace_list_fails_when_configured_local_marketplace_source_is_missing541–557 ↗
async fn marketplace_list_fails_when_configured_local_marketplace_source_is_missing() -> Result<()>

作用:测试本地市场配置缺少 source 字段时,命令会给出清楚错误。

数据流:创建缺 source 的市场配置 → 运行市场列表 → 检查命令失败,并在 stderr 中找到 debug、无效 source 和缺失说明。

调用关系:它直接使用 setup_configured_local_marketplace_with_missing_sourcecodex_command,不走公共断言,因为这个错误的路径文字是特殊的。

调用图:调用 2 个内部函数(codex_command, setup_configured_local_marketplace_with_missing_source);外部调用 1 个(contains)。

marketplace_list_fails_when_home_marketplace_is_malformed560–582 ↗
async fn marketplace_list_fails_when_home_marketplace_is_malformed() -> Result<()>

作用:测试 HOME 目录下的市场清单写坏时,市场列表会失败并指出是哪一个文件解析失败。

数据流:在临时 HOME 写入损坏的 marketplace.json → 运行市场列表 → 检查失败输出包含文件路径和 JSON 解析错误。

调用关系:它自己创建坏 HOME 市场,验证自动发现的 HOME 市场也会被严格校验。

调用图:调用 2 个内部函数(codex_command, write_plugins_enabled_config);外部调用 4 个(new, contains, create_dir_all, write)。

marketplace_list_fails_when_configured_marketplace_snapshot_is_malformed585–598 ↗
async fn marketplace_list_fails_when_configured_marketplace_snapshot_is_malformed() -> Result<()>

作用:测试已配置市场的清单 JSON 损坏时,市场列表会失败并显示解析错误。

数据流:搭建有坏 marketplace.json 的配置市场 → 运行市场列表 → 使用公共断言检查失败信息包含市场名、路径和解析细节。

调用关系:它复用 setup_configured_marketplace_with_malformed_manifestassert_marketplace_failure,覆盖配置市场的坏清单路径。

调用图:调用 3 个内部函数(assert_marketplace_failure, codex_command, setup_configured_marketplace_with_malformed_manifest)。

plugin_list_prints_plugins_in_a_table601–625 ↗
async fn plugin_list_prints_plugins_in_a_table() -> Result<()>

作用:测试普通文本模式下,插件列表会以表格形式显示可用插件和关键信息。

数据流:搭建正常市场 → 运行 plugin list → 检查输出包含市场标题、列名、清单路径、sample@debug、未安装状态和插件路径。

调用关系:它验证人类用户直接看的输出格式,依赖 setup_local_marketplace 和真实 CLI。

调用图:调用 2 个内部函数(codex_command, setup_local_marketplace);外部调用 1 个(contains)。

plugin_list_json_prints_available_plugins_when_requested628–668 ↗
async fn plugin_list_json_prints_available_plugins_when_requested() -> Result<()>

作用:测试请求可用插件并要求 JSON 时,输出会包含未安装插件的完整信息。

数据流:搭建正常市场 → 运行 plugin list --available --json → 解析 stdout 并比较 installed 为空、available 里有 sample 的版本、来源、策略等字段。

调用关系:它覆盖自动化工具可能依赖的插件发现接口,使用 setup_local_marketplace 准备标准市场。

调用图:调用 2 个内部函数(codex_command, setup_local_marketplace);外部调用 2 个(assert_eq!, from_slice)。

plugin_list_json_includes_configured_git_marketplace_source671–727 ↗
async fn plugin_list_json_includes_configured_git_marketplace_source() -> Result<()>

作用:测试插件列表 JSON 在 Git 市场场景下,也能保留市场的 Git 来源信息。

数据流:创建本地缓存市场文件,但配置记录为 Git 来源 → 运行 plugin list --available --json → 检查插件路径被规范化,marketplaceSource 显示 Git URL。

调用关系:它和市场列表的 Git 测试互相补充,确认插件级 JSON 输出也不会丢掉市场来源。

调用图:调用 3 个内部函数(codex_command, write_marketplace_source, write_plugins_enabled_config);外部调用 5 个(new, assert_eq!, record_user_marketplace, canonicalize_existing_preserving_symlinks, from_slice)。

plugin_list_json_prints_installed_plugins730–775 ↗
async fn plugin_list_json_prints_installed_plugins() -> Result<()>

作用:测试插件安装后,JSON 插件列表会把它放进 installed,而不是 available。

数据流:搭建市场 → 先运行 plugin add sample@debug 安装 → 再运行 plugin list --json → 解析并检查 installed 里有启用的 sample,available 为空。

调用关系:它串起添加命令和列表命令,验证配置写入后的状态能被后续命令正确读到。

调用图:调用 2 个内部函数(codex_command, setup_local_marketplace);外部调用 2 个(assert_eq!, from_slice)。

plugin_list_available_requires_json778–791 ↗
async fn plugin_list_available_requires_json() -> Result<()>

作用:测试 --available 这个选项必须和 --json 一起用。这样可以避免普通表格模式下语义不清。

数据流:搭建正常市场 → 运行 plugin list --available 但不加 --json → 检查命令失败并提示缺少 --json

调用关系:它验证命令行参数规则本身,环境仍用标准市场 setup。

调用图:调用 2 个内部函数(codex_command, setup_local_marketplace);外部调用 1 个(contains)。

plugin_list_shows_installed_version_when_plugin_is_installed794–811 ↗
async fn plugin_list_shows_installed_version_when_plugin_is_installed() -> Result<()>

作用:测试插件安装后,普通列表会显示版本号和“已安装、已启用”状态。

数据流:搭建市场 → 安装 sample@debug → 运行普通 plugin list → 检查输出包含插件 ID、版本 1.2.3 和 installed, enabled。

调用关系:它关注人类可读列表里的安装状态展示,先通过 plugin add 制造已安装状态。

调用图:调用 2 个内部函数(codex_command, setup_local_marketplace);外部调用 1 个(contains)。

plugin_list_excludes_unconfigured_repo_local_marketplaces814–825 ↗
async fn plugin_list_excludes_unconfigured_repo_local_marketplaces() -> Result<()>

作用:测试当前目录里虽然有市场文件,但没有登记配置时,插件列表不会把它当作可用市场。

数据流:搭建未配置市场并把当前目录切到该市场源 → 运行 plugin list --marketplace debug → 检查提示没有插件,并确认不出现 sample@debug。

调用关系:它使用 setup_unconfigured_local_marketplacecodex_command_in,验证安全边界:只信任配置过的市场。

调用图:调用 2 个内部函数(codex_command_in, setup_unconfigured_local_marketplace);外部调用 2 个(contains, is_match)。

plugin_list_fails_when_configured_marketplace_snapshot_is_missing828–840 ↗
async fn plugin_list_fails_when_configured_marketplace_snapshot_is_missing() -> Result<()>

作用:测试插件列表遇到已配置但缺清单的市场时,会以配置市场快照加载失败的形式报错。

数据流:搭建无 manifest 的配置市场 → 运行 plugin list → 用公共断言检查失败信息包含市场路径和缺清单原因。

调用关系:它和市场列表的缺清单测试类似,但覆盖的是插件列表入口,调用 assert_configured_marketplace_snapshot_failure

调用图:调用 3 个内部函数(assert_configured_marketplace_snapshot_failure, codex_command, setup_configured_marketplace_without_manifest)。

plugin_list_ignores_implicit_system_marketplace_roots_without_manifests843–866 ↗
async fn plugin_list_ignores_implicit_system_marketplace_roots_without_manifests() -> Result<()>

作用:测试系统默认的内置市场目录如果没有清单,不会让插件列表失败。

数据流:搭建一个正常市场,再造两个无清单的系统默认市场根 → 设置 XDG_CACHE_HOME 后运行插件列表 → 检查正常市场出现,stderr 没有快照加载失败。

调用关系:它依赖 setup_local_marketplace_with_implicit_system_roots,确认系统隐式路径的容错规则。

调用图:调用 2 个内部函数(codex_command, setup_local_marketplace_with_implicit_system_roots);外部调用 1 个(contains)。

plugin_list_fails_for_custom_marketplace_under_system_root869–886 ↗
async fn plugin_list_fails_for_custom_marketplace_under_system_root() -> Result<()>

作用:测试自定义市场即使放在系统默认路径下面,缺清单也必须报错。名字不是系统保留市场,就不能被静默忽略。

数据流:搭建 custom-marketplace 空目录并登记 → 运行插件列表 → 检查命令失败,错误里有市场名、路径和缺清单说明。

调用关系:它和忽略系统市场的测试形成对照,使用 setup_custom_marketplace_under_implicit_system_root 制造边界情况。

调用图:调用 2 个内部函数(codex_command, setup_custom_marketplace_under_implicit_system_root);外部调用 1 个(contains)。

plugin_list_hides_version_for_cached_but_unconfigured_plugin889–908 ↗
async fn plugin_list_hides_version_for_cached_but_unconfigured_plugin() -> Result<()>

作用:测试插件文件还在缓存里、但配置记录被删掉时,列表不会显示它的版本号。这样避免把未安装状态说得像已确认安装。

数据流:搭建并安装插件 → 手动删除配置里的插件段 → 运行插件列表 → 检查仍能看到 sample@debug 和 not installed,但看不到 1.2.3。

调用关系:它调用 remove_installed_plugin_config 制造不一致状态,验证列表展示对配置状态更谨慎。

调用图:调用 3 个内部函数(codex_command, remove_installed_plugin_config, setup_local_marketplace);外部调用 1 个(contains)。

plugin_add_and_remove_updates_installed_plugin_config911–935 ↗
async fn plugin_add_and_remove_updates_installed_plugin_config() -> Result<()>

作用:测试安装和移除插件会正确改写用户配置文件。配置文件是之后判断插件是否已安装的依据。

数据流:搭建市场 → 运行 add,检查输出并读取配置确认出现 [plugins."sample@debug"] → 运行 remove,再读取配置确认该段消失。

调用关系:它串联 plugin addplugin remove,直接检查磁盘上的 config.toml 是否跟用户操作一致。

调用图:调用 2 个内部函数(codex_command, setup_local_marketplace);外部调用 3 个(assert!, contains, read_to_string)。

plugin_add_json_prints_install_outcome938–963 ↗
async fn plugin_add_json_prints_install_outcome() -> Result<()>

作用:测试安装插件时加 --json,命令会输出机器可读的安装结果。

数据流:搭建市场 → 运行 plugin add sample@debug --json → 解析 JSON,并检查插件 ID、名字、市场名、版本、安装路径和授权策略。

调用关系:它验证安装命令给脚本和工具使用的输出格式,并用路径规范化工具对安装目录做准确比较。

调用图:调用 2 个内部函数(codex_command, setup_local_marketplace);外部调用 3 个(assert_eq!, canonicalize_existing_preserving_symlinks, from_slice)。

plugin_remove_json_prints_remove_outcome966–998 ↗
async fn plugin_remove_json_prints_remove_outcome() -> Result<()>

作用:测试移除插件时加 --json,会输出简洁的移除结果。

数据流:搭建市场并先安装插件 → 运行 plugin remove sample --marketplace debug --json → 解析 JSON,确认包含 pluginId、name 和 marketplaceName。

调用关系:它先用添加命令建立可移除状态,再检查移除命令的机器可读输出。

调用图:调用 2 个内部函数(codex_command, setup_local_marketplace);外部调用 2 个(assert_eq!, from_slice)。

plugin_add_rejects_unconfigured_repo_local_marketplaces1001–1013 ↗
async fn plugin_add_rejects_unconfigured_repo_local_marketplaces() -> Result<()>

作用:测试当前目录里有未配置的本地市场时,安装命令不能从里面安装插件。

数据流:搭建未登记的市场并在该目录运行命令 → 执行 plugin add sample@debug → 检查命令失败并提示找不到该插件。

调用关系:它和未配置市场的列表测试一起验证安全规则:只从用户明确配置的市场安装。

调用图:调用 2 个内部函数(codex_command_in, setup_unconfigured_local_marketplace);外部调用 1 个(contains)。

plugin_add_fails_when_configured_marketplace_snapshot_is_malformed1016–1028 ↗
async fn plugin_add_fails_when_configured_marketplace_snapshot_is_malformed() -> Result<()>

作用:测试已配置市场的清单损坏时,安装插件会失败并显示清楚的解析错误。

数据流:搭建坏 JSON 清单的配置市场 → 运行 plugin add sample@debug → 用公共断言检查加载快照失败、路径和错误细节。

调用关系:它覆盖安装入口的坏清单处理,复用 setup_configured_marketplace_with_malformed_manifest 和快照失败断言。

调用图:调用 3 个内部函数(assert_configured_marketplace_snapshot_failure, codex_command, setup_configured_marketplace_with_malformed_manifest)。

plugin_add_reinstalls_from_configured_marketplace_snapshot1031–1053 ↗
async fn plugin_add_reinstalls_from_configured_marketplace_snapshot() -> Result<()>

作用:测试重复安装同一个插件仍会成功,并确保缓存里的插件文件存在。它覆盖“重新安装”这条常见路径。

数据流:搭建市场 → 第一次 add 安装 → 第二次 add 同一插件 → 检查成功提示,并确认缓存目录里的 plugin.json 是文件。

调用关系:它用真实 CLI 连续执行两次安装,验证安装逻辑能从已配置市场快照重新复制插件。

调用图:调用 2 个内部函数(codex_command, setup_local_marketplace);外部调用 2 个(assert!, contains)。

plugin_remove_works_after_marketplace_is_removed1056–1081 ↗
async fn plugin_remove_works_after_marketplace_is_removed() -> Result<()>

作用:测试市场配置被移除后,已经安装的插件仍然可以被移除。用户不应该因为市场不见了就删不掉插件配置。

数据流:搭建市场并安装插件 → 移除 debug 市场 → 再移除 sample@debug 插件 → 检查成功提示,并确认配置里插件段消失。

调用关系:它串联添加、移除市场、移除插件三个命令,验证卸载只需要已有插件配置,不依赖市场仍存在。

调用图:调用 2 个内部函数(codex_command, setup_local_marketplace);外部调用 3 个(assert!, contains, read_to_string)。

plugin_add_rejects_cached_plugins_without_authorizing_marketplace_snapshot1084–1114 ↗
async fn plugin_add_rejects_cached_plugins_without_authorizing_marketplace_snapshot() -> Result<()>

作用:测试插件虽然已经在本地缓存里,但对应市场被移除后,不能仅凭缓存再次安装。这样防止绕过市场授权。

数据流:搭建市场并安装插件,让缓存文件存在 → 移除市场配置 → 再尝试 add 同一插件 → 检查失败并提示在该市场找不到插件。

调用关系:它验证安全边界:安装必须有有效的市场快照授权,缓存只是文件副本,不能单独作为信任来源。

调用图:调用 2 个内部函数(codex_command, setup_local_marketplace);外部调用 2 个(assert!, contains)。

cli/tests/marketplace_add.rs源码 ↗
testtest run

这个测试文件像一组自动验收脚本。它先在临时目录里搭一个假的插件市场:里面有 marketplace.json 清单、一个 sample 插件、还有标记文件。然后它启动真正的 codex 命令行程序,模拟用户运行 plugin marketplace add。测试重点不是插件本身能不能运行,而是“添加市场”这一步有没有做对:本地目录应该被记录到配置文件里,而不是被复制安装;加 --json 时应该打印机器能读懂的 JSON 结果;如果用户传的是 marketplace.json 文件而不是目录,应该报错;如果本地目录还加 --sparse,也应该报错,因为这个选项只给 git 来源用。整个文件用临时目录隔离环境,就像每次考试都发一张新白纸,避免污染真实用户配置。

函数细节6
codex_command11–15 ↗
fn codex_command(codex_home: &Path) -> Result<assert_cmd::Command>

作用:这个函数准备一个可以运行的 codex 命令行程序,并把它的“家目录”指向测试用的临时目录。这样测试不会碰到开发者电脑上的真实配置。

数据流:输入是一个 codex_home 路径 → 它找到测试要运行的 codex 可执行文件,创建一个命令对象,并设置环境变量 CODEX_HOME → 输出一个已经配置好的命令对象,后面的测试可以继续给它加参数并执行。

调用关系:四个测试都会先调用它来启动 codex。它把底层找二进制文件和设置环境变量的细节包起来,让每个测试只关心自己要跑什么命令。

调用图:被 4 处调用(marketplace_add_json_prints_add_outcome, marketplace_add_local_directory_source, marketplace_add_rejects_local_manifest_file_source, marketplace_add_rejects_sparse_for_local_directory_source);外部调用 2 个(new, cargo_bin)。

write_marketplace_source17–41 ↗
fn write_marketplace_source(source: &Path, marker: &str) -> Result<()>

作用:这个函数在磁盘上造出一个假的本地插件市场,供测试命令行去添加。没有它,每个测试都得重复手写目录和清单文件。

数据流:输入是一个源目录路径和一个 marker 字符串 → 它创建 .agents/plugins、插件目录和 .codex-plugin 目录,写入 marketplace.json、plugin.json,以及一个 marker.txt → 输出是磁盘上出现了一套看起来像真实 marketplace 的测试文件。

调用关系:四个测试都会调用它来准备同一类测试材料。之后 codex 命令会读取这些文件,判断这是一个名叫 debug、包含 sample 插件的本地 marketplace。

调用图:被 4 处调用(marketplace_add_json_prints_add_outcome, marketplace_add_local_directory_source, marketplace_add_rejects_local_manifest_file_source, marketplace_add_rejects_sparse_for_local_directory_source);外部调用 3 个(join, create_dir_all, write)。

marketplace_add_local_directory_source44–73 ↗
async fn marketplace_add_local_directory_source() -> Result<()>

作用:这个测试确认:用户从本地目录添加 marketplace 时,codex 会把这个目录登记到配置里,而不是把它复制到安装目录。

数据流:开始时创建两个临时目录,一个当 codex_home,一个当 marketplace 来源 → 写入假的 marketplace 文件,然后在来源目录的父目录下用相对路径运行 plugin marketplace add → 命令成功后,测试读取配置文件,检查 source_type 是 local,source 是规范化后的绝对路径,同时确认没有生成复制安装目录。

调用关系:它先用 write_marketplace_source 准备来源,再用 codex_command 启动命令行。命令跑完后,它还调用 marketplace_install_root 来确认本地 marketplace 没有被当成需要下载或复制的远程来源处理。

调用图:调用 3 个内部函数(codex_command, write_marketplace_source, marketplace_install_root);外部调用 6 个(new, assert!, assert_eq!, format!, read_to_string, from_str)。

marketplace_add_json_prints_add_outcome76–108 ↗
async fn marketplace_add_json_prints_add_outcome() -> Result<()>

作用:这个测试确认:添加本地 marketplace 时如果用户加了 --json,命令会输出清楚、稳定的 JSON 结果。这个结果通常给脚本或其他程序读取,而不是给人眼看。

数据流:开始时创建临时 codex_home 和假的 marketplace 来源 → 用相对路径运行 plugin marketplace add ... --json → 捕获标准输出,把它当 JSON 解析,再和预期内容比较:marketplace 名字是 debug,installedRoot 指向本地来源目录,alreadyAdded 是 false。

调用关系:它和普通添加测试使用同一套准备步骤:write_marketplace_source 造数据,codex_command 启动命令。区别是它重点检查命令输出,而不是配置文件内容;AbsolutePathBuf::try_from 用来把来源路径变成项目认可的绝对路径格式。

调用图:调用 3 个内部函数(codex_command, write_marketplace_source, try_from);外部调用 4 个(new, assert_eq!, format!, from_slice)。

marketplace_add_rejects_local_manifest_file_source111–131 ↗
async fn marketplace_add_rejects_local_manifest_file_source() -> Result<()>

作用:这个测试确认:用户不能直接把 marketplace.json 文件当成本地 marketplace 来源传进去。系统要求传的是目录,因为目录里还可能有插件文件和其他内容。

数据流:开始时创建临时 codex_home 和假的 marketplace 来源 → 取出其中的 .agents/plugins/marketplace.json 文件路径 → 用这个文件路径运行添加命令 → 结果应该失败,并且错误信息里明确说本地 marketplace 来源必须是目录,不是文件。

调用关系:它先用 write_marketplace_source 造出包含清单文件的来源,再用 codex_command 执行错误用法。contains 用来检查 stderr,也就是命令报错文字里是否包含预期提示。

调用图:调用 2 个内部函数(codex_command, write_marketplace_source);外部调用 2 个(new, contains)。

marketplace_add_rejects_sparse_for_local_directory_source134–155 ↗
async fn marketplace_add_rejects_sparse_for_local_directory_source() -> Result<()>

作用:这个测试确认:--sparse 选项不能用于本地目录 marketplace。--sparse 是给 git 来源做稀疏拉取用的,也就是只下载仓库里一部分内容,本地目录不需要也不支持这一套。

数据流:开始时创建临时 codex_home 和假的本地 marketplace 来源 → 运行 plugin marketplace add --sparse .agents <本地目录> → 命令应该失败,并在错误信息里说明 --sparse 只支持 git marketplace 来源。

调用关系:它同样用 write_marketplace_source 准备一个合法本地来源,用 codex_command 执行命令。但它故意加上不该出现的 --sparse 参数,验证命令行的参数检查会及时拦住这种误用。

调用图:调用 2 个内部函数(codex_command, write_marketplace_source);外部调用 2 个(new, contains)。

cli/tests/marketplace_remove.rs源码 ↗
testtest run

这个测试文件像是在给“删除插件市场”按钮做验收。插件市场既会写进用户配置文件,也会在本地磁盘上留下安装目录,所以删除时必须两边都处理干净。文件先用临时目录假装一个独立的 CODEX_HOME,也就是 Codex 的用户数据目录;再写入一条假的 marketplace 配置,并造出一个假的已安装目录。随后它真正启动 codex 命令行程序,执行移除命令。测试会检查三件事:普通输出要告诉用户删掉了;配置文件里不能再有这个 marketplace;本地安装目录也不能再存在。另一个测试检查 --json 模式,确保机器读取时能拿到准确的 marketplace 名称和安装路径。最后一个测试故意删除一个不存在的 marketplace,确认程序会失败并给出清楚的错误,而不是假装成功。

函数细节6
codex_command12–16 ↗
fn codex_command(codex_home: &Path) -> Result<assert_cmd::Command>

作用:这个辅助函数用来准备一次真正的 codex 命令行调用。它把测试用的临时目录设成 CODEX_HOME,这样测试不会碰到开发者电脑上的真实配置。

数据流:输入是一个临时的 Codex 用户目录路径。它先找到测试要运行的 codex 可执行文件,再创建一个命令对象,并给这个命令加上 CODEX_HOME 环境变量。输出是准备好的命令对象,后面的测试可以继续给它加参数并运行。

调用关系:三个测试函数都会先找它要一个干净的命令对象。它内部把“找到 codex 程序”和“设置测试目录”这两步做好,后面的测试只需要关心要执行哪些命令参数。

调用图:被 3 处调用(marketplace_remove_deletes_config_and_installed_root, marketplace_remove_json_prints_remove_outcome, marketplace_remove_rejects_unknown_marketplace);外部调用 2 个(new, cargo_bin)。

configured_marketplace_update18–27 ↗
fn configured_marketplace_update() -> MarketplaceConfigUpdate<'static>

作用:这个辅助函数造出一份固定的 marketplace 配置信息,用来模拟“用户已经添加过一个插件市场”。这样测试删除功能时,就有东西可以删。

数据流:它不需要外部输入。它直接返回一份包含更新时间、来源类型、仓库地址、分支名等信息的配置数据。它不写文件,只负责提供一块标准的测试数据。

调用关系:需要先登记 marketplace 的测试会调用它,然后把返回的数据交给 record_user_marketplace 写进临时配置里。它让多个测试使用同一套假配置,避免每个测试重复写一大段数据。

调用图:被 2 处调用(marketplace_remove_deletes_config_and_installed_root, marketplace_remove_json_prints_remove_outcome)。

write_installed_marketplace29–35 ↗
fn write_installed_marketplace(codex_home: &Path, marketplace_name: &str) -> Result<()>

作用:这个辅助函数在测试目录里造出一个假的已安装 marketplace。它的作用是模拟真实安装后磁盘上会出现的文件夹和标记文件。

数据流:输入是 Codex 用户目录和 marketplace 名字。它先根据用户目录算出 marketplace 的安装根目录,然后创建插件清单所在的文件夹,写入一个空的 marketplace.json,再写一个 marker.txt 表示这里确实被安装过。输出是成功或失败的结果;成功时磁盘上会多出这套测试文件。

调用关系:删除成功相关的两个测试会先调用它,把“已安装”的现场搭好。它把路径计算交给 marketplace_install_root,把具体建目录、写文件交给标准文件系统函数完成。

调用图:调用 1 个内部函数(marketplace_install_root);被 2 处调用(marketplace_remove_deletes_config_and_installed_root, marketplace_remove_json_prints_remove_outcome);外部调用 2 个(create_dir_all, write)。

marketplace_remove_deletes_config_and_installed_root38–58 ↗
async fn marketplace_remove_deletes_config_and_installed_root() -> Result<()>

作用:这个测试确认普通删除命令真的会同时删除配置记录和本地安装目录。它防止出现“命令说删了,但配置或文件还残留”的问题。

数据流:一开始它创建一个临时 Codex 用户目录,然后写入名为 debug 的 marketplace 配置,并造出对应的安装目录。接着它运行 codex plugin marketplace remove debug。运行成功后,它读取配置文件,确认里面不再包含 debug 的配置段;同时检查安装目录已经不存在。最后返回测试成功或错误。

调用关系:它是对正常删除流程的端到端测试,也就是从命令行入口一路跑到真实文件改动。它会用 codex_command 启动命令,用 configured_marketplace_update 准备配置数据,用 write_installed_marketplace 准备磁盘现场,再用断言检查结果。

调用图:调用 3 个内部函数(codex_command, configured_marketplace_update, write_installed_marketplace);外部调用 5 个(new, assert!, record_user_marketplace, contains, read_to_string)。

marketplace_remove_json_prints_remove_outcome61–84 ↗
async fn marketplace_remove_json_prints_remove_outcome() -> Result<()>

作用:这个测试确认用户加上 --json 后,删除命令会输出适合程序读取的 JSON 结果。它保证脚本或其他工具可以可靠地知道删掉了哪个 marketplace,以及它原来的安装位置。

数据流:它先创建临时用户目录,写入 debug 的配置,并造出安装目录。然后它算出这个安装目录的规范路径,运行 codex plugin marketplace remove debug --json,拿到标准输出,把输出解析成 JSON。最后它把实际 JSON 和预期 JSON 比较,确认里面有 marketplaceNameinstalledRoot,并且值完全一致。

调用关系:它测试的是同一个删除功能的机器可读输出分支。它和普通删除测试一样依赖 codex_commandconfigured_marketplace_updatewrite_installed_marketplace 搭现场,但额外使用路径规范化函数来得到应该出现在 JSON 里的安装路径。

调用图:调用 4 个内部函数(codex_command, configured_marketplace_update, write_installed_marketplace, marketplace_install_root);外部调用 5 个(new, assert_eq!, record_user_marketplace, canonicalize_existing_preserving_symlinks, from_slice)。

marketplace_remove_rejects_unknown_marketplace87–99 ↗
async fn marketplace_remove_rejects_unknown_marketplace() -> Result<()>

作用:这个测试确认删除一个不存在的 marketplace 时,命令会失败并说明原因。它防止程序误报成功,让用户以为删掉了其实从未配置或安装的东西。

数据流:它只创建一个空的临时 Codex 用户目录,不写任何 marketplace 配置,也不创建安装目录。然后它运行 codex plugin marketplace remove debug。预期结果是命令失败,并且错误输出里包含“这个 marketplace 没有配置或安装”的提示。

调用关系:它覆盖的是删除流程里的异常情况。它只需要 codex_command 来启动命令,再用输出匹配检查错误信息是否清楚,和前两个测试一起把成功、JSON 输出、失败三种常见场景都包住。

调用图:调用 1 个内部函数(codex_command);外部调用 2 个(new, contains)。

cli/tests/marketplace_upgrade.rs源码 ↗
test测试运行时

这个测试文件像一张验收清单,专门检查用户敲 marketplace upgrade 这类命令时,程序会不会走到正确入口、给出正确结果。它每次都先建一个临时的 CODEX_HOME,也就是一份干净的临时用户目录,避免测试碰到真实配置。然后它启动 codex 这个命令行程序,分别测试三件事:在 plugin marketplace upgrade 下能成功运行;加上 --json 后会打印可被机器读取的 JSON;旧的顶层 marketplace upgrade 不再被接受。这样可以防止以后有人改命令结构时,不小心把新入口弄坏,或者把已经废弃的旧入口又放回来。

函数细节4
codex_command8–12 ↗
fn codex_command(codex_home: &Path) -> Result<assert_cmd::Command>

作用:这个小工具函数用来准备一个可以运行 codex 命令的测试对象。它还会把 CODEX_HOME 指向临时目录,让每个测试都在干净环境里跑。

数据流:输入是一条临时目录路径 → 它找到测试用的 codex 可执行文件,创建一个命令对象,并把环境变量 CODEX_HOME 设置成这条路径 → 输出一个准备好的命令对象;如果找不到程序或创建失败,就把错误交回给调用者。

调用关系:三个测试都会先调用它,避免每个测试重复写启动 codex 的代码。它内部借助外部库找到 cargo 构建出的 codex 程序,再把配置目录塞进环境变量,然后把后续的参数和断言工作交回各个测试函数。

调用图:被 3 处调用(marketplace_upgrade_json_prints_upgrade_outcome, marketplace_upgrade_no_longer_runs_at_top_level, marketplace_upgrade_runs_under_plugin);外部调用 2 个(new, cargo_bin)。

marketplace_upgrade_runs_under_plugin15–25 ↗
async fn marketplace_upgrade_runs_under_plugin() -> Result<()>

作用:这个测试确认新的正确入口是 codex plugin marketplace upgrade。它关心的是:命令能成功结束,并且在没有配置任何 Git 市场时说清楚“没东西可升级”。

数据流:开始时创建一个临时用户目录 → 用 codex_command 生成命令,再传入 plugin marketplace upgrade 这些参数 → 程序运行后,测试检查退出状态是成功,并且标准输出里包含“No configured Git marketplaces to upgrade.”这句话。

调用关系:它是对新命令路径的基础验收。它把启动命令的准备工作交给 codex_command,把输出文字匹配交给测试库的 contains,用来证明插件子命令下的升级功能仍然可用。

调用图:调用 1 个内部函数(codex_command);外部调用 2 个(new, contains)。

marketplace_upgrade_json_prints_upgrade_outcome28–48 ↗
async fn marketplace_upgrade_json_prints_upgrade_outcome() -> Result<()>

作用:这个测试确认加上 --json 后,升级命令会输出固定结构的 JSON。JSON 是一种机器容易读取的文本格式,常用于脚本或其他程序接收结果。

数据流:开始时创建临时用户目录 → 运行 codex plugin marketplace upgrade --json → 读取程序标准输出,把它从字节内容解析成 JSON 值 → 和期望的 JSON 对象比较,确认选中的市场、升级的目录、错误列表都为空。

调用关系:它测试的是同一个升级命令的机器可读输出模式。它先通过 codex_command 启动程序,再用 JSON 解析函数检查输出不是随便一段文字,最后用断言比较完整结果,保证自动化工具依赖这个输出时不会被格式变化坑到。

调用图:调用 1 个内部函数(codex_command);外部调用 3 个(new, assert_eq!, from_slice)。

marketplace_upgrade_no_longer_runs_at_top_level51–61 ↗
async fn marketplace_upgrade_no_longer_runs_at_top_level() -> Result<()>

作用:这个测试确认旧入口 codex marketplace upgrade 已经不能用了。它防止命令层级被误改,让用户必须通过 plugin marketplace upgrade 这个新位置来执行升级。

数据流:开始时创建临时用户目录 → 用 codex_command 准备命令,再传入 marketplace upgrade → 程序运行后,测试要求它失败,并检查错误输出里包含“unrecognized subcommand 'upgrade'”。

调用关系:它和前两个测试形成对照:前两个证明新入口能用,这个证明旧入口不能用。它同样依赖 codex_command 创建隔离环境,并用 contains 检查报错文字,确保命令行结构符合现在的设计。

调用图:调用 1 个内部函数(codex_command);外部调用 2 个(new, contains)。

MCP 管理命令

这些测试验证 MCP 服务器配置生命周期命令,从添加和移除条目,到以文本和 JSON 形式列出与检查条目。

cli/tests/mcp_add_remove.rs源码 ↗
testtest

MCP 可以理解成一种让 Codex 连接外部工具或服务的方式;这里测试的是用户通过命令行添加、删除这些 MCP 服务器时,系统有没有把配置保存对。测试会给每个用例创建一个临时的 CODEX_HOME,也就是假的用户主目录,这样不会碰到真实用户文件。然后它启动真正的 codex 命令,像真人一样输入 mcp addmcp remove 等参数,再读取保存后的全局配置来核对结果。它覆盖了几类容易出错的地方:普通本地命令型服务器、带环境变量的服务器、HTTP 地址型服务器、OAuth 选项、已删除的旧参数、互斥参数冲突,以及旧版 profile 配置迁移提示。这个文件重要在于它不是只测某个小函数,而是从命令行入口一直测到磁盘配置结果,能发现“用户真实使用时才会遇到”的问题。

函数细节9
codex_command10–14 ↗
fn codex_command(codex_home: &Path) -> Result<assert_cmd::Command>

作用:这个小工具函数用来准备一个可运行的 codex 命令,并把它的用户目录指向测试专用的临时目录。这样每个测试都像在一个干净的新用户环境里运行,不会污染真实配置。

数据流:输入是一个临时目录路径 → 它找到测试要运行的 codex 可执行文件,创建命令对象,并设置 CODEX_HOME 环境变量 → 输出一个已经准备好的命令对象,后面的测试可以继续往里面加参数并执行。

调用关系:它是本文件所有测试的共同起点。各个测试先调用它拿到 codex 命令,再分别添加 mcp addmcp removemcp list 参数;它内部把找二进制文件和设置测试目录这两件重复工作包起来。

调用图:被 8 处调用(add_and_remove_server_updates_global_config, add_cant_add_command_and_url, add_streamable_http_rejects_removed_flag, add_streamable_http_with_custom_env_var, add_streamable_http_with_oauth_options, add_streamable_http_without_manual_token, add_with_env_preserves_key_order_and_values, profile_mcp_reports_legacy_profile_migration);外部调用 2 个(new, cargo_bin)。

add_and_remove_server_updates_global_config17–69 ↗
async fn add_and_remove_server_updates_global_config() -> Result<()>

作用:这个测试确认最基本的流程:添加一个本地命令型 MCP 服务器后,配置里真的出现它;删除后,配置里真的没有它;再次删除不存在的服务器时,也要给出友好的提示。

数据流:一开始创建一个空的临时用户目录 → 运行 codex mcp add docs -- echo hello → 读取全局 MCP 配置,检查里面有名叫 docs 的服务器,启动命令是 echo,参数是 hello,并且处于启用状态 → 再运行 codex mcp remove docs,读取配置确认已清空 → 最后再次删除 docs,确认命令成功但提示没找到,配置仍然为空。

调用关系:它通过 codex_command 启动真实命令,通过 load_global_mcp_servers 读取命令写下来的配置。断言和字符串匹配负责确认用户能看到正确提示,配置枚举检查负责确认内部保存格式没有跑偏。

调用图:调用 2 个内部函数(codex_command, load_global_mcp_servers);外部调用 5 个(new, assert!, assert_eq!, panic!, contains)。

profile_mcp_reports_legacy_profile_migration72–91 ↗
async fn profile_mcp_reports_legacy_profile_migration() -> Result<()>

作用:这个测试确认旧版 profile 配置遇到 MCP 命令时,会给用户清楚的迁移提示,而不是静默失败或误用旧配置。profile 可以理解成一套命名的使用配置,比如“work”工作配置。

数据流:先在临时用户目录里手动写入一个旧格式的 config.toml,里面有 [profiles.work] → 运行 codex --profile work mcp list → 预期命令失败,并在错误输出里说明这个 profile 不能这样用,同时提示旧配置位置和新的 work.config.toml 文件名。

调用关系:它先用普通文件写入模拟历史用户留下的旧配置,再用 codex_command 启动真实命令。这里不读取服务器列表,因为重点不是服务器内容,而是命令行在遇到旧 profile 时有没有把迁移信息讲清楚。

调用图:调用 1 个内部函数(codex_command);外部调用 3 个(new, contains, write)。

add_with_env_preserves_key_order_and_values94–127 ↗
async fn add_with_env_preserves_key_order_and_values() -> Result<()>

作用:这个测试确认添加本地命令型 MCP 服务器时,用户传入的环境变量会被完整保存。环境变量就是给子程序看的键值对,比如 FOO=bar

数据流:先创建空的临时用户目录 → 运行 codex mcp add envy --env FOO=bar --env ALPHA=beta -- python server.py → 读取全局 MCP 配置 → 找到 envy 服务器,检查它保存了两个环境变量,键和值都正确,并且服务器是启用状态。

调用关系:它复用 codex_command 执行添加命令,再交给 load_global_mcp_servers 读取落盘后的配置。它重点检查 McpServerTransportConfig::Stdio 这种本地进程启动方式里的环境变量部分,防止命令行解析或配置保存时丢值。

调用图:调用 2 个内部函数(codex_command, load_global_mcp_servers);外部调用 4 个(new, assert!, assert_eq!, panic!)。

add_streamable_http_without_manual_token130–161 ↗
async fn add_streamable_http_without_manual_token() -> Result<()>

作用:这个测试确认添加 HTTP 型 MCP 服务器时,如果用户只给 URL,不手动配置令牌,系统就只保存 URL,不偷偷创建凭据文件。HTTP 型服务器可以理解成通过网址连接的远程服务。

数据流:先创建一个干净的临时用户目录 → 运行 codex mcp add github --url https://example.com/mcp → 读取全局 MCP 配置 → 检查 github 被保存为 Streamable HTTP 类型,URL 正确,没有 bearer token 环境变量,也没有 HTTP 头配置 → 再确认目录里没有额外生成 .credentials.json.env 文件。

调用关系:它从命令行入口走完整流程:codex_command 负责启动命令,load_global_mcp_servers 负责验证结果。这个测试特别关注“没有提供令牌时不要自作主张保存敏感信息”这一行为。

调用图:调用 2 个内部函数(codex_command, load_global_mcp_servers);外部调用 4 个(new, assert!, assert_eq!, panic!)。

add_streamable_http_with_custom_env_var164–199 ↗
async fn add_streamable_http_with_custom_env_var() -> Result<()>

作用:这个测试确认用户可以给 HTTP 型 MCP 服务器指定一个保存访问令牌的环境变量名。也就是说,配置里只记“去哪个环境变量找令牌”,而不是直接写入令牌本身。

数据流:创建临时用户目录 → 运行 codex mcp add issues --url https://example.com/issues --bearer-token-env-var GITHUB_TOKEN → 读取全局 MCP 配置 → 找到 issues 服务器,确认 URL 正确,令牌环境变量名是 GITHUB_TOKEN,没有额外 HTTP 头配置,并且服务器启用。

调用关系:它同样通过 codex_command 执行真实 CLI,再用 load_global_mcp_servers 看配置结果。它和“不带手动令牌”的测试互相补充,确保 HTTP 服务器既能保持简单配置,也能支持用户自定义鉴权来源。

调用图:调用 2 个内部函数(codex_command, load_global_mcp_servers);外部调用 4 个(new, assert!, assert_eq!, panic!)。

add_streamable_http_with_oauth_options202–235 ↗
async fn add_streamable_http_with_oauth_options() -> Result<()>

作用:这个测试确认添加 HTTP 型 MCP 服务器时,OAuth 相关选项会被保存。OAuth 可以理解成一种常见的网页登录授权机制,让程序代表用户访问服务。

数据流:先创建临时用户目录 → 运行 codex mcp add oauth-server --url ... --oauth-client-id ... --oauth-resource ... → 读取全局 MCP 配置 → 找到 oauth-server,检查 OAuth 客户端 ID 和资源地址都保存成了期望值。

调用关系:它用 codex_command 从命令行发起添加操作,再用 load_global_mcp_servers 检查配置对象。它不细查 HTTP 传输的每个字段,而是专门盯住 OAuth 这两个鉴权字段有没有穿过命令行解析并写入配置。

调用图:调用 2 个内部函数(codex_command, load_global_mcp_servers);外部调用 2 个(new, assert_eq!)。

add_streamable_http_rejects_removed_flag238–259 ↗
async fn add_streamable_http_rejects_removed_flag() -> Result<()>

作用:这个测试确认一个已经废弃或移除的旧参数 --with-bearer-token 不会再被接受。这样可以避免用户以为开启了某种令牌保存功能,但实际行为已经改变。

数据流:创建空临时用户目录 → 运行带 --with-bearer-tokencodex mcp add github --url ... → 预期命令失败,并且错误信息里提到这个参数 → 再读取全局 MCP 配置,确认没有因为失败命令而留下半成品服务器。

调用关系:它通过 codex_command 检查命令行参数验证,通过 load_global_mcp_servers 检查失败后磁盘配置仍然干净。它的作用像一道门卫测试:不合法的旧入口必须挡住,不能悄悄写配置。

调用图:调用 2 个内部函数(codex_command, load_global_mcp_servers);外部调用 3 个(new, assert!, contains)。

add_cant_add_command_and_url262–286 ↗
async fn add_cant_add_command_and_url() -> Result<()>

作用:这个测试确认添加 MCP 服务器时,不能同时选择“本地命令启动”和“HTTP URL 连接”两种方式。因为这两种是不同类型的服务器入口,混在一起会让配置含义不清。

数据流:创建临时用户目录 → 运行一个同时带 --url--command 风格内容的添加命令 → 预期命令失败,并在错误输出里说明 --command 是意外参数 → 读取全局 MCP 配置,确认没有写入任何服务器。

调用关系:它使用 codex_command 触发真实的参数解析错误,再用 load_global_mcp_servers 验证错误没有留下配置副作用。它和其他成功添加的测试一起,证明 CLI 不只会写正确配置,也会拒绝容易误用的组合。

调用图:调用 2 个内部函数(codex_command, load_global_mcp_servers);外部调用 3 个(new, assert!, contains)。

cli/tests/mcp_list.rs源码 ↗
testtest

这个测试文件像一个“假用户”,临时建一个干净的 Codex 配置目录,然后真的去运行 codex 命令。它先检查没有配置 MCP 服务器时,列表命令会不会友好地提示“还没有配置”。接着它添加一个叫 docs 的 MCP 服务器,再手动改配置,让它包含命令、参数、环境变量和需要从外部读取的变量名,然后分别检查普通文本输出和 JSON 输出。这里特别重要的一点是:普通文本里密钥要被打码成 *****,不能把 TOKEN=secret 直接露出来;但 JSON 输出仍要准确反映真实配置,方便程序读取。最后它还测试禁用服务器时,get 命令只显示一行简洁结果。整体来说,这个文件保护的是命令行界面的“可读、准确、安全”。

函数细节4
codex_command14–18 ↗
fn codex_command(codex_home: &Path) -> Result<assert_cmd::Command>

作用:这个小工具函数用来创建一个可以运行 codex 命令的测试对象,并把它的配置目录指向测试用的临时目录。这样每个测试都像在一台全新的机器上运行,不会碰到用户真实配置。

数据流:进去的是一个 codex_home 路径,也就是测试专用的配置文件夹位置。函数先找到测试构建出来的 codex 可执行程序,再创建命令对象,并设置 CODEX_HOME 环境变量,让这个命令只读写这个临时文件夹。出来的是一个准备好的命令对象,后面的测试可以继续给它加参数并运行。

调用关系:它是这个测试文件里的共同入口工具。list_shows_empty_statelist_and_get_render_expected_outputget_disabled_server_shows_single_line 都会先调用它来准备命令;它内部把寻找 codex 可执行文件的工作交给外部的 cargo_bin,再用外部命令创建工具生成可运行命令。

调用图:被 3 处调用(get_disabled_server_shows_single_line, list_and_get_render_expected_output, list_shows_empty_state);外部调用 2 个(new, cargo_bin)。

list_shows_empty_state21–31 ↗
fn list_shows_empty_state() -> Result<()>

作用:这个测试确认:当用户还没有配置任何 MCP 服务器时,执行 codex mcp list 不会报错,而是显示一条清楚的空状态提示。

数据流:一开始它创建一个全新的临时配置目录,里面什么 MCP 配置都没有。然后它通过 codex_command 准备命令,传入 mcp list 参数并运行。运行结果出来后,它检查命令是否成功退出,再把标准输出从字节转成文字,最后确认文字里包含“还没有配置 MCP 服务器”的提示。

调用关系:这是最基础的列表场景测试。它依赖 codex_command 提供干净的命令运行环境,然后直接检查命令行输出;如果这个测试失败,说明用户第一次使用 mcp list 时可能会看到错误、空白或难懂的信息。

调用图:调用 1 个内部函数(codex_command);外部调用 3 个(from_utf8, new, assert!)。

list_and_get_render_expected_output34–139 ↗
async fn list_and_get_render_expected_output() -> Result<()>

作用:这个测试覆盖完整的正常使用场景:先添加一个 MCP 服务器,再检查 listget 的普通输出、JSON 输出是否都符合预期。它还重点确认敏感环境变量在给人看的文本里会被打码。

数据流:它先创建临时配置目录,然后运行 codex mcp add docs ... 添加一个服务器,里面有命令、参数和 TOKEN=secret 这样的环境变量。接着它读取刚写入的全局 MCP 配置,手动补上两个只声明名字的环境变量 APP_TOKENWORKSPACE_ID,再把配置写回去。之后它分别运行 mcp listmcp list --jsonmcp get docsmcp get docs --json。普通输出会被当成文字检查,确认名字、命令、状态、认证状态都出现,并且密钥显示为 *****;JSON 输出会被解析成结构化数据,确认每个字段和预期完全一致。

调用关系:这是本文件最核心的集成测试,串起了添加配置、读取配置、改写配置、列表展示和单项查看。它多次使用 codex_command 来模拟用户运行不同命令;用 load_global_mcp_servers 读取配置;用 ConfigEditsBuilder 把修改后的服务器配置写回磁盘;最后用断言工具检查输出内容。

调用图:调用 3 个内部函数(codex_command, new, load_global_mcp_servers);外部调用 8 个(from_utf8, new, assert!, assert_eq!, panic!, contains, from_str, vec!)。

get_disabled_server_shows_single_line142–166 ↗
async fn get_disabled_server_shows_single_line() -> Result<()>

作用:这个测试确认:如果某个 MCP 服务器被禁用了,codex mcp get <name> 会用一行非常简短的话说明它已禁用,而不是继续展开一大堆细节。

数据流:它先创建临时配置目录,再运行 codex mcp add docs -- docs-server 添加一个服务器。然后它读取配置,找到 docs 这一项,把它的 enabled 改成 false,也就是禁用,再写回配置文件。最后运行 mcp get docs,把输出转成文字,并确认去掉末尾换行后,内容正好是 docs (disabled)

调用关系:这个测试关注的是禁用状态下的单项查看体验。它和完整场景测试一样,通过 codex_command 运行真实命令,通过 load_global_mcp_serversConfigEditsBuilder 改配置;不同的是,它只检查禁用服务器的特殊显示规则,确保用户能一眼看懂这个服务器不可用。

调用图:调用 3 个内部函数(codex_command, new, load_global_mcp_servers);外部调用 4 个(from_utf8, new, assert!, assert_eq!)。

实时 CLI 冒烟覆盖

这些可选冒烟测试使用真实 CLI 二进制文件连接实时服务,以确认模拟集成套件之外的端到端行为。

core/tests/suite/live_cli.rs源码 ↗
testmanual ignored live test

这类测试像是给整台机器做一次简短试运行,而不是只检查某个小零件。文件先确认本机有 OPENAI_API_KEY,也就是访问 OpenAI 服务用的钥匙。然后它创建临时目录,让被测程序在干净环境里运行,避免改到开发者真实文件。run_live 会启动 codex-rs,把提示词传进去,同时把子进程的输出一边实时打印到屏幕,一边保存下来,方便后面断言检查。两个被忽略的测试分别让模型创建 hello.txt,和打印当前工作目录。重要的是:这些测试会访问真实服务,结果可能受网络、模型行为和账号配置影响,所以只适合开发者手动运行,用来确认“命令行程序 + 工具调用 + 真实接口”这条完整链路还通着。

函数细节4
require_api_key12–15 ↗
fn require_api_key() -> String

作用:这个函数专门读取 OPENAI_API_KEY 环境变量,也就是调用 OpenAI 真服务所需的钥匙。没有它,测试就不能安全地继续,因为真实请求无法认证。

数据流:进去的是当前进程的环境变量信息;它查找名为 OPENAI_API_KEY 的值;如果找到了,就把这串钥匙返回给后续启动的命令行程序,如果没找到,就直接报错,提醒开发者不要跑这个 live 测试。

调用关系:run_live 在准备启动 codex-rs 前会调用它,把拿到的 API Key 放进子进程环境里。它只做取钥匙这一件事,让启动测试程序的逻辑不用到处重复检查环境变量。

调用图:被 1 处调用(run_live);外部调用 1 个(var)。

run_live18–115 ↗
fn run_live(prompt: &str) -> (assert_cmd::assert::Assert, TempDir)

作用:这个函数是 live 测试的核心助手:它负责在临时目录里启动真正的 codex-rs 程序,把用户提示词交给它,并收集运行结果。测试用它来避免每个用例都重复写一大段启动子进程的代码。

数据流:进去的是一段提示词,比如“创建 hello.txt”。它先新建临时工作目录和临时 HOME 目录,再通过 require_api_key 取 API Key,并设置好 HOME、CODEX_HOME 等环境变量。接着它启动 codex-rs,把提示词作为命令行参数传入,并给标准输入写入一个换行,让程序完成第一轮后退出。运行时,它用两个后台线程把标准输出和标准错误同时打印到当前终端并保存到内存。最后它等待子进程结束,把退出状态和输出包装成 assert_cmd 可检查的结果,同时返回临时目录,方便测试查看程序到底改了哪些文件。

调用关系:live_create_file_hello_txt 和 live_print_working_directory 都把具体任务交给 run_live。run_live 自己会调用 require_api_key,并使用系统创建临时目录、启动进程、接管输入输出。它是测试用例和真实命令行程序之间的桥。

调用图:调用 1 个内部函数(require_api_key);被 2 处调用(live_create_file_hello_txt, live_print_working_directory);外部调用 7 个(piped, new, new, cargo_bin, create_dir_all, stderr, stdout)。

live_create_file_hello_txt119–137 ↗
fn live_create_file_hello_txt()

作用:这个测试验证真实模型能通过 codex-rs 调用 shell 工具,并创建一个指定内容的文件。它检查的是端到端能力:从提示词到工具执行,再到磁盘上真的出现文件。

数据流:开始时它先查看 OPENAI_API_KEY 是否存在;如果没有,就打印跳过信息并返回。若有钥匙,它把“创建 hello.txt,内容为 hello”的请求交给 run_live。run_live 返回后,它先确认命令执行成功,再到临时目录里寻找 hello.txt,读取文件内容,最后确认去掉首尾空白后的内容正好是 hello。

调用关系:这是一个被 #[ignore] 标记的手动测试,不会在普通测试中自动跑。它依赖 run_live 来启动真实 codex-rs,并在 run_live 完成后自己检查文件系统结果,判断模型和命令行工具链是否真的完成了任务。

调用图:调用 1 个内部函数(run_live);外部调用 5 个(assert!, assert_eq!, eprintln!, var, read_to_string)。

live_print_working_directory141–152 ↗
fn live_print_working_directory()

作用:这个测试验证真实模型能用 shell 功能打印当前工作目录,并且 codex-rs 的输出里确实包含那个目录。它主要检查命令行程序运行位置和工具输出是否能正确传回来。

数据流:开始时它检查 OPENAI_API_KEY;没有就打印跳过信息并结束。有钥匙时,它把“用 shell 打印当前工作目录”的提示词交给 run_live。运行结束后,它要求进程成功退出,并检查标准输出里包含 run_live 创建的临时工作目录路径。

调用关系:它和 live_create_file_hello_txt 一样,是手动运行的 live 测试。它把真实执行过程交给 run_live,自己只负责提出任务和检查输出文本是否符合预期。

调用图:调用 1 个内部函数(run_live);外部调用 3 个(eprintln!, contains, var)。