Codex 系统手册

Analytics 和 telemetry 测试

stage-23.6.118 个文件

这一阶段不是系统真正干活的主流程,而是幕后“质检台”,专门检查分析埋点和遥测数据靠不靠谱。入口和目录文件负责把测试接进来;harness 像假监控台,方便造指标、取结果、核对内容。各类 otel 测试检查名字标签是否合法、耗时和计数是否写对、快照和导出是否正常、敏感内容有没有走错通道。analytics、server、core、state 的测试则盯住事件收集、开关行为、任务指标、日志过滤,防止数据丢、错、脏。

本阶段的文件18

OTEL 测试脚手架

这些文件定义 OpenTelemetry 集成测试 crate,组织其套件模块,并提供各个测试使用的共享内存内框架。

otel/tests/tests.rs源码 ↗
testtest startup

这个文件像一本测试手册的目录页。Rust 的测试工具运行集成测试时,会从这里开始看有哪些测试模块要参与。它声明了 harnesssuite 两个模块:harness 通常放测试运行需要的脚手架,比如准备环境、启动假服务、收集结果;suite 通常放真正的一组测试场景。开头的 #![allow(clippy::expect_used)] 是告诉代码检查工具 Clippy:在这个测试文件里,允许使用 expectexpect 是一种“如果失败就直接报错并说明原因”的写法,在生产代码里可能太粗暴,但在测试里很常见,因为测试失败时我们反而希望它立刻停下并给出清楚信息。没有这个文件,这些测试模块可能不会被集成测试入口正确纳入。

otel/tests/suite/mod.rs源码 ↗
testtest discovery / test compile

这个文件本身不写具体测试,也不处理业务数据。它的作用是把同一套 OpenTelemetry 相关测试分门别类地接进来。OpenTelemetry 可以简单理解成一套“给程序做监控记录”的标准,比如记录指标、发送链路数据、导出运行状态等。这里的每一行 mod xxx; 都是在声明一个测试模块,好比在一本手册的总目录里写上章节名。测试运行时,Rust 会顺着这些声明去找到对应的测试文件,把里面的测试用例编译进去。这样做的好处是结构清楚:发送测试、快照测试、时间测试、校验测试等各放各的文件,而这个文件只负责把它们集合成一个测试套件。

otel/tests/harness/mod.rs源码 ↗
testtest execution

指标系统平时可能会把数据发到外部服务,但测试不能真的依赖外部服务,否则又慢又不稳定。这个文件用 OpenTelemetry 的内存导出器(把指标暂存在内存里的假出口)来替代真实上报通道。测试先用 build_metrics_with_defaults 建一个带默认标签的 MetricsClient,代码运行后再用 latest_metrics 拿到刚导出的指标。find_metric 像在一堆报表里按名字找某张表,attributes_to_map 把 OpenTelemetry 的标签列表变成普通键值表,方便断言。histogram_data 专门拆直方图(把数值按区间分桶统计的指标),并且会强硬检查:必须找到指标、必须是浮点直方图、必须只有一个数据点。这样测试写起来更短,也能把错误更早暴露出来。

函数细节5
build_metrics_with_defaults12–27 ↗
fn build_metrics_with_defaults(
    default_tags: &[(&str, &str)],
) -> Result<(MetricsClient, InMemoryMetricExporter)>

作用:为测试创建一套可以直接用的指标客户端,并把指标出口换成内存里的假出口。测试用它就不用真的连外部监控系统,也能检查指标有没有被正确记录。

数据流:输入是一组默认标签,比如环境名或服务名 → 它先创建一个 InMemoryMetricExporter,也就是把指标存在内存里的导出器;再用 MetricsConfig::in_memory 配好测试用配置,带上包版本;然后把传入的默认标签逐个加进去;最后用 MetricsClient::new 造出指标客户端 → 输出是一个二元组:可记录指标的 MetricsClient,以及稍后可读取结果的内存导出器。

调用关系:很多指标测试一开始都会调用它搭测试环境,比如检查元数据标签、插件安装指标、发送队列指标、直方图 payload 等场景。它内部把配置创建交给 MetricsConfig::in_memory,把客户端创建交给 MetricsClient::new;后续测试通常会用 latest_metrics 从它返回的导出器里取结果。

调用图:调用 2 个内部函数(new, in_memory);被 13 处调用(manager_allows_disabling_metadata_tags, manager_attaches_metadata_tags_to_metrics, manager_attaches_optional_service_name_tag, manager_records_plugin_install_elicitation_sent_metric, manager_records_plugin_install_suggestion_metric, client_sends_enqueued_metric, send_builds_payload_with_tags_and_histograms, send_merges_default_tags_per_line, shutdown_flushes_in_memory_exporter, shutdown_without_metrics_exports_nothing (+3 more));外部调用 2 个(default, env!)。

latest_metrics29–36 ↗
fn latest_metrics(exporter: &InMemoryMetricExporter) -> ResourceMetrics

作用:从内存导出器里取出最近一次导出的指标。测试记录完指标后,用它拿到“刚才到底导出了什么”。

数据流:输入是 InMemoryMetricExporter,也就是之前收集指标的内存出口 → 它调用 get_finished_metrics 取出已经完成导出的指标批次,并选择最后一批 → 输出一个 ResourceMetrics,里面包含这次导出的所有指标;如果没有任何可用指标,它会直接让测试失败。

调用关系:它通常接在 build_metrics_with_defaults 之后使用:先搭客户端并记录指标,再取最新结果检查。许多测试会拿到它的返回值后继续交给 find_metric、attributes_to_map 或 histogram_data 做更细的检查。

调用图:被 12 处调用(manager_allows_disabling_metadata_tags, manager_attaches_metadata_tags_to_metrics, manager_attaches_optional_service_name_tag, manager_records_plugin_install_elicitation_sent_metric, manager_records_plugin_install_suggestion_metric, client_sends_enqueued_metric, send_builds_payload_with_tags_and_histograms, send_merges_default_tags_per_line, shutdown_flushes_in_memory_exporter, record_duration_records_histogram (+2 more));外部调用 1 个(get_finished_metrics)。

find_metric38–50 ↗
fn find_metric(
    resource_metrics: &'a ResourceMetrics,
    name: &str,
) -> Option<&'a Metric>

作用:在一批导出的指标里按名字找某个指标。它让测试不用关心 OpenTelemetry 指标内部分了多少层结构。

数据流:输入是一份 ResourceMetrics 和要找的指标名 → 它逐层查看其中的 scope metrics,再查看每个 metric 的名字 → 如果名字匹配,就返回这个指标的引用;如果找不到,就返回空值 None,不改动原始数据。

调用关系:测试经常直接用它确认某个指标是否存在,histogram_data 也会先调用它找到目标直方图。它的位置像一个检索员:latest_metrics 给它整批报表,它从里面挑出指定名字的那一项。

调用图:被 15 处调用(histogram_data, manager_allows_disabling_metadata_tags, manager_attaches_metadata_tags_to_metrics, manager_attaches_optional_service_name_tag, manager_records_plugin_install_elicitation_sent_metric, manager_records_plugin_install_suggestion_metric, client_sends_enqueued_metric, send_builds_payload_with_tags_and_histograms, send_merges_default_tags_per_line, shutdown_flushes_in_memory_exporter (+5 more));外部调用 1 个(scope_metrics)。

attributes_to_map52–58 ↗
fn attributes_to_map(
    attributes: impl Iterator<Item = &'a KeyValue>,
) -> BTreeMap<String, String>

作用:把指标上的标签转换成普通的键值表,方便测试比较。标签本来是 OpenTelemetry 的 KeyValue 形式,直接断言不够顺手。

数据流:输入是一串 KeyValue 标签迭代器,也就是一项项“键和值” → 它把每个键和值都转成字符串,再收集进 BTreeMap;BTreeMap 是按键排序的映射表,结果更稳定 → 输出一个 String 到 String 的键值表,不修改原标签。

调用关系:很多测试在用 find_metric 找到指标后,会拿指标的属性交给它转换,然后检查默认标签、元数据标签或服务名标签是否正确。它不负责找指标,只负责把找到后的标签变成更容易读、更容易比对的形状。

调用图:被 11 处调用(manager_allows_disabling_metadata_tags, manager_attaches_metadata_tags_to_metrics, manager_attaches_optional_service_name_tag, manager_records_plugin_install_elicitation_sent_metric, manager_records_plugin_install_suggestion_metric, client_sends_enqueued_metric, send_builds_payload_with_tags_and_histograms, send_merges_default_tags_per_line, manager_snapshot_metrics_collects_without_shutdown, snapshot_collects_metrics_without_shutdown (+1 more));外部调用 1 个(map)。

histogram_data60–79 ↗
fn histogram_data(
    resource_metrics: &ResourceMetrics,
    name: &str,
) -> (Vec<f64>, Vec<u64>, f64, u64)

作用:从指定名字的直方图指标里取出分桶边界、每个桶的数量、总和和总次数。测试用它验证耗时、区间统计这类指标是否记录正确。

数据流:输入是一批 ResourceMetrics 和直方图指标名 → 它先用 find_metric 找到该指标;再检查这个指标必须是 f64 浮点类型的 Histogram,也就是按区间统计小数数值;然后取出唯一的数据点,读出桶边界、桶计数、总和、总次数 → 输出这四类数据;如果指标不存在、类型不对或数据点数量不符合预期,它会让测试直接失败。

调用关系:它服务于专门检查直方图的测试,比如发送 payload 是否包含直方图、记录 duration 是否正确、计时器是否记录成功结果。它把底层 OpenTelemetry 的复杂结构拆开,让测试只关心“这些桶和数值对不对”。

调用图:调用 1 个内部函数(find_metric);被 4 处调用(send_builds_payload_with_tags_and_histograms, record_duration_records_histogram, record_duration_seconds_uses_fractional_seconds_and_scaled_buckets, timer_result_records_success);外部调用 2 个(assert_eq!, panic!)。

指标客户端行为

这些测试贯穿指标客户端和会话遥测 API,从验证、记录到发送、快照、摘要以及管理器专用计数器。

otel/tests/suite/validation.rs源码 ↗
testtest run

这个文件像是在指标入口前放了一排安检机。指标就是程序运行时上报的数字,比如请求耗时、次数统计;标签就是给这些数字贴的小纸条,比如 route=login,方便分类查看。测试里先用内存版导出器,也就是只把指标存在测试内存里、不发到真实外部系统,造出一个 MetricsClient。然后分别尝试传入带空格的标签名、带空格的标签值、带空格的指标名,以及负数的计数器增量。每个测试都期待系统立刻报出明确错误,而不是悄悄接受。这样可以保证真正运行时,上报到 OpenTelemetry 这类监控管道里的数据格式干净、稳定。

函数细节6
build_in_memory_client7–11 ↗
fn build_in_memory_client() -> Result<MetricsClient>

作用:这个小帮手用来快速创建一个只在内存里工作的指标客户端,给后面的测试共用。这样测试不用真的连接外部监控服务,速度快,也不会污染真实数据。

数据流:进去的是固定的测试服务名、程序名、当前包版本,以及一个默认的内存指标导出器 → 它先用 MetricsConfig::in_memory 拼出测试配置,再交给 MetricsClient::new 创建客户端 → 出来的是一个可用于测试的 MetricsClient,或者创建失败时返回错误。

调用关系:它是几个测试的共同准备步骤。counter_rejects_invalid_tag_key、histogram_rejects_invalid_tag_value、counter_rejects_invalid_metric_name 和 counter_rejects_negative_increment 都先叫它搭好临时指标客户端,然后再往客户端里塞故意写错的数据。

调用图:调用 2 个内部函数(new, in_memory);被 4 处调用(counter_rejects_invalid_metric_name, counter_rejects_invalid_tag_key, counter_rejects_negative_increment, histogram_rejects_invalid_tag_value);外部调用 2 个(default, env!)。

invalid_tag_component_is_rejected15–30 ↗
fn invalid_tag_component_is_rejected() -> Result<()>

作用:这个测试确认:在创建指标配置时,如果全局标签的名字不合法,系统会马上拒绝。这里的例子是标签名 bad key,中间有空格,不该被接受。

数据流:进去的是一份内存指标配置和一个故意写错的标签 bad key=value → 它调用 with_tag 试图把这个标签放进配置里,并要求这一步必须失败 → 出来的是一个错误对象,测试再检查错误确实说明 tag key 这个标签名不合法。

调用关系:这个测试直接检查配置构建阶段,不经过 build_in_memory_client。它调用 MetricsConfig::in_memory 准备配置,再用断言确认错误类型和值都对,保证问题能在最早的配置阶段被抓住。

调用图:调用 1 个内部函数(in_memory);外部调用 3 个(default, assert!, env!)。

counter_rejects_invalid_tag_key34–46 ↗
fn counter_rejects_invalid_tag_key() -> Result<()>

作用:这个测试确认:即使客户端已经建好了,单次上报计数器时传入坏标签名,也会被拒绝。计数器就是只增不减的次数统计,比如回合数加一。

数据流:进去的是一个内存指标客户端、指标名 codex.turns、增量 1,以及故意写错的标签名 bad key → 它尝试上报这个计数器 → 出来的是一个错误,测试检查错误明确指向 tag key,并保留了原始坏值 bad key;最后关闭测试客户端。

调用关系:它先调用 build_in_memory_client 取得临时客户端,再对客户端做一次错误上报,最后用断言把结果钉死。它覆盖的是运行时每条指标自己的标签检查,而不是配置阶段检查。

调用图:调用 1 个内部函数(build_in_memory_client);外部调用 1 个(assert!)。

histogram_rejects_invalid_tag_value50–66 ↗
fn histogram_rejects_invalid_tag_value() -> Result<()>

作用:这个测试确认:直方图指标上报时,标签值也必须合法。直方图可以理解成记录一批数值分布的工具,比如请求耗时落在哪些范围里。

数据流:进去的是一个内存指标客户端、指标名 codex.request_latency、数值 3,以及标签 route=bad value,其中标签值带空格 → 它尝试记录这条直方图数据 → 出来的是一个错误,测试确认错误说的是 tag value 不合法,坏值正是 bad value;之后关闭客户端。

调用关系:它通过 build_in_memory_client 复用同一套测试客户端搭建方式,然后专门走 histogram 这条上报路径。它和计数器标签测试互补,说明不同类型的指标都会执行同样的标签校验。

调用图:调用 1 个内部函数(build_in_memory_client);外部调用 1 个(assert!)。

counter_rejects_invalid_metric_name70–79 ↗
fn counter_rejects_invalid_metric_name() -> Result<()>

作用:这个测试确认:指标名本身不合法时,计数器不会接受。这里的 bad name 中间有空格,说明它不是系统允许的指标命名格式。

数据流:进去的是一个内存指标客户端、坏指标名 bad name、增量 1,以及空标签列表 → 它尝试上报计数器 → 出来的是 InvalidMetricName 这类错误,测试检查错误里记录的名字就是 bad name;最后关闭客户端。

调用关系:它由 build_in_memory_client 先准备测试环境,然后把关注点放在指标名校验上。和标签相关测试不同,它证明即便没有任何标签,指标自己的名字也必须先过关。

调用图:调用 1 个内部函数(build_in_memory_client);外部调用 1 个(assert!)。

counter_rejects_negative_increment82–91 ↗
fn counter_rejects_negative_increment() -> Result<()>

作用:这个测试确认:计数器不能用负数增加。因为计数器代表累计次数,像门口计数器一样只能往上走,传 -1 会让含义变乱。

数据流:进去的是一个内存指标客户端、合法指标名 codex.turns、负数增量 -1,以及空标签列表 → 它尝试把计数器增加 -1 → 出来的是 NegativeCounterIncrement 错误,测试确认错误里同时带着指标名和这个负数;最后关闭客户端。

调用关系:它同样先调用 build_in_memory_client 建好隔离的测试客户端,再验证计数器自己的数值规则。它补上了另一类防线:不只是名字和标签要合法,数字的业务含义也要合法。

调用图:调用 1 个内部函数(build_in_memory_client);外部调用 1 个(assert!)。

otel/tests/suite/timing.rs源码 ↗
testtest run

这是一组自动测试,用来防止“请求耗时”这类指标悄悄坏掉。OpenTelemetry 可以理解成一套把程序运行状态送去监控平台的标准;这里重点检查耗时是不是按预期变成直方图,也就是把很多耗时值分进不同区间,方便看快慢分布。文件先用测试工具搭一套默认指标系统和导出器,像临时搭了一个小监控站;然后记录几段时间,关闭指标系统,取出刚导出的数据,再检查数量、总和、单位、说明文字和标签是否正确。特别重要的是,它分别覆盖了毫秒单位、秒单位的小数换算、秒级分桶边界,以及自动计时器在结束时是否真的记录了一次耗时。没有这些测试,监控面板可能看起来还在运行,但单位错了、桶错了、标签丢了,排查线上性能问题时就会被误导。

函数细节3
record_duration_records_histogram11–34 ↗
fn record_duration_records_histogram() -> Result<()>

作用:这个测试确认:手动记录一个 15 毫秒的耗时后,系统会把它作为一个直方图指标导出。它还检查这个指标的单位是毫秒,说明文字也符合默认约定。

数据流:进去的是一个临时创建的指标系统和一条耗时记录:指标名是 codex.request_latency,耗时是 15 毫秒,标签是 route=chat。测试把这条耗时写进去,然后关闭指标系统,读取导出的最新指标数据。出来的结果应该是:直方图里有一个样本,总和是 15.0,计数是 1,指标单位是 ms,描述是 “Duration in milliseconds.”;如果任何一项不对,测试就失败。

调用关系:它在测试运行时由 Rust 测试框架自动调用。它先借助 build_metrics_with_defaults 搭好测试用指标环境,再用 latest_metrics 取出导出的数据,用 histogram_data 拆出直方图内容,最后用 find_metric 找到具体指标并检查单位和描述。它是在验证最基础的“毫秒耗时记录”链路。

调用图:调用 4 个内部函数(build_metrics_with_defaults, find_metric, histogram_data, latest_metrics);外部调用 3 个(from_millis, assert!, assert_eq!)。

record_duration_seconds_uses_fractional_seconds_and_scaled_buckets37–78 ↗
fn record_duration_seconds_uses_fractional_seconds_and_scaled_buckets() -> Result<()>

作用:这个测试确认:用“秒”来记录耗时时,毫秒会被正确换算成小数秒,而且直方图的分桶边界也会按秒来设置。它防止把 200 毫秒误当成 200 秒这类严重单位错误。

数据流:进去的是三段耗时:200 毫秒、1 秒、4900 毫秒,以及同一个指标名 codex.request_duration_seconds 和标签 method=initialize。测试把它们按“秒”记录进去,关闭指标系统后读取导出的直方图。出来应该看到固定的秒级分桶边界,例如 0.005、0.01、0.25、1.0、5.0 等;三条数据分别落到对应桶里,总和约为 6.1 秒,计数是 3,单位是 s,描述文字是传入的那句 “Duration of Codex requests in seconds.”。

调用关系:它由测试框架自动运行,用来覆盖 record_duration_seconds_with_description 这条更精细的记录路径。它同样依赖 build_metrics_with_defaults 创建环境,latest_metrics 读取结果,histogram_data 查看桶边界和桶计数,find_metric 检查指标元信息。它和前一个测试互补:前一个看毫秒默认行为,这一个看秒单位和自定义描述。

调用图:调用 4 个内部函数(build_metrics_with_defaults, find_metric, histogram_data, latest_metrics);外部调用 4 个(from_millis, from_secs, assert!, assert_eq!)。

timer_result_records_success82–118 ↗
fn timer_result_records_success() -> Result<()>

作用:这个测试确认:调用 start_timer 创建的计时器在结束时会自动记录一次耗时。它还检查记录下来的标签没有丢,比如 route=chat 仍然跟着这条指标。

数据流:进去的是一个临时指标系统,以及一次 start_timer 调用,指标名是 codex.request_latency,标签是 route=chat。测试把计时器放进一个小作用域里,离开作用域时计时器被释放,应该自动写入一条耗时。之后关闭指标系统并读取导出的数据。出来应该看到直方图计数是 1、桶里总共有一个样本、单位是 ms、描述是默认毫秒说明,并且指标的数据点属性里还能找到 route=chat。

调用关系:它由测试框架自动调用,主要验证“自动计时”这条使用方式。它先用 build_metrics_with_defaults 建环境,再启动计时器;计时器结束后,通过 latest_metrics 和 histogram_data 检查是否真的写入直方图。为了确认标签,它还用 find_metric 找到指标数据,再用 attributes_to_map 把 OpenTelemetry 的属性转成普通键值表,方便断言 route 标签是否存在。

调用图:调用 5 个内部函数(attributes_to_map, build_metrics_with_defaults, find_metric, histogram_data, latest_metrics);外部调用 2 个(assert!, assert_eq!)。

otel/tests/suite/send.rs源码 ↗
testtest run

这份测试专门检查 OpenTelemetry 指标发送流程。OpenTelemetry 可以简单理解成一套“把程序运行情况报给监控系统”的通用规范。文件里用内存里的假导出器代替真正的网络服务,像在厨房试菜一样,不真的上桌,但能看清做出来的菜。测试会先搭一个带默认标签的 metrics 客户端,再记录计数器、直方图和仪表盘数值。计数器像“累计发生了几次”,直方图像“把耗时分桶统计”,仪表盘数值像“当前有几个正在运行”。然后调用 shutdown,把后台攒着的数据刷出来,最后从导出器里取回指标,逐项核对名字、描述、数值和标签。这里特别重要的是标签合并规则:默认标签会自动带上,但单次记录传入的同名标签可以覆盖默认值。

函数细节5
send_builds_payload_with_tags_and_histograms12–108 ↗
fn send_builds_payload_with_tags_and_histograms() -> Result<()>

作用:这个测试确认一次发送里能同时正确生成计数器、直方图和仪表盘数值,并且每条指标都带上正确标签。它还检查“默认标签”和“本次调用传入的标签”合并时,谁该保留、谁该覆盖。

数据流:进去的是一组默认标签,比如 service=codex-cli、env=prod,以及三次指标记录:一次计数、一次耗时直方图、一次当前值。测试把这些交给 metrics 客户端记录,再调用 shutdown 让后台数据真正导出。出来的是内存导出器里保存的指标数据;测试读取它们,核对计数值是 1、直方图总和是 25 且只有一条记录、仪表盘值是 2,并确认标签集合符合预期,例如计数器里的 env 被本次调用的 dev 覆盖。

调用关系:它先通过 build_metrics_with_defaults 搭好测试用指标客户端和内存导出器;记录完数据后用 latest_metrics 取回最近导出的结果;再用 find_metric 找到指定名字的指标,用 attributes_to_map 把标签转成方便比较的表,用 histogram_data 抽出直方图的关键数字。它是整套发送行为的综合验收测试。

调用图:调用 5 个内部函数(attributes_to_map, build_metrics_with_defaults, find_metric, histogram_data, latest_metrics);外部调用 4 个(from, assert!, assert_eq!, panic!)。

send_merges_default_tags_per_line112–179 ↗
fn send_merges_default_tags_per_line() -> Result<()>

作用:这个测试专门盯住标签合并规则:每一条指标都要重新把默认标签和本次标签合在一起,不能把上一条的标签串到下一条。它还确认本次传入的同名标签优先级更高。

数据流:进去的是三个默认标签:service、env、region,以及两条不同的计数指标。第一条把 env 改成 dev,第二条把 service 改成 worker。测试记录后关闭并取回导出的数据;出来的是 alpha 和 beta 两个计数点,各自有自己的数值和标签。测试确认 alpha 的 env 是 dev、service 仍是 codex-cli;beta 的 service 是 worker、env 仍是 prod,说明每条数据都独立合并,没有互相污染。

调用关系:它使用 build_metrics_with_defaults 创建带默认标签的客户端,靠 latest_metrics 拿到导出结果,再用 find_metric 找 alpha 和 beta 两条指标,最后用 attributes_to_map 比较标签。它比综合测试更聚焦,只验证“每次记录一行指标时标签如何合并”这个细节。

调用图:调用 4 个内部函数(attributes_to_map, build_metrics_with_defaults, find_metric, latest_metrics);外部调用 3 个(from, assert_eq!, panic!)。

client_sends_enqueued_metric183–207 ↗
fn client_sends_enqueued_metric() -> Result<()>

作用:这个测试确认指标不是只被放进队列就算完,而是真的会被后台工作线程送到导出器里。换句话说,它检查“记了一笔账”最后确实能在账本里看到。

数据流:进去的是一个没有默认标签的 metrics 客户端和一条计数记录:codex.turns 加 1,带 model=gpt-5.1 标签。记录动作先把指标交给客户端内部流程,shutdown 再触发收尾和刷新。出来的是导出器里的一条计数数据;测试确认只有一个数据点、值是 1,并且标签里能找到 model=gpt-5.1。

调用关系:它通过 build_metrics_with_defaults 启动测试环境,通过 latest_metrics 读取后台导出的结果,用 find_metric 定位 codex.turns,再用 attributes_to_map 检查标签。它主要覆盖客户端到后台发送流程这一段,证明排队后的指标没有丢。

调用图:调用 4 个内部函数(attributes_to_map, build_metrics_with_defaults, find_metric, latest_metrics);外部调用 2 个(assert_eq!, panic!)。

shutdown_flushes_in_memory_exporter211–231 ↗
fn shutdown_flushes_in_memory_exporter() -> Result<()>

作用:这个测试确认调用 shutdown 时,会把还没导出的内存指标刷出去。它防止程序退出前最后一批监控数据悄悄丢失。

数据流:进去的是一个空默认标签的 metrics 客户端,以及一条 codex.turns 加 1 的计数记录。测试记录后立刻调用 shutdown,要求客户端把积压的数据交给内存导出器。出来的是导出器里可读取的指标;测试找到 codex.turns,并确认里面确实有一个数据点。

调用关系:它用 build_metrics_with_defaults 搭环境,用 latest_metrics 取导出的数据,再用 find_metric 找目标指标。和 client_sends_enqueued_metric 相比,它更强调 shutdown 这个收尾动作必须承担“刷新剩余数据”的责任。

调用图:调用 3 个内部函数(build_metrics_with_defaults, find_metric, latest_metrics);外部调用 2 个(assert_eq!, panic!)。

shutdown_without_metrics_exports_nothing235–243 ↗
fn shutdown_without_metrics_exports_nothing() -> Result<()>

作用:这个测试确认如果什么指标都没记录,直接关闭时不应该导出空的或假的数据。它保护监控结果不被无意义的空记录污染。

数据流:进去的是一个新建但没有记录任何指标的 metrics 客户端和内存导出器。测试只调用 shutdown,不做计数、直方图或仪表盘记录。出来的是导出器的已完成指标列表;测试确认这个列表是空的,说明系统没有凭空制造指标。

调用关系:它只需要 build_metrics_with_defaults 创建测试对象,然后直接检查导出器结果。它是关闭流程的边界情况测试,和 shutdown_flushes_in_memory_exporter 形成对照:有数据时要刷出,没有数据时就什么都别导出。

调用图:调用 1 个内部函数(build_metrics_with_defaults);外部调用 1 个(assert!)。

otel/tests/suite/snapshot.rs源码 ↗
testtest run

这个测试文件关注的是 OpenTelemetry 指标,也就是程序运行时记录的数字信号,比如“某个工具被调用了几次”。平时这些指标可能会被后台定时送出去,但测试里不想等,也不想真的关闭整个指标系统。这里用内存导出器(一块临时内存,用来假装接收指标)创建一个 MetricsClient,然后记录一次计数,再调用 snapshot 直接抓取当前指标。测试会确认两件事:第一,快照里确实有刚刚记录的指标和标签;第二,普通的后台导出还没发生,说明 snapshot 只是“拍照查看”,不是“结账关门”。第二个测试还检查 SessionTelemetry 这层会不会自动把会话信息,比如模型、认证方式、来源等,附加到指标标签里。

函数细节2
snapshot_collects_metrics_without_shutdown17–63 ↗
fn snapshot_collects_metrics_without_shutdown() -> Result<()>

作用:这个测试确认 MetricsClient 可以在不关闭指标系统的情况下,马上抓到已经记录的指标快照。它还确认这个抓取动作不会误触发常规的后台导出。

数据流:进入时没有外部输入;测试自己创建一个内存指标导出器和一份测试配置,并加上固定标签 service=codex-cli。然后它创建 MetricsClient,记录一次名为 codex.tool.call 的计数,标签是 tool=shell 和 success=true。接着它调用 snapshot 拿到当前指标,找到这条指标,把指标点上的标签转成普通 map,和期望值比较。最后它读取内存导出器里“已经完成导出”的指标,确认还是空的。结果是:测试通过返回 Ok,或者在指标缺失、类型不对、标签不一致、发生了意外导出时失败。

调用关系:这个函数是测试入口之一,由 Rust 测试框架在跑测试时调用。它先通过 MetricsConfig::in_memory 准备一个只在内存里工作的指标环境,再用 MetricsClient::new 启动客户端;记录指标后,它把查找指标的细活交给 find_metric,把标签整理交给 attributes_to_map,并用 assert_eq 和 assert 来判断结果是否符合预期。

调用图:调用 4 个内部函数(new, in_memory, attributes_to_map, find_metric);外部调用 6 个(from, default, assert!, assert_eq!, env!, panic!)。

manager_snapshot_metrics_collects_without_shutdown66–125 ↗
fn manager_snapshot_metrics_collects_without_shutdown() -> Result<()>

作用:这个测试确认更高一层的 SessionTelemetry 也能在不中断指标系统的情况下抓取指标快照。它重点检查会话级信息会不会自动变成指标标签一起出现。

数据流:进入时没有外部输入;测试先创建内存指标配置和 MetricsClient,再创建一个带有线程编号、模型名、账号信息、认证方式、来源等信息的 SessionTelemetry,并把 MetricsClient 接进去。之后它通过 manager 记录一次 codex.tool.call 计数。调用 snapshot_metrics 后,它从快照里找到这条指标,取出唯一的数据点,把标签转成 map。最后它把这些标签和期望集合比较,期望里除了 tool、success、service,还有 app.version、auth_mode、model、originator、session_source 等会话信息。结果是:标签完整就通过,否则测试失败。

调用关系:这个函数也是由测试框架直接运行的测试入口。它比前一个测试多走了一层 SessionTelemetry:先用 MetricsClient::new 建好底层指标客户端,再用 SessionTelemetry::new 建好会话遥测对象,并通过 with_metrics 把两者连起来。真正查验时,它仍然把定位指标交给 find_metric,把属性转换交给 attributes_to_map,最后用 assert_eq 判断 SessionTelemetry 是否正确补齐了会话标签。

调用图:调用 6 个内部函数(new, new, in_memory, attributes_to_map, find_metric, new);外部调用 5 个(from, default, assert_eq!, env!, panic!)。

otel/tests/suite/runtime_summary.rs源码 ↗
testtest

这个测试像是在给遥测系统做一次“模拟体检”。它先创建一个只存在内存里的指标收集器,也就是不把数据发到外部服务,只在测试里临时记录。然后它创建一个会话遥测对象,模拟一次真实使用过程:调用了一次工具、发了一次普通 API 请求、建立了一次 WebSocket 请求、收到了一次服务器推送事件,还收到两次 WebSocket 消息。其中一条 WebSocket 消息里带了更细的后端耗时数据。最后它还手动记录了首字时间和首消息时间。测试最后取出运行摘要,和一份手写的“正确答案”逐项对比。这样可以保证:次数没有多算少算,毫秒耗时没有放错地方,WebSocket 里的特殊 timing_metrics 也能被正确拆出来。

函数细节1
runtime_metrics_summary_collects_tool_api_and_streaming_metrics17–142 ↗
fn runtime_metrics_summary_collects_tool_api_and_streaming_metrics() -> Result<()>

作用:这个测试函数检查运行指标摘要是否能正确汇总不同来源的数据,包括工具调用、普通 API、SSE 流式事件、WebSocket 请求和 WebSocket 消息。有人改遥测代码时,它能及时发现统计口径被改坏了。

数据流:进去的是一套测试里临时搭好的遥测环境:内存指标导出器、测试用指标客户端、测试会话信息,以及一批人工构造的耗时和事件。函数先清空旧的运行指标,再逐个模拟事件发生:工具花了 250 毫秒,API 花了 300 毫秒,WebSocket 请求花了 400 毫秒,流式事件花了 120 毫秒,两个 WebSocket 事件一共花了 100 毫秒,并额外记录后端 timing_metrics 和回合耗时。出来的是一个 RuntimeMetricsSummary 摘要对象;函数把它和预期摘要比较。如果完全一致,测试通过;如果有任何字段不对,测试失败。

调用关系:它是测试框架运行时直接执行的测试入口。它会调用 MetricsConfig::in_memory 搭建只用于测试的内存指标配置,用 MetricsClient::new 创建指标客户端,用 SessionTelemetry::new 创建会话遥测对象,然后通过会话遥测对象的一系列记录方法把模拟数据送进去。最后它调用 runtime_metrics_summary 取回汇总结果,并用 assert_eq! 把实际结果和预期结果做严格比较。

调用图:调用 4 个内部函数(new, new, in_memory, new);外部调用 6 个(from_millis, default, new, assert_eq!, env!, Text)。

otel/tests/suite/manager_metrics.rs源码 ↗
testtest

这个文件专门测试“指标”这件事。指标可以理解成系统里的计数器,比如“会话开始了几次”“插件安装建议出现了几次”。这些计数如果没有标签,就像账本只写金额不写用途,很难分析;但标签太多或错了,也会造成误解。这里用测试用的指标收集器先搭一个假环境,再创建 SessionTelemetry,也就是会话遥测记录器。每个测试都会让它记录一次指标,然后关闭并导出指标,最后检查导出的标签是否正好符合预期。它重点覆盖几件事:默认会自动附加模型、来源、认证方式、版本等元信息;也可以关闭这些元信息;可以额外加 service_name;插件安装建议和插件安装询问这两类专用指标只暴露必要标签,不把插件名字、账号等敏感或高粒度信息带出去。

函数细节5
manager_attaches_metadata_tags_to_metrics19–75 ↗
fn manager_attaches_metadata_tags_to_metrics() -> Result<()>

作用:这个测试确认 SessionTelemetry 记录普通计数指标时,会自动把会话的背景信息一起贴到指标上。这样后续看监控报表时,才能按模型、来源、认证方式等维度分组分析。

数据流:进去的是一套测试用指标收集器、一个带有模型名、账号、认证方式、来源等信息的 SessionTelemetry,以及一次名为 codex.session_started 的计数记录。测试让记录器写入这个计数,再关闭指标系统把数据刷出来,然后从导出的指标里取出标签,和预期标签表逐项比较。出来的结果不是业务返回值,而是测试通过或失败;如果缺了 app.version、auth_mode、model、originator、service、session_source 或调用时传入的 source,测试就会失败。

调用关系:它先借助 build_metrics_with_defaults 搭好测试指标环境,再通过 SessionTelemetry::new 创建记录器,调用记录器的 counter 写入指标。之后用 latest_metrics 取最新导出的指标,用 find_metric 找到目标指标,用 attributes_to_map 把底层标签转成容易比较的表,最后用 assert_eq! 判断是否完全一致。

调用图:调用 6 个内部函数(new, attributes_to_map, build_metrics_with_defaults, find_metric, latest_metrics, new);外部调用 4 个(from, assert_eq!, env!, panic!)。

manager_allows_disabling_metadata_tags79–121 ↗
fn manager_allows_disabling_metadata_tags() -> Result<()>

作用:这个测试确认自动标签是可以关掉的。它保证某些场景只想记录调用者手动传入的标签时,不会偷偷混入模型、版本、来源等会话信息。

数据流:进去的是空默认标签的测试指标环境,以及一个通过 with_metrics_without_metadata_tags 绑定指标系统的 SessionTelemetry。测试记录一次 codex.session_started,并手动带上 source=tui。然后它导出指标、读取标签,并确认最终只有 source 这一项。出来的效果是验证“关闭元信息标签”真的生效;如果仍然出现 model、auth_mode 之类自动标签,测试会失败。

调用关系:它和前一个测试形成对照:同样创建 SessionTelemetry,同样调用 counter,同样通过 latest_metrics、find_metric、attributes_to_map 检查导出的数据。但它使用的是 with_metrics_without_metadata_tags,所以检查重点从“自动标签是否齐全”变成“自动标签是否完全没有”。

调用图:调用 6 个内部函数(new, attributes_to_map, build_metrics_with_defaults, find_metric, latest_metrics, new);外部调用 3 个(from, assert_eq!, panic!)。

manager_attaches_optional_service_name_tag124–165 ↗
fn manager_attaches_optional_service_name_tag() -> Result<()>

作用:这个测试确认可以给指标额外加一个 service_name 标签。它适合一个程序里有不同客户端或服务端组件时,用来区分指标到底来自哪一块。

数据流:进去的是测试指标收集器、一个没有账号和认证方式的 SessionTelemetry,以及调用 with_metrics_service_name 设置的 my_app_server_client。测试记录一次 codex.session_started,不额外传标签。之后它导出指标、找到这条计数、取出标签,并检查 service_name 的值是否就是 my_app_server_client。出来的结果是证明这个可选标签会被写进指标里。

调用关系:它先创建 SessionTelemetry,再用 with_metrics_service_name 给记录器加上可选服务名,随后用 with_metrics 接入测试指标系统。记录指标后,仍然走 latest_metrics、find_metric、attributes_to_map 这条测试检查链路,只是这里不比较整张标签表,而是专门看 service_name 这一项。

调用图:调用 6 个内部函数(new, attributes_to_map, build_metrics_with_defaults, find_metric, latest_metrics, new);外部调用 2 个(assert_eq!, panic!)。

manager_records_plugin_install_suggestion_metric168–219 ↗
fn manager_records_plugin_install_suggestion_metric() -> Result<()>

作用:这个测试确认“向用户建议安装插件”这类事件会被记成正确的指标,并且只带必要标签。这样产品可以统计用户是否接受、流程是否完成,同时避免把插件具体名称等不该细分的信息塞进指标。

数据流:进去的是测试指标环境、关闭自动元信息标签的 SessionTelemetry,以及一次插件安装建议事件:工具类型是 connector,插件标识和展示名也传入,用户动作是 accept,用户确认了,但流程未完成。测试调用 record_plugin_install_suggestion 记录事件,再导出指标,找到 PLUGIN_INSTALL_SUGGESTION_METRIC 这条指标,读取它的标签。出来的预期标签只有 completed=false、response_action=accept、tool_type=connector;插件标识、插件展示名、user_confirmed 不会作为标签出现在最终比较结果里。

调用关系:它使用 SessionTelemetry::new 建立记录器,并通过 with_metrics_without_metadata_tags 避免自动会话标签干扰测试。核心动作交给 record_plugin_install_suggestion。之后还是用 latest_metrics 抽取导出的指标,用 find_metric 按指标名定位,用 attributes_to_map 转换标签,再用 assert_eq! 验证标签集合正好符合设计。

调用图:调用 6 个内部函数(new, attributes_to_map, build_metrics_with_defaults, find_metric, latest_metrics, new);外部调用 2 个(assert_eq!, panic!)。

manager_records_plugin_install_elicitation_sent_metric222–262 ↗
fn manager_records_plugin_install_elicitation_sent_metric() -> Result<()>

作用:这个测试确认“已经向用户发出插件安装询问”会被记录成专门的指标。它验证这类指标只按工具类型统计,不按具体插件名统计,避免指标维度过细或泄露不必要信息。

数据流:进去的是测试指标环境、关闭自动元信息标签的 SessionTelemetry,以及一次插件安装询问事件:工具类型是 plugin,插件标识是 slack@openai-curated,展示名是 Slack。测试调用 record_plugin_install_elicitation_sent 写入指标,关闭并导出指标后,找到 PLUGIN_INSTALL_ELICITATION_SENT_METRIC,读取标签。出来的预期结果只有 tool_type=plugin;具体插件标识和名称不会进入标签。

调用关系:它和插件安装建议的测试类似,但调用的是 record_plugin_install_elicitation_sent,检查的是另一条指标常量 PLUGIN_INSTALL_ELICITATION_SENT_METRIC。它同样依赖 build_metrics_with_defaults 准备环境,依赖 latest_metrics 和 find_metric 找到导出结果,再用 attributes_to_map 与 assert_eq! 完成验证。

调用图:调用 6 个内部函数(new, attributes_to_map, build_metrics_with_defaults, find_metric, latest_metrics, new);外部调用 2 个(assert_eq!, panic!)。

遥测导出与路由

这些测试涵盖遥测如何在日志和跟踪之间路由,以及完整的 OTLP/HTTP 导出如何通过网络发出。

otel/tests/suite/otel_export_routing_policy.rs源码 ↗
testtest

这个文件测试的是 OpenTelemetry,简称 OTEL,也就是一套把程序运行情况发出去做观察和排查的标准。这里关心一个很实际的问题:日志可以保存较完整的信息,但追踪通常应该只放统计信息和排查线索,不能把用户输入、工具输出这类敏感原文到处传播。测试会搭一个“假出口”,把日志和追踪都先存在内存里,不真的发到外部系统。然后它模拟一次会话,触发用户提示词、工具结果、认证恢复、API 请求、WebSocket 连接等事件。最后逐项检查:日志里能看到需要的原文和认证细节;追踪事件里只看到长度、数量、状态等安全摘要;并且日志事件都走到专门的 log_only 目标。它像给快递分拣线做质检,确保机密包裹不会被送错通道。

函数细节12
log_attributes28–33 ↗
fn log_attributes(record: &SdkLogRecord) -> BTreeMap<String, String>

作用:把一条日志记录里的属性整理成普通的“名字到文字值”的表,方便测试直接检查某个字段有没有、值对不对。

数据流:进去的是一条 SDK 日志记录;它读取这条日志的全部属性,把每个属性名转成字符串,并把各种类型的属性值也转成字符串;出来的是一个按键名排序的表,不改动原日志。

调用关系:各个测试在拿到内存里的日志后都会用它做第一步整理。它内部依赖 attributes_iter 取出属性,并把值交给 any_value_to_string 变成好比较的文字。

调用图:被 6 处调用(otel_export_routing_policy_routes_api_request_auth_observability, otel_export_routing_policy_routes_auth_recovery_log_and_trace_events, otel_export_routing_policy_routes_tool_result_log_and_trace_events, otel_export_routing_policy_routes_user_prompt_log_and_trace_events, otel_export_routing_policy_routes_websocket_connect_auth_observability, otel_export_routing_policy_routes_websocket_request_transport_observability);外部调用 1 个(attributes_iter)。

span_event_attributes35–41 ↗
fn span_event_attributes(event: &opentelemetry::trace::Event) -> BTreeMap<String, String>

作用:把一次追踪事件里的属性整理成普通表,让测试能像查清单一样检查追踪里有哪些字段。

数据流:进去的是一个追踪事件;它遍历事件自带的键值属性,把键和值都转成字符串;出来的是一个字段名到字段值的表,不改变事件本身。

调用关系:所有检查追踪内容的测试都会调用它。它和 log_attributes 成对出现:一个看日志,一个看追踪,用来确认同一个事件在两个出口里的内容是否符合规则。

调用图:被 6 处调用(otel_export_routing_policy_routes_api_request_auth_observability, otel_export_routing_policy_routes_auth_recovery_log_and_trace_events, otel_export_routing_policy_routes_tool_result_log_and_trace_events, otel_export_routing_policy_routes_user_prompt_log_and_trace_events, otel_export_routing_policy_routes_websocket_connect_auth_observability, otel_export_routing_policy_routes_websocket_request_transport_observability)。

any_value_to_string43–54 ↗
fn any_value_to_string(value: &AnyValue) -> String

作用:把 OTEL 日志属性里的各种值统一转成文字,避免测试时还要分别处理整数、小数、布尔值、字符串、字节等不同格式。

数据流:进去的是一个 AnyValue,也就是 OTEL 用来装任意属性值的容器;它根据实际类型分别转换,比如数字转数字文本、布尔值转 true 或 false、字节按 UTF-8 尽量转成可读文字;出来的是一个字符串。

调用关系:它主要服务于 log_attributes。日志属性的值类型很多,log_attributes 需要它来把这些值统一成测试容易比较的形式。

调用图:外部调用 4 个(as_str, to_string, from_utf8_lossy, format!)。

find_log_by_event_name56–67 ↗
fn find_log_by_event_name(
    logs: &'a [opentelemetry_sdk::logs::in_memory_exporter::LogDataWithResource],
    event_name: &str,
) -> &'a opentelemetry_sdk::logs::in_memory_exporter::LogDataWithReso

作用:在一堆日志里找到指定事件名的那一条,比如找到 codex.user_prompt 对应的日志。

数据流:进去的是日志列表和想找的事件名;它逐条查看日志属性里的 event.name 字段;找到匹配的就返回那条日志,找不到就让测试失败并提示日志事件应该存在。

调用关系:每个测试触发事件后都会先用它从内存日志中挑出目标日志。它会借助 log_attributes 读取字段,然后测试再继续检查这条日志里的具体属性。

调用图:被 6 处调用(otel_export_routing_policy_routes_api_request_auth_observability, otel_export_routing_policy_routes_auth_recovery_log_and_trace_events, otel_export_routing_policy_routes_tool_result_log_and_trace_events, otel_export_routing_policy_routes_user_prompt_log_and_trace_events, otel_export_routing_policy_routes_websocket_connect_auth_observability, otel_export_routing_policy_routes_websocket_request_transport_observability);外部调用 1 个(iter)。

find_span_event_by_name_attr69–81 ↗
fn find_span_event_by_name_attr(
    events: &'a [opentelemetry::trace::Event],
    event_name: &str,
) -> &'a opentelemetry::trace::Event

作用:在一个追踪 span 的事件列表里找到指定事件名的事件。span 可以理解成一次操作的时间段,里面可以挂多个小事件。

数据流:进去的是追踪事件列表和要找的事件名;它逐个读取事件属性中的 event.name;找到匹配事件就返回,找不到就让测试失败。

调用关系:所有检查追踪事件的测试都会用它。它和 find_log_by_event_name 类似,只是一个找日志,一个找追踪事件;找到后再交给 span_event_attributes 整理字段。

调用图:被 6 处调用(otel_export_routing_policy_routes_api_request_auth_observability, otel_export_routing_policy_routes_auth_recovery_log_and_trace_events, otel_export_routing_policy_routes_tool_result_log_and_trace_events, otel_export_routing_policy_routes_user_prompt_log_and_trace_events, otel_export_routing_policy_routes_websocket_connect_auth_observability, otel_export_routing_policy_routes_websocket_request_transport_observability);外部调用 1 个(iter)。

auth_env_metadata83–92 ↗
fn auth_env_metadata() -> AuthEnvTelemetryMetadata

作用:造一份固定的认证环境信息,供测试模拟“环境变量里有哪些密钥、开关是否打开”等情况。

数据流:它不接收输入;直接构造一份 AuthEnvTelemetryMetadata,里面写死了 openai key 存在、codex key 不存在但启用、供应商 key 名为 configured、刷新 token 地址被覆盖等信息;返回这份测试用数据。

调用关系:认证相关的测试会把它挂到 SessionTelemetry 上。这样后面触发 API 请求或 WebSocket 事件时,日志和追踪里就应该带上这些认证环境字段,测试再检查它们有没有正确出现。

otel_export_routing_policy_routes_user_prompt_log_and_trace_events95–203 ↗
fn otel_export_routing_policy_routes_user_prompt_log_and_trace_events()

作用:测试用户输入提示词时,日志可以记录提示词原文和用户邮箱,但追踪只能记录长度和输入数量,不能带原文和用户身份。

数据流:开始时它创建内存日志出口和内存追踪出口,再装上带过滤规则的订阅器;随后创建一次会话,模拟用户输入文字、网络图片和本地图片;刷新出口后读取结果,检查日志里有 prompt 和 user.email,追踪里只有 prompt_length、text_input_count、image_input_count、local_image_input_count 等摘要,并确认没有敏感字段。

调用关系:这是对导出分流策略的核心测试之一。它触发 SessionTelemetry 的 user_prompt,之后用 find_log_by_event_name、log_attributes、find_span_event_by_name_attr、span_event_attributes 这些辅助函数分别检查日志出口和追踪出口。

调用图:调用 4 个内部函数(find_log_by_event_name, find_span_event_by_name_attr, log_attributes, span_event_attributes);外部调用 11 个(default, default, builder, builder, assert!, assert_eq!, new, with_default, layer, filter_fn (+1 more))。

otel_export_routing_policy_routes_tool_result_log_and_trace_events206–314 ↗
fn otel_export_routing_policy_routes_tool_result_log_and_trace_events()

作用:测试工具调用结果的分流:日志里可以有工具参数和输出,追踪里只能有参数长度、输出长度、行数等摘要。

数据流:它先搭好内存日志和追踪出口,再创建会话并模拟一次 shell 工具结果,包含秘密参数、两行秘密输出和 MCP 标签;刷新后读取日志和追踪,确认日志保留 arguments、output、mcp_server、mcp_server_origin,追踪只保留长度、行数等字段,并且不包含原始参数、原始输出或 MCP 标签。

调用关系:它验证 tool_result_with_tags 产生的事件是否被正确拆成两种版本。测试最后通过通用查找和属性整理函数来确认日志与追踪没有串线。

调用图:调用 4 个内部函数(find_log_by_event_name, find_span_event_by_name_attr, log_attributes, span_event_attributes);外部调用 11 个(default, default, builder, builder, assert!, assert_eq!, new, with_default, layer, filter_fn (+1 more))。

otel_export_routing_policy_routes_auth_recovery_log_and_trace_events317–460 ↗
fn otel_export_routing_policy_routes_auth_recovery_log_and_trace_events()

作用:测试认证恢复事件,比如 token 过期后重新加载,是否在日志和追踪里都带上必要的排查字段。

数据流:它创建内存出口和订阅器,启动一个使用 ChatGPT 认证模式的会话,然后记录一次认证恢复:模式、步骤、结果、请求 ID、Cloudflare ray ID、错误和错误码、状态是否变化;刷新后分别读取日志和追踪,确认这些字段两边都存在且值正确。

调用关系:它触发 SessionTelemetry 的 record_auth_recovery。因为这类信息主要用于排查登录和授权问题,不是用户正文,所以测试要求日志和追踪都能看到同样的认证诊断字段。

调用图:调用 4 个内部函数(find_log_by_event_name, find_span_event_by_name_attr, log_attributes, span_event_attributes);外部调用 10 个(default, default, builder, builder, assert_eq!, new, with_default, layer, filter_fn, registry)。

otel_export_routing_policy_routes_api_request_auth_observability463–644 ↗
fn otel_export_routing_policy_routes_api_request_auth_observability()

作用:测试 API 请求失败或重试时,认证相关线索会被记录下来,方便排查为什么请求被拒绝。

数据流:它先准备内存日志和追踪出口,创建带认证环境信息的会话;接着记录会话开始,再记录一次 API 请求,里面包含 401 状态、是否带 Authorization 头、是否因未授权而重试、恢复模式、接口路径、请求 ID、错误和错误码;最后检查会话开始事件和 API 请求事件在日志、追踪中都带有应有的认证环境和请求字段。

调用关系:这个测试同时覆盖 conversation_starts 和 record_api_request 两类事件。它使用 auth_env_metadata 提供固定环境,再用查找和属性整理辅助函数核对日志出口与追踪出口里的字段。

调用图:调用 4 个内部函数(find_log_by_event_name, find_span_event_by_name_attr, log_attributes, span_event_attributes);外部调用 10 个(default, default, builder, builder, assert_eq!, new, with_default, layer, filter_fn, registry)。

otel_export_routing_policy_routes_websocket_connect_auth_observability647–761 ↗
fn otel_export_routing_policy_routes_websocket_connect_auth_observability()

作用:测试 WebSocket 建连时的认证信息会被正确记录。WebSocket 可以理解成一条持续打开的网络连接。

数据流:它搭好内存出口,创建带认证环境信息的会话,然后模拟一次 WebSocket 连接,包含耗时、401 状态、是否带认证头、是否重试、恢复阶段、接口路径、连接是否复用、请求 ID 和错误信息;刷新后检查日志里的认证头、错误、接口、连接复用和环境字段,也检查追踪里的恢复阶段和刷新 token 地址覆盖信息。

调用关系:它触发 SessionTelemetry 的 record_websocket_connect。这个测试专门覆盖长连接建立阶段,确保认证排查信息不会只出现在普通 API 请求里。

调用图:调用 4 个内部函数(find_log_by_event_name, find_span_event_by_name_attr, log_attributes, span_event_attributes);外部调用 10 个(default, default, builder, builder, assert_eq!, new, with_default, layer, filter_fn, registry)。

otel_export_routing_policy_routes_websocket_request_transport_observability764–851 ↗
fn otel_export_routing_policy_routes_websocket_request_transport_observability()

作用:测试 WebSocket 已连接后的请求传输问题会被记录,比如流式传输报错和连接是否复用。

数据流:它创建内存日志和追踪出口,启动带认证环境信息的会话,记录一次 WebSocket 请求,包含耗时、错误消息和连接复用状态;刷新后检查日志里有 stream error、connection_reused 和认证环境字段,追踪里也有连接复用和供应商 key 是否存在等字段。

调用关系:它触发 SessionTelemetry 的 record_websocket_request。相比建连测试,它关注连接已经存在后的请求过程;最后同样借助日志和追踪辅助函数确认字段进入了正确出口。

调用图:调用 4 个内部函数(find_log_by_event_name, find_span_event_by_name_attr, log_attributes, span_event_attributes);外部调用 10 个(default, default, builder, builder, assert_eq!, new, with_default, layer, filter_fn, registry)。

otel/tests/suite/otlp_http_loopback.rs源码 ↗
testtest run

OTLP 是 OpenTelemetry 用来上报遥测数据的协议,遥测数据包括指标、日志和追踪。这个测试文件不依赖真正的外部服务器,而是在本机开一个很小的假 HTTP 服务器,像“收件箱”一样接住程序发出的请求。测试会配置不同的导出器,让 MetricsClient 或 OtelProvider 发送指标、日志、追踪,然后检查收到的请求路径是不是 /v1/metrics、/v1/logs 或 /v1/traces,内容类型是不是 JSON,正文里有没有期望的名字、标签和服务信息。它还专门测试 W3C Trace Context(跨服务传递追踪身份的一套标准)和 tracestate 的安全性,避免换行等危险内容被塞进 HTTP 头。文件里的两个小工具函数负责读 HTTP 请求和写 HTTP 响应,其余函数都是具体测试场景。

函数细节8
read_http_request33–134 ↗
fn read_http_request(
    stream: &mut TcpStream,
) -> std::io::Result<(String, HashMap<String, String>, Vec<u8>)>

作用:从一个 TCP 连接里手工读出一条 HTTP 请求,拿到请求路径、请求头和请求正文。测试里的假服务器靠它看清楚“客户端到底发来了什么”。

数据流:输入是一条已经连上的 TcpStream,也就是一根网络连接管道。它先设置最多等 2 秒,然后一点点读取字节,直到读到 HTTP 头和正文的分隔符;接着把头部按 UTF-8 文本解析,取出路径和各个请求头;如果有 Content-Length,就继续读够指定长度的正文。最后输出路径、请求头表和正文 bytes;如果超时、头太大、格式不对或正文没读完,就返回输入输出错误。

调用关系:每个测试都会启动一个本机假服务器。这个假服务器收到连接后,就调用 read_http_request 把导出器发来的 HTTP 请求拆开,之后测试才能检查路径、content-type 和正文内容。它读完后通常会配合 write_http_response 给客户端回一个成功响应。

调用图:外部调用 7 个(from_secs, new, now, set_read_timeout, new, new, from_utf8)。

write_http_response136–140 ↗
fn write_http_response(stream: &mut TcpStream, status: &str) -> std::io::Result<()>

作用:给测试里的假 HTTP 服务器写回一个极简响应,比如“202 Accepted”。这样被测的导出器会以为收集器已经收到了数据。

数据流:输入是一条 TCP 连接和一个状态字符串。它把状态拼成一段 HTTP/1.1 响应文本,声明正文长度为 0,并要求关闭连接;然后把这段文本写进连接并刷新。结果是客户端能收到一个完整响应;函数本身只返回写入是否成功。

调用关系:假服务器在 read_http_request 读完请求后调用它。它不检查业务内容,只负责“回信”,让指标、日志或追踪导出流程能正常结束,而不是卡在等待服务器响应上。

调用图:外部调用 3 个(flush, write_all, format!)。

otlp_http_exporter_sends_metrics_to_collector143–231 ↗
fn otlp_http_exporter_sends_metrics_to_collector() -> Result<()>

作用:验证指标导出器真的会把计数器和仪表盘数值通过 OTLP HTTP JSON 发到收集器。没有这个测试,指标名字、标签或 HTTP 路径改坏了可能没人发现。

数据流:测试先在 127.0.0.1 上开一个随机端口的假服务器,并用通道收集它抓到的请求。然后创建 MetricsClient,配置它把数据发到这个假服务器的 /v1/metrics;接着发送一个 counter(计数器)和一个 gauge(当前值),再 shutdown 强制把缓冲里的数据刷出去。最后测试从假服务器拿回请求,检查路径、content-type,以及正文里是否包含 codex.turns、codex.active 和标签 component=test。

调用关系:这是指标链路的端到端小演练。它内部让假服务器使用 read_http_request 接收请求、write_http_response 回复成功;被测对象是 MetricsClient 和 OTLP HTTP 导出配置。它证明“创建指标 → 上报 → HTTP 收到 → 内容可识别”这条路是通的。

调用图:调用 2 个内部函数(new, otlp);外部调用 8 个(from_secs, new, from_utf8_lossy, bind, assert!, env!, format!, spawn)。

otlp_http_exporter_sends_logs_to_collector234–323 ↗
fn otlp_http_exporter_sends_logs_to_collector() -> std::result::Result<(), Box<dyn std::error::Error>>

作用:验证日志事件能通过 OTLP HTTP JSON 发到收集器。它保证 tracing 产生的日志不会只停留在本地,而是真的被 OpenTelemetry 日志导出层送出去。

数据流:测试先启动本机假服务器,准备接收 /v1/logs。然后用 OtelSettings 创建 OtelProvider,只启用日志导出,不启用追踪和指标;再把 logger_layer 接到 tracing_subscriber 上。随后发出一个带 event.name 的 INFO 日志事件,调用 shutdown 刷出数据。最后取回假服务器抓到的请求,确认 content-type 是 JSON,并且正文里有 codex.test.log_exported。

调用关系:这个测试站在日志导出流程的最外层。它把 OtelProvider、tracing_subscriber 和假 HTTP 收集器串起来:tracing 产生日志,logger_layer 接住日志,OTLP HTTP 导出器发送,假服务器捕获并让测试断言内容。

调用图:调用 1 个内部函数(from);外部调用 12 个(new, from_secs, new, from, from_utf8_lossy, bind, assert!, env!, format!, spawn (+2 more))。

otel_provider_rejects_header_unsafe_configured_tracestate326–352 ↗
fn otel_provider_rejects_header_unsafe_configured_tracestate()

作用:验证配置里的 tracestate 如果包含不适合放进 HTTP 头的危险字符,会被 OtelProvider 拒绝。这里重点防的是换行这类可能破坏 HTTP 头结构的内容。

数据流:输入是一份故意写坏的 OtelSettings:tracestate 里有值 one\ntwo,中间带换行。函数尝试创建 OtelProvider,预期不是成功,而是拿到错误。最后检查错误文字里提到了 configured tracestate value,说明拒绝原因确实是配置的 tracestate 值不安全。

调用关系:它不是测试发送数据,而是测试启动前的安全校验。OtelProvider::from 在创建遥测提供者时会检查配置;这个测试确保坏配置在进入真正的 HTTP 传播和导出流程之前就被挡住。

调用图:调用 1 个内部函数(from);外部调用 6 个(from, new, new, from, assert!, env!)。

otlp_http_exporter_sends_traces_to_collector355–497 ↗
fn otlp_http_exporter_sends_traces_to_collector() -> std::result::Result<(), Box<dyn std::error::Error>>

作用:验证追踪 span 和事件能通过 OTLP HTTP JSON 发到收集器,并且 W3C trace context 的父子关系和 tracestate 合并规则正常工作。它覆盖的是最复杂的追踪链路。

数据流:测试先拿一把全局互斥锁(一把锁,防止多个测试同时改同一份追踪上下文配置),再启动假服务器接收 /v1/traces。随后创建只启用追踪导出的 OtelProvider,并配置一个固定 span 属性和 tracestate 规则。测试创建一个 span,把外部传入的 traceparent/tracestate 设置成它的父上下文,进入 span 后读取当前 span 要继续传播出去的 W3C 上下文,并发出追踪事件。shutdown 后,测试先确认传播出的 tracestate 已按配置改成期望值,再检查假服务器收到的 JSON 里有 span 名、服务名、配置属性和事件名。

调用关系:这是追踪导出的主测试。它把 set_parent_from_w3c_trace_context、current_span_w3c_trace_context、tracing_layer、OTLP HTTP 导出器和假服务器连成一条完整链路:外部上下文进入 span,span 产生事件,导出器发送到 /v1/traces,测试再检查传出上下文和导出内容。

调用图:调用 1 个内部函数(from);外部调用 13 个(from, from_secs, new, from, from_utf8_lossy, bind, assert!, assert_eq!, env!, format! (+3 more))。

otlp_http_exporter_sends_traces_to_collector_in_tokio_runtime500–600 ↗
async fn otlp_http_exporter_sends_traces_to_collector_in_tokio_runtime() -> std::result::Result<(), Box<dyn std::error::Error>>

作用:验证追踪导出在 Tokio 多线程异步运行时里也能正常工作。Tokio 是 Rust 常用的异步任务运行器,这个测试防止导出器只在普通同步环境里可用。

数据流:测试用 Tokio 的多线程测试运行时启动。它先加锁避免追踪上下文测试互相干扰,然后开本机假服务器。接着创建追踪用的 OtelProvider 和 tracing subscriber,在 subscriber 里创建名为 trace-loopback-tokio 的 span 并写一条日志。shutdown 后从假服务器取回请求,检查 /v1/traces 的 JSON 正文里包含 span 名和服务名 codex-cli。

调用关系:它和普通追踪测试走同一条导出链路,但外层运行环境换成 Tokio 多线程运行时。这样可以证明 OtelProvider 和导出器在异步程序中不会因为运行时线程模型不同而漏发或卡住。

调用图:调用 1 个内部函数(from);外部调用 12 个(new, from_secs, new, from, from_utf8_lossy, bind, assert!, env!, format!, spawn (+2 more))。

otlp_http_exporter_sends_traces_to_collector_in_current_thread_tokio_runtime603–722 ↗
fn otlp_http_exporter_sends_traces_to_collector_in_current_thread_tokio_runtime() -> std::result::Result<(), Box<dyn std::error::Error>>

作用:验证追踪导出在 Tokio 单线程运行时里也能完成。单线程运行时更容易暴露“等待自己导致卡死”这类问题,所以这个测试很重要。

数据流:测试先启动假服务器,然后另外开一个线程,在里面创建 Tokio current-thread 运行时,也就是所有异步任务主要在一个线程里跑。运行时中创建 OtelProvider、接上 tracing_layer、创建 trace-loopback-current-thread span 并写日志,然后 shutdown。测试通过通道等待运行时线程报告成功,再从假服务器取回请求,检查 JSON 正文里有 span 名和 codex-cli。

调用关系:它专门覆盖和多线程 Tokio 不同的环境。外层线程负责假服务器和断言,运行时线程负责创建并关闭遥测导出器;两边用通道同步结果。这样能确认追踪导出不会依赖多线程运行时才能正常把数据送到 /v1/traces。

调用图:外部调用 5 个(from_secs, from_utf8_lossy, bind, assert!, spawn)。

分析客户端与测试夹具

这些文件构建面向分析的测试夹具,并验证分析客户端行为,从传输决策到由 reducer 驱动的完整事件生成。

analytics/src/client_tests.rs源码 ↗
testtest/debug validation

这个文件不像正式功能代码,而是给分析事件客户端做“体检”。分析事件可以理解成产品运行时留下的使用记录,比如用户开始一次对话、模型回复、接受了哪些代码行等。测试里先造出假的事件、假的请求、假的服务器响应,再看客户端会不会只挑有用的内容放进队列。它还检查发送目的地的选择:普通情况下走 HTTP 网络地址;调试版本里如果指定了捕获文件,就把要发送的内容按 JSON 行写到文件里,方便开发者检查。一个重要细节是,“接受代码行指纹”这种事件必须单独成批发送,不能和普通事件混在一起。整个文件就像质检员,拿一堆样品去验证分析系统的关键规则有没有被破坏。

函数细节22
sample_accepted_line_fingerprint_event50–68 ↗
fn sample_accepted_line_fingerprint_event(thread_id: &str) -> TrackEventRequest

作用:造一个假的“接受代码行指纹”分析事件。这个事件代表用户接受了某些代码行,用来测试这类特殊事件是否会被单独发送。

数据流:输入一个线程编号 → 把它填进事件里的 thread_id,并补上固定的 turn_id、模型名、接受行数等测试数据 → 返回一个 TrackEventRequest,也就是一条可被发送的分析事件。

调用关系:它是测试样品制造器。后面的分批测试和捕获文件批量写入测试会把它和普通事件混在一起,用来确认主逻辑会把这种特殊事件单独拎出来。

调用图:外部调用 3 个(new, new, AcceptedLineFingerprints)。

sample_regular_track_event70–86 ↗
fn sample_regular_track_event(thread_id: &str) -> TrackEventRequest

作用:造一个普通的技能调用分析事件。它用来代表一般埋点,和特殊的代码行指纹事件形成对照。

数据流:输入一个线程编号 → 用这个编号拼出 skill_id,并放进事件参数里的 thread_id、turn_id、调用类型、模型名等字段 → 返回一条普通的 TrackEventRequest。

调用关系:它被捕获文件单条写入测试调用,也被其他测试用来组成事件列表。测试借它确认普通事件可以正常序列化、写入和分批。

调用图:被 1 处调用(capture_file_writes_exact_serialized_request);外部调用 2 个(SkillInvocation, format!)。

unique_capture_path89–98 ↗
fn unique_capture_path(name: &str) -> PathBuf

作用:生成一个几乎不会和别的测试撞名的临时文件路径。这样多个测试同时跑时,不会互相覆盖对方的捕获文件。

数据流:输入一个名字标签 → 读取当前时间和当前进程号,把它们拼进文件名,再放到系统临时目录下 → 返回一个 PathBuf,也就是文件路径对象。

调用关系:它只在调试版本的测试里使用。凡是需要写捕获文件的测试,都会先找它要一个安全的临时路径。

调用图:被 4 处调用(analytics_destination_uses_explicit_capture_file, capture_file_writes_exact_serialized_request, capture_file_writes_final_batches_as_separate_lines, capture_write_failure_still_consumes_delivery);外部调用 3 个(now, format!, temp_dir)。

client_with_receiver100–108 ↗
fn client_with_receiver() -> (AnalyticsEventsClient, mpsc::Receiver<AnalyticsFact>)

作用:搭一个带接收端的测试版分析客户端。测试可以通过接收端看到客户端到底有没有把分析事实放进队列。

数据流:没有外部输入 → 创建一个容量为 8 的异步通道,再创建两个带互斥锁的集合;互斥锁就是一把锁,防止多个任务同时改同一份集合 → 返回分析客户端和通道接收端。

调用关系:请求追踪测试和响应追踪测试都用它开局。测试调用客户端的 track_request 或 track_response 后,就从接收端检查有没有收到 AnalyticsFact。

调用图:被 2 处调用(track_request_only_enqueues_analytics_relevant_requests, track_response_only_enqueues_analytics_relevant_responses);外部调用 4 个(new, new, new, channel)。

analytics_destination_uses_explicit_capture_file112–140 ↗
fn analytics_destination_uses_explicit_capture_file()

作用:确认调试版本里,如果明确给了捕获文件路径,分析事件目的地会变成本地文件,而不是网络地址。

数据流:先生成一个唯一临时路径 → 调用目的地选择函数,并传入基础网址和这个路径 → 检查结果是不是 CaptureFile,文件是否被创建且为空;在 Unix 系统上还检查权限是不是只有当前用户能读写 → 最后删除临时文件。

调用关系:它直接验证 AnalyticsEventsDestination::from_base_url_and_capture_file 的调试行为。这个测试保证开发者开捕获模式时,数据真的会落到指定文件,并且文件权限比较安全。

调用图:调用 2 个内部函数(from_base_url_and_capture_file, unique_capture_path);外部调用 3 个(assert_eq!, metadata, remove_file)。

analytics_destination_uses_http_without_capture_file143–155 ↗
fn analytics_destination_uses_http_without_capture_file()

作用:确认没有指定捕获文件时,分析事件会走正常的 HTTP 网络地址发送。

数据流:输入一个后端基础网址,并把捕获文件设为空 → 调用目的地选择函数 → 得到 Http 目的地,并检查最终 URL 是否拼成 analytics-events/events 这个接口。

调用关系:它验证最常见的运行路径:没有调试捕获文件时,分析事件应该发往服务端,而不是写本地。

调用图:调用 1 个内部函数(from_base_url_and_capture_file);外部调用 1 个(assert_eq!)。

analytics_destination_ignores_capture_file_in_release159–171 ↗
fn analytics_destination_ignores_capture_file_in_release()

作用:确认发布版本会忽略捕获文件参数,仍然使用网络发送。这样可以避免正式环境意外把分析数据写到本地文件。

数据流:传入基础网址和一个看似有效的文件名 → 调用目的地选择函数 → 检查结果仍然是 Http 目的地,而不是 CaptureFile。

调用关系:它只在非调试版本编译时运行。这个测试守住边界:捕获文件是开发调试工具,不应该影响正式发布行为。

调用图:调用 1 个内部函数(from_base_url_and_capture_file);外部调用 2 个(assert_eq!, from)。

capture_file_writes_exact_serialized_request175–194 ↗
async fn capture_file_writes_exact_serialized_request()

作用:确认写入捕获文件的内容,和真正要发送的 JSON 请求完全一致。换句话说,捕获文件不是随便记日志,而是在保存真实发送包。

数据流:先生成临时文件路径和一个普通事件 → 把事件转成期望的 JSON 值,再创建一个测试用假登录身份 → 调用发送函数写入捕获文件 → 读回文件,解析唯一一行 JSON,并检查它正好是 {"events": [...]} → 最后删除文件。

调用关系:它调用 sample_regular_track_event 准备样品,也调用 send_track_events_request 走真实发送入口。这个测试保证捕获文件模式能忠实记录发送请求。

调用图:调用 3 个内部函数(sample_regular_track_event, unique_capture_path, create_dummy_chatgpt_auth_for_testing);外部调用 7 个(assert_eq!, read_to_string, remove_file, from_str, to_value, send_track_events_request, vec!)。

capture_file_writes_final_batches_as_separate_lines198–228 ↗
async fn capture_file_writes_final_batches_as_separate_lines()

作用:确认多个最终发送批次会在捕获文件里写成多行,一批一行。这样开发者打开文件时,可以清楚看到每次发送了什么。

数据流:生成临时文件和假登录身份 → 准备普通事件、特殊指纹事件、普通事件的混合列表 → 先交给分批函数拆成批次,再逐批调用发送函数 → 读回文件,把每一行解析成 JSON → 检查一共有三行,并且顺序和事件类型都正确 → 删除文件。

调用关系:它把 track_event_request_batches 和 send_track_events_request 串起来测试,模拟真实发送前的最后阶段。重点是确认分批结果写入文件时不会被重新混在一起。

调用图:调用 2 个内部函数(unique_capture_path, create_dummy_chatgpt_auth_for_testing);外部调用 6 个(assert_eq!, read_to_string, remove_file, send_track_events_request, track_event_request_batches, vec!)。

capture_write_failure_still_consumes_delivery232–240 ↗
fn capture_write_failure_still_consumes_delivery()

作用:确认即使捕获文件写失败,发送流程也会把这次投递当作已经处理完。这样不会因为调试文件路径坏了,就让队列反复卡住。

数据流:生成一个父目录不存在的文件路径 → 构造一个包含普通事件的请求包 → 调用捕获写入函数 → 断言它返回 true,表示这次投递被消费掉了,即使实际写文件失败。

调用关系:它测试 capture_track_events_request 的容错态度。这个行为很重要:捕获文件只是调试辅助,不能拖垮分析队列本身。

调用图:调用 1 个内部函数(unique_capture_path);外部调用 2 个(assert!, vec!)。

sample_turn_start_request242–252 ↗
fn sample_turn_start_request() -> ClientRequest

作用:造一个假的“开始一轮对话”客户端请求。它用来测试这类请求是否会被分析系统记录。

数据流:没有外部输入 → 填入固定的 request_id、thread_id 和空输入列表,其余字段用默认值 → 返回一个 ClientRequest::TurnStart。

调用关系:它被 track_request_only_enqueues_analytics_relevant_requests 使用。测试把它交给客户端追踪函数,预期队列里会出现一条客户端请求分析事实。

调用图:被 1 处调用(track_request_only_enqueues_analytics_relevant_requests);外部调用 3 个(default, new, Integer)。

sample_turn_steer_request254–266 ↗
fn sample_turn_steer_request() -> ClientRequest

作用:造一个假的“继续引导当前对话轮次”请求。它代表用户在已有轮次中继续给指令。

数据流:没有外部输入 → 填入固定 request_id、thread_id、expected_turn_id 和空输入列表 → 返回一个 ClientRequest::TurnSteer。

调用关系:它也是请求追踪测试里的正面样品。客户端收到这类请求时应该记录分析事实,所以测试会检查队列里有输出。

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

sample_thread_archive_request268–275 ↗
fn sample_thread_archive_request() -> ClientRequest

作用:造一个假的“归档线程”请求。它用来测试不重要的请求不会被分析系统记录。

数据流:没有外部输入 → 填入固定 request_id 和 thread_id → 返回一个 ClientRequest::ThreadArchive。

调用关系:它在请求追踪测试里作为反面样品。客户端处理它之后,接收队列应该仍然是空的。

调用图:被 1 处调用(track_request_only_enqueues_analytics_relevant_requests);外部调用 1 个(Integer)。

sample_thread277–300 ↗
fn sample_thread(thread_id: &str) -> Thread

作用:造一个假的线程对象。线程可以理解成一次会话的容器,里面会有多轮对话。

数据流:输入一个线程编号 → 用它填出线程 id、session_id,并补上创建时间、更新时间、状态、工作目录、来源等固定测试字段 → 返回一个 Thread 对象。

调用关系:它被三种线程响应样品函数复用:开始线程、恢复线程、分叉线程。这样这些响应测试共享同一套可信的假线程数据。

调用图:被 3 处调用(sample_thread_fork_response, sample_thread_resume_response, sample_thread_start_response);外部调用 3 个(new, test_path_buf, format!)。

sample_thread_start_response302–317 ↗
fn sample_thread_start_response() -> ClientResponsePayload

作用:造一个假的“线程开始成功”服务器响应。它用来确认这种响应会被分析系统记录。

数据流:没有外部输入 → 调用 sample_thread 生成 thread-1,再补上模型、工作目录、审批策略、沙箱策略等响应字段 → 返回 ClientResponsePayload::ThreadStart。

调用关系:它被响应追踪测试使用。客户端追踪到这个响应时,应该往队列里放一条客户端响应分析事实。

调用图:调用 1 个内部函数(sample_thread);被 1 处调用(track_response_only_enqueues_analytics_relevant_responses);外部调用 3 个(ThreadStart, new, test_path_buf)。

sample_thread_resume_response319–335 ↗
fn sample_thread_resume_response() -> ClientResponsePayload

作用:造一个假的“恢复旧线程成功”服务器响应。它代表用户继续之前的会话。

数据流:没有外部输入 → 调用 sample_thread 生成 thread-2,并填入模型、目录、权限相关字段和空的初始分页信息 → 返回 ClientResponsePayload::ThreadResume。

调用关系:它是响应追踪测试的正面样品之一。测试借它确认恢复线程这种响应也属于值得分析记录的事件。

调用图:调用 1 个内部函数(sample_thread);被 1 处调用(track_response_only_enqueues_analytics_relevant_responses);外部调用 3 个(ThreadResume, new, test_path_buf)。

sample_thread_fork_response337–352 ↗
fn sample_thread_fork_response() -> ClientResponsePayload

作用:造一个假的“从旧线程分叉出新线程成功”响应。分叉可以理解成从已有会话复制出一条新路线继续聊。

数据流:没有外部输入 → 调用 sample_thread 生成 thread-3,并补齐模型、目录、权限和沙箱等字段 → 返回 ClientResponsePayload::ThreadFork。

调用关系:它被响应追踪测试调用。这个样品帮助确认分叉线程的响应不会被漏记。

调用图:调用 1 个内部函数(sample_thread);被 1 处调用(track_response_only_enqueues_analytics_relevant_responses);外部调用 3 个(ThreadFork, new, test_path_buf)。

sample_turn_start_response354–367 ↗
fn sample_turn_start_response() -> ClientResponsePayload

作用:造一个假的“对话轮次开始成功”响应。它代表服务端已经创建了一个正在进行的 turn,也就是一轮对话任务。

数据流:没有外部输入 → 创建一个 turn-1,状态设为 InProgress,内容列表为空,时间和错误为空 → 包成 ClientResponsePayload::TurnStart 返回。

调用关系:它是响应追踪测试的正面样品之一。客户端追踪到它时,应该产生分析事实。

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

sample_turn_steer_response369–373 ↗
fn sample_turn_steer_response() -> ClientResponsePayload

作用:造一个假的“引导轮次成功”响应。它只带回新的 turn_id,用来表示服务端接受了这次引导。

数据流:没有外部输入 → 创建包含 turn-2 的 TurnSteerResponse → 包成 ClientResponsePayload::TurnSteer 返回。

调用关系:它被响应追踪测试使用,用来确认 TurnSteer 这种简短响应也会进入分析队列。

调用图:被 1 处调用(track_response_only_enqueues_analytics_relevant_responses);外部调用 1 个(TurnSteer)。

track_request_only_enqueues_analytics_relevant_requests376–397 ↗
fn track_request_only_enqueues_analytics_relevant_requests()

作用:测试客户端只会记录和分析有关的请求,不会把所有请求都塞进分析队列。

数据流:先创建测试客户端和接收端 → 依次发送 TurnStart、TurnSteer 两种请求给 track_request → 每次都检查队列收到 ClientRequest 分析事实 → 再发送 ThreadArchive 请求 → 检查队列没有新东西。

调用关系:它驱动 client_with_receiver 和三个请求样品函数。这个测试直接保护 track_request 的筛选规则,避免分析数据过多或误报。

调用图:调用 4 个内部函数(client_with_receiver, sample_thread_archive_request, sample_turn_start_request, sample_turn_steer_request);外部调用 2 个(Integer, assert!)。

track_response_only_enqueues_analytics_relevant_responses400–423 ↗
fn track_response_only_enqueues_analytics_relevant_responses()

作用:测试客户端只会记录重要的服务器响应,比如线程开始、恢复、分叉和轮次变化,而忽略无关响应。

数据流:先创建测试客户端和接收端 → 依次构造五种重要响应并交给 track_response → 每次都确认队列收到 ClientResponse 分析事实 → 最后发送 ThreadArchive 响应 → 确认队列为空。

调用关系:它使用多个响应样品函数,把 track_response 的正反例都跑一遍。这个测试保证响应侧的埋点不会漏掉关键状态,也不会记录归档这类不需要的内容。

调用图:调用 6 个内部函数(client_with_receiver, sample_thread_fork_response, sample_thread_resume_response, sample_thread_start_response, sample_turn_start_response, sample_turn_steer_response);外部调用 3 个(ThreadArchive, Integer, assert!)。

track_event_request_batches_only_isolates_accepted_line_fingerprint_events426–443 ↗
fn track_event_request_batches_only_isolates_accepted_line_fingerprint_events()

作用:测试事件分批规则:只有“接受代码行指纹”事件需要单独一批,普通事件可以挨在一起发送。

数据流:输入一个混合事件列表:两个普通、两个特殊、两个普通 → 调用分批函数 → 检查结果是四批:普通两条一批,两个特殊各自一批,最后两个普通一批 → 再确认特殊批次确实标记为必须单独发送。

调用关系:它直接验证 track_event_request_batches 的核心规则。这个规则会影响最终网络请求或捕获文件的形状,所以这里专门用清晰的排列来防止未来改坏。

调用图:外部调用 4 个(assert!, assert_eq!, track_event_request_batches, vec!)。

analytics/src/analytics_client_tests.rs源码 ↗
testtest-time

这份文件不负责线上真正发送数据,而是用很多假消息模拟用户和 Codex 服务之间的互动,然后把 AnalyticsReducer 产出的埋点事件拿来比对。AnalyticsReducer 可以理解成“记账员”:它不断收到事实,比如线程创建、回合开始、工具执行完成、用户审批结果,然后整理成要上报的事件。测试里先造出固定的线程、回合、错误、插件信息等样本,再喂给这个记账员,最后检查输出字段是否完整、名称是否正确、重复事件是否被挡住。它特别重要,因为分析数据一旦字段变了,后台报表、产品判断、安全审计都可能被误导。这里还覆盖了边界情况,比如超大 diff 不带明细、子代理继承父线程信息、失败回合保留错误类型等。

函数细节101
sample_thread_with_metadata164–193 ↗
fn sample_thread_with_metadata(
    thread_id: &str,
    ephemeral: bool,
    source: AppServerSessionSource,
    thread_source: Option<AppServerThreadSource>,
    parent_thread_id: Option<String>,
)

作用:造一个带固定元数据的假线程,给测试当基础材料用。这样每个测试不用重复手写一大堆线程字段。

数据流:输入线程编号、是否临时线程、来源、父线程等信息 → 填入固定的 session、路径、状态、版本等字段 → 返回一个完整的 Thread 对象,不改外部状态。

调用关系:它是线程样本的底座;sample_thread_start_response 和 sample_thread_resume_response_with_source 会调用它,再把线程包进开始或恢复线程的响应里。

调用图:被 2 处调用(sample_thread_resume_response_with_source, sample_thread_start_response);外部调用 3 个(new, test_path_buf, format!)。

sample_thread_start_response195–220 ↗
fn sample_thread_start_response(
    thread_id: &str,
    ephemeral: bool,
    model: &str,
) -> ClientResponsePayload

作用:造一个“线程启动成功”的假客户端响应。测试用它模拟服务端告诉客户端:新会话已经建好了。

数据流:输入线程编号、是否临时、模型名 → 先生成线程元数据,再加上模型、目录、审批策略、沙箱策略等信息 → 返回 ClientResponsePayload::ThreadStart。

调用关系:很多测试在准备阶段调用它,让 reducer 先知道某个线程存在;它把线程细节交给 sample_thread_with_metadata 来生成。

调用图:调用 1 个内部函数(sample_thread_with_metadata);被 6 处调用(guardian_review_event_ingests_custom_fact_with_optional_target_item, ingest_review_prerequisites, ingest_turn_prerequisites, initialize_caches_client_and_thread_lifecycle_publishes_once_initialized, item_review_summaries_do_not_cross_threads_with_reused_item_ids, subagent_events_use_inherited_connection_unless_turn_connection_is_explicit);外部调用 3 个(ThreadStart, new, test_path_buf)。

sample_app_server_client_metadata222–230 ↗
fn sample_app_server_client_metadata() -> CodexAppServerClientMetadata

作用:造一份固定的客户端身份信息,比如客户端名、版本、通信方式。测试用它检查事件里是否正确带上“是谁在用”。

数据流:没有输入 → 填入固定的 product_client_id、codex-tui、版本号和 stdio 通信方式 → 返回 CodexAppServerClientMetadata。

调用关系:序列化测试会直接用它构造期望事件,主要出现在压缩事件和回合事件的 JSON 形状检查里。

调用图:被 2 处调用(compaction_event_serializes_expected_shape, turn_event_serializes_expected_shape)。

sample_runtime_metadata232–239 ↗
fn sample_runtime_metadata() -> CodexRuntimeMetadata

作用:造一份固定的运行环境信息,比如系统、架构、Codex 版本。这样测试能稳定检查事件里的运行环境字段。

数据流:没有输入 → 填入 macOS、aarch64、Codex 版本等固定值 → 返回 CodexRuntimeMetadata。

调用关系:初始化、压缩、子代理、回合事件等测试都会用它;它是测试里“运行环境”字段的统一来源。

调用图:被 7 处调用(compaction_event_ingests_custom_fact, compaction_event_serializes_expected_shape, guardian_review_event_ingests_custom_fact_with_optional_target_item, ingest_initialize, ingest_rejected_turn_steer, subagent_events_use_inherited_connection_unless_turn_connection_is_explicit, turn_event_serializes_expected_shape)。

sample_thread_resume_response241–254 ↗
fn sample_thread_resume_response(
    thread_id: &str,
    ephemeral: bool,
    model: &str,
) -> ClientResponsePayload

作用:造一个“恢复已有线程成功”的假响应。测试用它模拟用户重新打开或接续一个线程。

数据流:输入线程编号、是否临时、模型名 → 使用默认来源信息转交给 sample_thread_resume_response_with_source → 返回恢复线程响应。

调用关系:它是更简单的包装函数;需要自定义来源时测试会直接用 sample_thread_resume_response_with_source。

调用图:调用 1 个内部函数(sample_thread_resume_response_with_source);被 2 处调用(ingest_rejected_turn_steer, initialize_caches_client_and_thread_lifecycle_publishes_once_initialized)。

sample_thread_resume_response_with_source256–285 ↗
fn sample_thread_resume_response_with_source(
    thread_id: &str,
    ephemeral: bool,
    model: &str,
    source: AppServerSessionSource,
    thread_source: Option<AppServerThreadSource>,
    paren

作用:造一个可指定来源和父线程的“恢复线程成功”响应。它用于测试子代理、继承关系等更复杂场景。

数据流:输入线程编号、是否临时、模型、会话来源、线程来源、父线程编号 → 生成线程元数据并补上运行配置 → 返回 ClientResponsePayload::ThreadResume。

调用关系:sample_thread_resume_response 会调用它;压缩和子代理相关测试会直接调用它来控制线程血缘信息。

调用图:调用 1 个内部函数(sample_thread_with_metadata);被 2 处调用(compaction_event_ingests_custom_fact, sample_thread_resume_response);外部调用 3 个(ThreadResume, new, test_path_buf)。

sample_turn_start_request287–306 ↗
fn sample_turn_start_request(thread_id: &str, request_id: i64) -> ClientRequest

作用:造一个“开始一轮对话”的假客户端请求。里面同时放文字和图片,用来测试图片数量等字段。

数据流:输入线程编号和请求编号 → 生成带文本 hello 和一张网络图片的 TurnStart 请求 → 返回 ClientRequest。

调用关系:回合生命周期相关准备函数和若干错误测试会调用它,让 reducer 记录一个待开始的回合请求。

调用图:被 3 处调用(ingest_turn_prerequisites, subagent_events_use_inherited_connection_unless_turn_connection_is_explicit, turn_start_error_response_discards_pending_start_request);外部调用 3 个(default, Integer, vec!)。

sample_turn_start_response308–321 ↗
fn sample_turn_start_response(turn_id: &str) -> ClientResponsePayload

作用:造一个“回合开始成功”的假响应。它告诉测试里的 reducer:请求对应的 turn_id 已经产生。

数据流:输入回合编号 → 构造一个状态为进行中的 Turn → 返回 ClientResponsePayload::TurnStart。

调用关系:ingest_turn_prerequisites 和若干请求匹配测试会用它,把之前的开始请求和真正的回合编号连起来。

调用图:被 4 处调用(ingest_turn_prerequisites, subagent_events_use_inherited_connection_unless_turn_connection_is_explicit, turn_start_error_response_discards_pending_start_request, unrelated_client_requests_are_ignored_by_reducer);外部调用 2 个(TurnStart, vec!)。

sample_turn_started_notification323–337 ↗
fn sample_turn_started_notification(thread_id: &str, turn_id: &str) -> ServerNotification

作用:造一个“回合已经开始”的服务端通知,并带上开始时间。测试用它检查 started_at 字段。

数据流:输入线程编号和回合编号 → 包装一个进行中的 Turn,started_at 固定为 455 → 返回 ServerNotification::TurnStarted。

调用关系:回合准备、工具项生命周期和子代理工具项测试会调用它,让 reducer 知道回合进入运行状态。

调用图:被 4 处调用(ingest_completed_command_execution_item, ingest_turn_prerequisites, item_lifecycle_notifications_publish_command_execution_event, subagent_tool_items_inherit_parent_connection_metadata);外部调用 2 个(TurnStarted, vec!)。

sample_turn_token_usage_fact339–351 ↗
fn sample_turn_token_usage_fact(thread_id: &str, turn_id: &str) -> TurnTokenUsageFact

作用:造一份固定的 token 用量记录。token 可以理解成模型读写文字的计费/统计单位。

数据流:输入线程编号和回合编号 → 填入输入、缓存输入、输出、推理输出、总 token 数 → 返回 TurnTokenUsageFact。

调用关系:ingest_turn_prerequisites 和子代理继承测试会用它,检查最终回合事件是否带上 token 用量。

调用图:被 2 处调用(ingest_turn_prerequisites, subagent_events_use_inherited_connection_unless_turn_connection_is_explicit)。

sample_turn_completed_notification353–376 ↗
fn sample_turn_completed_notification(
    thread_id: &str,
    turn_id: &str,
    status: AppServerTurnStatus,
    codex_error_info: Option<codex_app_server_protocol::CodexErrorInfo>,
) -> ServerNoti

作用:造一个“回合结束”的服务端通知,可指定成功、失败或中断。它还可以带上 Codex 错误信息。

数据流:输入线程编号、回合编号、结束状态和可选错误 → 构造完成时间、耗时和错误字段 → 返回 ServerNotification::TurnCompleted。

调用关系:大量回合、diff、工具统计、失败场景测试都会调用它;它通常是触发 reducer 输出最终回合事件的最后一步。

调用图:被 12 处调用(accepted_steers_increment_turn_steer_count, ingest_complete_child_turn, item_completed_without_turn_state_does_not_create_turn_state, reducer_emits_accepted_line_fingerprints_once_from_latest_turn_diff_on_completion, reducer_emits_large_accepted_line_aggregates_without_fingerprints, turn_completed_without_started_notification_emits_null_started_at, turn_does_not_emit_without_required_prerequisites, turn_event_counts_completed_tool_items, turn_lifecycle_emits_failed_turn_event, turn_lifecycle_emits_interrupted_turn_event_without_error (+2 more));外部调用 2 个(TurnCompleted, vec!)。

sample_turn_resolved_config378–401 ↗
fn sample_turn_resolved_config(thread_id: &str, turn_id: &str) -> TurnResolvedConfigFact

作用:造一份回合最终使用配置,比如模型、权限、沙箱、审批策略。测试用它模拟系统已经算清楚本轮该怎么运行。

数据流:输入线程编号和回合编号 → 填入固定模型、权限 profile、目录、审批和协作模式等 → 返回 TurnResolvedConfigFact。

调用关系:ingest_turn_prerequisites 和子代理完成测试会把它喂给 reducer;没有这份配置时,有些回合事件不会发布。

调用图:被 3 处调用(ingest_complete_child_turn, ingest_turn_prerequisites, turn_start_error_response_discards_pending_start_request);外部调用 2 个(read_only, from)。

sample_turn_profile403–413 ↗
fn sample_turn_profile() -> TurnProfile

作用:造一份回合耗时分布数据,比如采样花多久、工具阻塞多久。它用来检查性能统计字段。

数据流:没有输入 → 返回固定的采样次数、重试次数和各阶段耗时 → 不改外部状态。

调用关系:ingest_turn_prerequisites 和 ingest_complete_child_turn 会调用它,让最终回合事件包含性能画像。

调用图:被 2 处调用(ingest_complete_child_turn, ingest_turn_prerequisites)。

sample_turn_steer_request415–440 ↗
fn sample_turn_steer_request(
    thread_id: &str,
    expected_turn_id: &str,
    request_id: i64,
) -> ClientRequest

作用:造一个“追加引导当前回合”的请求。steer 可以理解成用户在回合进行中又补一句要求。

数据流:输入线程编号、期望回合编号、请求编号 → 构造含文字 more 和一张本地图片的 TurnSteer 请求 → 返回 ClientRequest。

调用关系:被转向接受、拒绝、计数等测试使用,让 reducer 记录一次待处理的 steer 请求。

调用图:被 3 处调用(accepted_steers_increment_turn_steer_count, accepted_turn_steer_emits_expected_event, ingest_rejected_turn_steer);外部调用 2 个(Integer, vec!)。

sample_turn_steer_response442–446 ↗
fn sample_turn_steer_response(turn_id: &str) -> ClientResponsePayload

作用:造一个“追加引导被接受”的响应。它表示服务端认可这次 steer,并关联到某个回合。

数据流:输入回合编号 → 包装成 TurnSteerResponse → 返回 ClientResponsePayload::TurnSteer。

调用关系:接受 steer 的测试会在 sample_turn_steer_request 后使用它,触发 reducer 输出 steer 事件并增加计数。

调用图:被 2 处调用(accepted_steers_increment_turn_steer_count, accepted_turn_steer_emits_expected_event);外部调用 1 个(TurnSteer)。

no_active_turn_steer_error448–454 ↗
fn no_active_turn_steer_error() -> JSONRPCErrorError

作用:造一个“没有可引导的活跃回合”的 JSON-RPC 错误。JSON-RPC 是一种用 JSON 表达请求和响应的通信格式。

数据流:没有输入 → 填入错误码 -32600 和固定错误文字 → 返回 JSONRPCErrorError。

调用关系:拒绝 steer、无待处理请求、开始回合失败等测试用它模拟服务端报错。

调用图:被 4 处调用(accepted_steers_increment_turn_steer_count, rejected_turn_steer_uses_request_connection_metadata, turn_start_error_response_discards_pending_start_request, turn_steer_does_not_emit_without_pending_request)。

no_active_turn_steer_error_type456–458 ↗
fn no_active_turn_steer_error_type() -> AnalyticsJsonRpcError

作用:造一个分析系统内部识别的“没有活跃回合”错误类型。它比原始错误文字更适合统计。

数据流:没有输入 → 包装成 AnalyticsJsonRpcError::TurnSteer(NoActiveTurn) → 返回错误分类。

调用关系:通常和 no_active_turn_steer_error 配对使用,测试 reducer 是否把拒绝原因写成 no_active_turn。

调用图:被 3 处调用(accepted_steers_increment_turn_steer_count, rejected_turn_steer_uses_request_connection_metadata, turn_steer_does_not_emit_without_pending_request);外部调用 1 个(TurnSteer)。

non_steerable_review_error460–475 ↗
fn non_steerable_review_error() -> JSONRPCErrorError

作用:造一个“评审回合不能被 steer”的服务端错误。它用于测试特殊错误能否被正确归类。

数据流:没有输入 → 构造带 ActiveTurnNotSteerable 细节的 JSON-RPC 错误,并把细节序列化进 data → 返回错误对象。

调用关系:rejected_turn_steer_maps_active_turn_not_steerable_error_type 调用它,和对应内部错误类型一起验证映射结果。

调用图:被 1 处调用(rejected_turn_steer_maps_active_turn_not_steerable_error_type);外部调用 1 个(to_value)。

non_steerable_review_error_type477–479 ↗
fn non_steerable_review_error_type() -> AnalyticsJsonRpcError

作用:造一个内部错误分类,表示“评审回合不可引导”。

数据流:没有输入 → 返回 AnalyticsJsonRpcError::TurnSteer(NonSteerableReview) → 不改外部状态。

调用关系:和 non_steerable_review_error 配合,测试拒绝 steer 的 rejection_reason 是否是 non_steerable_review。

调用图:被 1 处调用(rejected_turn_steer_maps_active_turn_not_steerable_error_type);外部调用 1 个(TurnSteer)。

input_too_large_steer_error481–491 ↗
fn input_too_large_steer_error() -> JSONRPCErrorError

作用:造一个“输入太长”的 steer 错误。它模拟用户补充内容超过服务端限制。

数据流:没有输入 → 构造错误码、错误文字和包含 actual/max 字段的 JSON data → 返回 JSONRPCErrorError。

调用关系:输入过大映射测试会调用它,检查 reducer 是否能把这类错误写成 input_too_large。

调用图:被 1 处调用(rejected_turn_steer_maps_input_too_large_error_type);外部调用 1 个(json!)。

input_too_large_error_type493–495 ↗
fn input_too_large_error_type() -> AnalyticsJsonRpcError

作用:造一个内部错误分类,表示输入太大。它让测试不用依赖错误文字猜原因。

数据流:没有输入 → 返回 AnalyticsJsonRpcError::Input(InputError::TooLarge) → 不改外部状态。

调用关系:和 input_too_large_steer_error 配对使用,验证拒绝原因字段。

调用图:被 1 处调用(rejected_turn_steer_maps_input_too_large_error_type);外部调用 1 个(Input)。

ingest_rejected_turn_steer497–566 ↗
async fn ingest_rejected_turn_steer(
    reducer: &mut AnalyticsReducer,
    out: &mut Vec<TrackEventRequest>,
    error: JSONRPCErrorError,
    error_type: Option<AnalyticsJsonRpcError>,
) -> serde_j

作用:把“steer 被拒绝”的完整前置流程跑一遍,最后返回生成的事件 JSON。它减少多个拒绝场景测试里的重复代码。

数据流:输入 reducer、输出事件数组、错误对象和可选错误分类 → 先准备线程和回合,再发起 steer 请求,最后喂入错误响应 → 断言只产生一个事件,并返回这个事件的 JSON 值;会改动 reducer 状态和 out。

调用关系:三个拒绝 steer 测试调用它;它内部使用 ingest_turn_prerequisites、sample_runtime_metadata、sample_thread_resume_response、sample_turn_steer_request 等帮手。

调用图:调用 5 个内部函数(ingest_turn_prerequisites, sample_runtime_metadata, sample_thread_resume_response, sample_turn_steer_request, ingest);被 3 处调用(rejected_turn_steer_maps_active_turn_not_steerable_error_type, rejected_turn_steer_maps_input_too_large_error_type, rejected_turn_steer_uses_request_connection_metadata);外部调用 4 个(new, Integer, assert_eq!, to_value)。

ingest_initialize568–588 ↗
async fn ingest_initialize(reducer: &mut AnalyticsReducer, out: &mut Vec<TrackEventRequest>)

作用:向 reducer 喂一条固定的初始化事实。初始化告诉分析系统当前连接来自哪个客户端、运行在哪种环境。

数据流:输入 reducer 和事件数组 → 构造 Initialize fact 并调用 reducer.ingest → 更新 reducer 的客户端缓存,通常不直接输出事件。

调用关系:ingest_turn_prerequisites、无关响应测试、开始回合失败测试都会先调用它。

调用图:调用 2 个内部函数(sample_runtime_metadata, ingest);被 3 处调用(ingest_turn_prerequisites, turn_start_error_response_discards_pending_start_request, unrelated_client_responses_are_ignored_by_reducer)。

ingest_turn_prerequisites590–680 ↗
async fn ingest_turn_prerequisites(
    reducer: &mut AnalyticsReducer,
    out: &mut Vec<TrackEventRequest>,
    include_initialize: bool,
    include_resolved_config: bool,
    include_started: bool

作用:按需喂入一个回合事件发布前需要的材料。它像搭舞台:线程、回合、配置、开始通知、token、性能数据都可以选择放进去。

数据流:输入 reducer、事件数组和四个开关 → 根据开关依次喂初始化、线程开始、回合开始、配置、开始通知、token 用量和 profile → 改变 reducer 内部状态,可能清空或追加事件。

调用关系:大量回合相关测试都调用它;它集中调用多个 sample_* 函数,避免每个测试重复准备流程。

调用图:调用 9 个内部函数(ingest_initialize, sample_thread_start_response, sample_turn_profile, sample_turn_resolved_config, sample_turn_start_request, sample_turn_start_response, sample_turn_started_notification, sample_turn_token_usage_fact, ingest);被 11 处调用(accepted_steers_increment_turn_steer_count, accepted_turn_steer_emits_expected_event, ingest_rejected_turn_steer, reducer_emits_accepted_line_fingerprints_once_from_latest_turn_diff_on_completion, reducer_emits_large_accepted_line_aggregates_without_fingerprints, turn_completed_without_started_notification_emits_null_started_at, turn_does_not_emit_without_required_prerequisites, turn_event_counts_completed_tool_items, turn_lifecycle_emits_failed_turn_event, turn_lifecycle_emits_interrupted_turn_event_without_error (+1 more));外部调用 7 个(new, Custom, Notification, TurnProfile, TurnResolvedConfig, TurnTokenUsage, Integer)。

ingest_review_prerequisites682–702 ↗
async fn ingest_review_prerequisites(
    reducer: &mut AnalyticsReducer,
    events: &mut Vec<TrackEventRequest>,
)

作用:准备审批/评审类测试需要的基础状态。先让 reducer 知道客户端和线程存在。

数据流:输入 reducer 和事件数组 → 喂初始化事实和线程开始响应 → 清空准备阶段产生的事件,留下干净状态给后续测试。

调用关系:命令审批、权限审批、Guardian 评审、工具项汇总等测试都会先调用它。

调用图:调用 3 个内部函数(sample_initialize_fact, sample_thread_start_response, ingest);被 9 处调用(aborted_server_request_publishes_aborted_user_review_event_once, command_execution_approval_response_publishes_user_review_event, effective_session_permissions_response_publishes_session_user_review_event, guardian_completed_notification_publishes_review_event_with_thread_metadata, item_lifecycle_notifications_publish_command_execution_event, item_review_summaries_do_not_cross_threads_with_reused_item_ids, permissions_reviews_emit_events_without_denormalizing_onto_tool_items, subagent_tool_items_inherit_parent_connection_metadata, terminal_reviews_denormalize_counts_onto_tool_item_events);外部调用 2 个(new, Integer)。

ingest_completed_command_execution_item704–754 ↗
async fn ingest_completed_command_execution_item(
    reducer: &mut AnalyticsReducer,
    events: &mut Vec<TrackEventRequest>,
    thread_id: &str,
    item_id: &str,
)

作用:模拟一个命令工具项从开始到完成。测试用它检查完成后的工具事件和审批统计。

数据流:输入 reducer、事件数组、线程编号、工具项编号 → 依次喂回合开始、工具项开始、工具项完成 → reducer 可能输出命令执行事件。

调用关系:权限不污染工具项、终态评审汇总、跨线程 item_id 等测试调用它;它使用 sample_turn_started_notification 和 sample_command_execution_item_with_id。

调用图:调用 3 个内部函数(sample_command_execution_item_with_id, sample_turn_started_notification, ingest);被 3 处调用(item_review_summaries_do_not_cross_threads_with_reused_item_ids, permissions_reviews_emit_events_without_denormalizing_onto_tool_items, terminal_reviews_denormalize_counts_onto_tool_item_events);外部调用 4 个(new, ItemCompleted, ItemStarted, Notification)。

sample_initialize_fact756–780 ↗
fn sample_initialize_fact(connection_id: u64) -> AnalyticsFact

作用:造一条固定的初始化事实,带 websocket、Linux 等不同于默认样本的字段。测试用它验证客户端元数据传播。

数据流:输入连接编号 → 填入客户端信息、能力开关、运行时信息、通信方式 → 返回 AnalyticsFact::Initialize。

调用关系:ingest_review_prerequisites 和子代理继承测试用它,作为 reducer 缓存连接信息的来源。

调用图:被 2 处调用(ingest_review_prerequisites, subagent_events_use_inherited_connection_unless_turn_connection_is_explicit)。

ingest_complete_child_turn782–807 ↗
async fn ingest_complete_child_turn(
    reducer: &mut AnalyticsReducer,
    events: &mut Vec<TrackEventRequest>,
    thread_id: &str,
    turn_id: &str,
)

作用:模拟子线程里的一个回合完成。它用于检查子代理事件能否继承父线程的客户端信息。

数据流:输入 reducer、事件数组、线程编号、回合编号 → 喂入回合配置、profile、完成通知 → reducer 可能输出一个 turn event。

调用关系:subagent_events_use_inherited_connection_unless_turn_connection_is_explicit 调用它,用来比较继承连接和显式连接的差别。

调用图:调用 4 个内部函数(sample_turn_completed_notification, sample_turn_profile, sample_turn_resolved_config, ingest);被 1 处调用(subagent_events_use_inherited_connection_unless_turn_connection_is_explicit);外部调用 5 个(new, Custom, Notification, TurnProfile, TurnResolvedConfig)。

sample_command_execution_item809–815 ↗
fn sample_command_execution_item(
    status: CommandExecutionStatus,
    exit_code: Option<i32>,
    duration_ms: Option<i64>,
) -> ThreadItem

作用:造一个默认编号的命令执行工具项。命令固定为 echo hi,方便测试只关注状态和耗时。

数据流:输入命令状态、退出码、耗时 → 转交给 sample_command_execution_item_with_id 并使用 item-1 → 返回 ThreadItem::CommandExecution。

调用关系:工具项生命周期、子代理工具项、无状态 item 完成等测试会用它;带自定义动作的函数也以它为基础。

调用图:调用 1 个内部函数(sample_command_execution_item_with_id);被 4 处调用(item_completed_without_turn_state_does_not_create_turn_state, item_lifecycle_notifications_publish_command_execution_event, sample_command_execution_item_with_actions, subagent_tool_items_inherit_parent_connection_metadata)。

sample_command_execution_item_with_id817–835 ↗
fn sample_command_execution_item_with_id(
    id: &str,
    status: CommandExecutionStatus,
    exit_code: Option<i32>,
    duration_ms: Option<i64>,
) -> ThreadItem

作用:造一个可指定 item_id 的命令执行工具项。它让测试能模拟不同工具项或重复编号。

数据流:输入 item_id、状态、退出码、耗时 → 填入命令、目录、进程号、来源和状态 → 返回 ThreadItem::CommandExecution。

调用关系:ingest_completed_command_execution_item 和 sample_command_execution_item 会调用它。

调用图:被 2 处调用(ingest_completed_command_execution_item, sample_command_execution_item);外部调用 2 个(new, test_path_buf)。

sample_command_execution_item_with_actions837–853 ↗
fn sample_command_execution_item_with_actions(
    status: CommandExecutionStatus,
    exit_code: Option<i32>,
    duration_ms: Option<i64>,
    command_actions: Vec<CommandAction>,
) -> ThreadItem

作用:造一个带命令动作分类的命令工具项,比如读文件、列目录、搜索。测试用它检查动作计数字段。

数据流:输入状态、退出码、耗时、动作列表 → 先造普通命令项,再把 command_actions 替换成输入列表 → 返回带动作的 ThreadItem。

调用关系:item_lifecycle_notifications_publish_command_execution_event 调用它,验证 read/list/search/unknown 数量是否统计正确。

调用图:调用 1 个内部函数(sample_command_execution_item);被 1 处调用(item_lifecycle_notifications_publish_command_execution_event);外部调用 1 个(unreachable!)。

sample_command_approval_request855–875 ↗
fn sample_command_approval_request(request_id: i64, approval_id: Option<&str>) -> ServerRequest

作用:造一个命令执行需要用户批准的服务端请求。它模拟系统问用户“能不能运行这个命令”。

数据流:输入请求编号和可选 approval_id → 填入线程、回合、工具项、开始时间、命令等字段 → 返回 ServerRequest。

调用关系:命令审批、终态评审、请求中止、跨线程汇总测试都会调用它。

调用图:被 4 处调用(aborted_server_request_publishes_aborted_user_review_event_once, command_execution_approval_response_publishes_user_review_event, item_review_summaries_do_not_cross_threads_with_reused_item_ids, terminal_reviews_denormalize_counts_onto_tool_item_events);外部调用 1 个(Integer)。

sample_command_approval_response877–885 ↗
fn sample_command_approval_response(
    request_id: i64,
    decision: CommandExecutionApprovalDecision,
) -> ServerResponse

作用:造一个用户对命令审批请求的响应,比如接受或本会话接受。测试用它触发用户评审事件。

数据流:输入请求编号和决策 → 构造对应的 ServerResponse → 返回审批响应。

调用关系:它通常跟 sample_command_approval_request 成对出现,用来测试 reducer 如何把请求和响应配对成 review event。

调用图:被 4 处调用(aborted_server_request_publishes_aborted_user_review_event_once, command_execution_approval_response_publishes_user_review_event, item_review_summaries_do_not_cross_threads_with_reused_item_ids, terminal_reviews_denormalize_counts_onto_tool_item_events);外部调用 1 个(Integer)。

sample_permissions_approval_request887–906 ↗
fn sample_permissions_approval_request(request_id: i64) -> ServerRequest

作用:造一个权限提升审批请求,比如请求开启网络。它用于测试权限类评审事件。

数据流:输入请求编号 → 填入线程、回合、权限项、目录、原因和请求的网络权限 → 返回 ServerRequest::PermissionsRequestApproval。

调用关系:权限审批相关两个测试调用它,随后用 effective permissions 响应验证批准或拒绝结果。

调用图:被 2 处调用(effective_session_permissions_response_publishes_session_user_review_event, permissions_reviews_emit_events_without_denormalizing_onto_tool_items);外部调用 2 个(Integer, test_path_buf)。

sample_effective_permissions_approval_response908–917 ↗
fn sample_effective_permissions_approval_response(
    permissions: CoreRequestPermissionProfile,
    scope: CorePermissionGrantScope,
) -> CoreRequestPermissionsResponse

作用:造一个权限审批的最终生效结果。它说明用户给了什么权限,以及只给本回合还是整个会话。

数据流:输入权限 profile 和授权范围 → 组装 CoreRequestPermissionsResponse,strict_auto_review 固定为 false → 返回响应对象。

调用关系:权限评审测试用它来触发 reducer 输出 approved、denied、session_approval 等结果。

调用图:被 2 处调用(effective_session_permissions_response_publishes_session_user_review_event, permissions_reviews_emit_events_without_denormalizing_onto_tool_items)。

sample_guardian_review_completed919–946 ↗
fn sample_guardian_review_completed(
    review_id: &str,
    target_item_id: Option<&str>,
    status: GuardianApprovalReviewStatus,
) -> ServerNotification

作用:造一个 Guardian 自动评审完成通知。Guardian 可以理解成自动安全审查员。

数据流:输入评审编号、目标工具项、评审状态 → 填入线程、回合、时间、动作、命令和决策来源 → 返回 ServerNotification。

调用关系:guardian_completed_notification_publishes_review_event_with_thread_metadata 调用它,检查自动评审事件是否带上线程元数据。

调用图:被 1 处调用(guardian_completed_notification_publishes_review_event_with_thread_metadata);外部调用 2 个(ItemGuardianApprovalReviewCompleted, test_path_buf)。

expected_absolute_path948–953 ↗
fn expected_absolute_path(path: &PathBuf) -> String

作用:把路径转成测试期望的绝对路径字符串,并统一斜杠格式。这样不同系统上的路径比较更稳定。

数据流:输入 PathBuf → 尝试 canonicalize 成真实绝对路径,失败就用原路径,再把反斜杠换成斜杠 → 返回字符串。

调用关系:几个 normalize_path_for_skill_id 测试调用它,用来生成用户级、管理员级或不在仓库内路径的期望值。

调用图:被 3 处调用(normalize_path_for_skill_id_admin_scoped_uses_absolute_path, normalize_path_for_skill_id_repo_root_not_in_skill_path_uses_absolute_path, normalize_path_for_skill_id_user_scoped_uses_absolute_path);外部调用 1 个(canonicalize)。

normalize_path_for_skill_id_repo_scoped_uses_relative_path956–967 ↗
fn normalize_path_for_skill_id_repo_scoped_uses_relative_path()

作用:测试仓库内技能文件生成技能 ID 时使用相对路径。这样同一个仓库换机器位置也能得到稳定 ID。

数据流:准备 repo_root 和仓库内 skill_path → 调用 normalize_path_for_skill_id → 断言结果是 .codex/skills/doc/SKILL.md。

调用关系:由测试框架运行;它直接检查 reducer 模块里的 normalize_path_for_skill_id。

调用图:调用 1 个内部函数(normalize_path_for_skill_id);外部调用 2 个(from, assert_eq!)。

normalize_path_for_skill_id_user_scoped_uses_absolute_path970–981 ↗
fn normalize_path_for_skill_id_user_scoped_uses_absolute_path()

作用:测试用户级技能没有仓库上下文时使用绝对路径。这样不同本地技能不会混在一起。

数据流:准备用户目录下的 skill_path → 调用 normalize_path_for_skill_id,并用 expected_absolute_path 算期望值 → 比较二者相等。

调用关系:由测试框架运行;它依赖 expected_absolute_path 来适配运行环境。

调用图:调用 2 个内部函数(expected_absolute_path, normalize_path_for_skill_id);外部调用 2 个(from, assert_eq!)。

normalize_path_for_skill_id_admin_scoped_uses_absolute_path984–995 ↗
fn normalize_path_for_skill_id_admin_scoped_uses_absolute_path()

作用:测试管理员级技能同样使用绝对路径。它避免系统级技能 ID 被错误地当作仓库内路径。

数据流:准备 /etc 下的技能路径 → 调用 normalize_path_for_skill_id → 与 expected_absolute_path 的结果比较。

调用关系:由测试框架运行;关注技能 ID 路径归一化规则。

调用图:调用 2 个内部函数(expected_absolute_path, normalize_path_for_skill_id);外部调用 2 个(from, assert_eq!)。

normalize_path_for_skill_id_repo_root_not_in_skill_path_uses_absolute_path998–1010 ↗
fn normalize_path_for_skill_id_repo_root_not_in_skill_path_uses_absolute_path()

作用:测试技能路径不在仓库根目录里时不能硬算相对路径。否则会把无关文件错误归到仓库里。

数据流:准备 repo_root 和另一个目录下的 skill_path → 调用 normalize_path_for_skill_id → 断言返回绝对路径字符串。

调用关系:由测试框架运行;它用 expected_absolute_path 生成期望结果。

调用图:调用 2 个内部函数(expected_absolute_path, normalize_path_for_skill_id);外部调用 2 个(from, assert_eq!)。

app_mentioned_event_serializes_expected_shape1013–1048 ↗
fn app_mentioned_event_serializes_expected_shape()

作用:测试“应用被提到”事件序列化后的 JSON 字段。比如用户明确提到 Calendar 时,埋点要能看懂。

数据流:准备 tracking 和 AppInvocation → 调用 codex_app_metadata 构造事件,再转 JSON → 和固定 JSON 比较。

调用关系:由测试框架运行;它直接验证事件结构,不经过 reducer。

调用图:调用 1 个内部函数(codex_app_metadata);外部调用 3 个(AppMentioned, assert_eq!, to_value)。

app_used_event_serializes_expected_shape1051–1086 ↗
fn app_used_event_serializes_expected_shape()

作用:测试“应用被使用”事件的 JSON 长相。它确保 connector、应用名、调用方式等字段不会变。

数据流:准备 tracking 和 Drive 调用信息 → 构造 TrackEventRequest::AppUsed 并序列化 → 和期望 JSON 比较。

调用关系:由测试框架运行;它调用 codex_app_metadata 来生成事件参数。

调用图:调用 1 个内部函数(codex_app_metadata);外部调用 3 个(AppUsed, assert_eq!, to_value)。

accepted_line_fingerprints_event_serializes_expected_shape1089–1128 ↗
fn accepted_line_fingerprints_event_serializes_expected_shape()

作用:测试“接受的代码行指纹”事件的 JSON 格式。这个事件用于统计用户接受了多少新增/删除代码行。

数据流:手动构造 AcceptedLineFingerprints 事件 → 序列化为 JSON → 断言字段和值完全符合预期。

调用关系:由测试框架运行;它直接验证事件类型的序列化。

调用图:外部调用 5 个(new, new, AcceptedLineFingerprints, assert_eq!, to_value)。

reducer_emits_large_accepted_line_aggregates_without_fingerprints1131–1199 ↗
async fn reducer_emits_large_accepted_line_aggregates_without_fingerprints()

作用:测试超大 diff 完成时只上报汇总数量,不带庞大的行指纹列表。这样可以防止事件太大。

数据流:准备完整回合状态 → 构造 20000 行新增 diff 喂给 reducer → 回合完成后检查只产生一个 accepted line 事件,新增数正确且指纹为空。

调用关系:由异步测试框架运行;它先调用 ingest_turn_prerequisites,再用 sample_turn_completed_notification 触发发布。

调用图:调用 2 个内部函数(ingest_turn_prerequisites, sample_turn_completed_notification);外部调用 8 个(new, TurnDiffUpdated, new, Notification, default, assert!, assert_eq!, format!)。

reducer_emits_accepted_line_fingerprints_once_from_latest_turn_diff_on_completion1202–1266 ↗
async fn reducer_emits_accepted_line_fingerprints_once_from_latest_turn_diff_on_completion()

作用:测试多次 diff 更新时,完成回合只按最后一次 diff 发一次事件。避免旧 diff 和新 diff 重复统计。

数据流:准备回合 → 先后喂入两个 diff 更新 → 回合完成后检查 accepted line 事件只有一个,且来自最新 diff 的汇总。

调用关系:由异步测试框架运行;它依赖 ingest_turn_prerequisites 和 sample_turn_completed_notification。

调用图:调用 2 个内部函数(ingest_turn_prerequisites, sample_turn_completed_notification);外部调用 8 个(new, TurnDiffUpdated, new, Notification, default, assert!, assert_eq!, format!)。

compaction_event_serializes_expected_shape1269–1347 ↗
fn compaction_event_serializes_expected_shape()

作用:测试上下文压缩事件的 JSON 格式。上下文压缩就是把过长对话缩短,保留关键内容。

数据流:构造 CodexCompactionEvent 和客户端/运行时元数据 → 调用 codex_compaction_event_params 生成事件 → 序列化并比较完整 JSON。

调用关系:由测试框架运行;它使用 sample_app_server_client_metadata 和 sample_runtime_metadata。

调用图:调用 3 个内部函数(sample_app_server_client_metadata, sample_runtime_metadata, codex_compaction_event_params);外部调用 4 个(new, Compaction, assert_eq!, to_value)。

compaction_implementation_serializes_remote_v21350–1355 ↗
fn compaction_implementation_serializes_remote_v2()

作用:测试一种压缩实现枚举会被序列化成指定字符串。后台统计依赖这个字符串稳定不变。

数据流:输入固定枚举 ResponsesCompactionV2 → 转成 JSON → 断言结果是 responses_compaction_v2。

调用关系:由测试框架运行;它直接验证枚举序列化。

调用图:外部调用 2 个(assert_eq!, to_value)。

app_used_dedupe_is_keyed_by_turn_and_connector1358–1385 ↗
fn app_used_dedupe_is_keyed_by_turn_and_connector()

作用:测试应用使用事件的去重规则:同一回合、同一 connector 只发一次,不同回合可以再发。

数据流:创建 AnalyticsEventsQueue 和同一个应用调用 → 对 turn-1 调两次,对 turn-2 调一次 → 检查结果是 true、false、true。

调用关系:由测试框架运行;它直接调用队列的 should_enqueue_app_used。

调用图:外部调用 5 个(new, new, new, assert_eq!, channel)。

thread_initialized_event_serializes_expected_shape1388–1451 ↗
fn thread_initialized_event_serializes_expected_shape()

作用:测试线程初始化事件的 JSON 格式。线程初始化是分析系统认识一次会话的起点。

数据流:手动构造 ThreadInitializedEvent → 序列化 JSON → 和包含客户端、运行时、模型、来源等字段的期望值比较。

调用关系:由测试框架运行;不经过 reducer,只检查事件结构本身。

调用图:外部调用 4 个(ThreadInitialized, Feature, assert_eq!, to_value)。

command_execution_event_serializes_expected_shape1454–1550 ↗
fn command_execution_event_serializes_expected_shape()

作用:测试命令执行事件的 JSON 格式。它确保命令来源、退出码、动作统计、审批结果等字段稳定。

数据流:手动构造 CommandExecution 事件 → 转为 JSON → 与期望 JSON 完整比较。

调用关系:由测试框架运行;它直接验证 CodexCommandExecutionEventRequest 的序列化。

调用图:外部调用 3 个(CommandExecution, assert_eq!, to_value)。

review_event_serializes_expected_shape1553–1627 ↗
fn review_event_serializes_expected_shape()

作用:测试评审事件的 JSON 格式。评审可能来自用户或自动审查员,用来记录谁批准了什么。

数据流:手动构造 ReviewEvent → 序列化 → 检查线程、评审人、触发原因、结果、耗时等字段。

调用关系:由测试框架运行;它直接覆盖 CodexReviewEventRequest 的输出形状。

调用图:外部调用 3 个(ReviewEvent, assert_eq!, to_value)。

initialize_caches_client_and_thread_lifecycle_publishes_once_initialized1629–1729 ↗
async fn initialize_caches_client_and_thread_lifecycle_publishes_once_initialized()

作用:测试 reducer 只有拿到客户端初始化信息后,才会发布线程初始化事件。这样事件不会缺客户端身份。

数据流:先喂线程响应但不初始化,确认无事件 → 再喂初始化,仍无事件 → 再喂恢复线程响应,检查发布一个完整线程事件。

调用关系:由异步测试框架运行;它调用 sample_thread_start_response 和 sample_thread_resume_response 来模拟线程生命周期。

调用图:调用 2 个内部函数(sample_thread_resume_response, sample_thread_start_response);外部调用 7 个(new, new, default, Integer, assert!, assert_eq!, to_value)。

unrelated_client_requests_are_ignored_by_reducer1732–1766 ↗
async fn unrelated_client_requests_are_ignored_by_reducer()

作用:测试无关客户端请求不会被误当成回合开始请求。否则后续响应可能被错误配对。

数据流:喂入 ThreadArchive 请求,再喂入 TurnStart 响应 → 检查没有事件产生 → reducer 不应创建待处理回合状态。

调用关系:由异步测试框架运行;它用 sample_turn_start_response 验证错误配对不会发生。

调用图:调用 1 个内部函数(sample_turn_start_response);外部调用 5 个(new, new, default, Integer, assert!)。

unrelated_client_responses_are_ignored_by_reducer1769–1788 ↗
async fn unrelated_client_responses_are_ignored_by_reducer()

作用:测试无关客户端响应不会产生分析事件。比如归档线程响应不该触发埋点。

数据流:先初始化 reducer → 喂入 ThreadArchive 响应 → 断言事件数组为空。

调用关系:由异步测试框架运行;它调用 ingest_initialize 准备客户端信息。

调用图:调用 1 个内部函数(ingest_initialize);外部调用 6 个(new, ThreadArchive, new, default, Integer, assert!)。

compaction_event_ingests_custom_fact1791–1919 ↗
async fn compaction_event_ingests_custom_fact()

作用:测试 reducer 收到自定义压缩事实后能发布压缩事件,并带上线程、子代理和错误信息。

数据流:先初始化并恢复一个子代理线程 → 清空准备事件 → 喂入 Compaction fact → 检查输出的 compaction JSON 字段。

调用关系:由异步测试框架运行;它调用 sample_thread_resume_response_with_source 和 sample_runtime_metadata。

调用图:调用 3 个内部函数(sample_runtime_metadata, sample_thread_resume_response_with_source, from_string);外部调用 9 个(SubAgent, new, new, Custom, Compaction, default, Integer, assert_eq!, to_value)。

guardian_review_event_ingests_custom_fact_with_optional_target_item1922–2081 ↗
async fn guardian_review_event_ingests_custom_fact_with_optional_target_item()

作用:测试自定义 Guardian 评审事实可以发布事件,即使没有目标工具项也能正确写 null。

数据流:先初始化并创建线程 → 喂入 GuardianReview fact → 检查 session、reviewed_action、超时、模型配置等字段。

调用关系:由异步测试框架运行;它调用 sample_thread_start_response 和 sample_runtime_metadata。

调用图:调用 2 个内部函数(sample_runtime_metadata, sample_thread_start_response);外部调用 9 个(new, new, Custom, GuardianReview, default, Integer, assert!, assert_eq!, to_value)。

item_lifecycle_notifications_publish_command_execution_event2084–2197 ↗
async fn item_lifecycle_notifications_publish_command_execution_event()

作用:测试命令工具项只有完成时才发布命令执行事件,并正确统计命令动作。

数据流:准备评审前置状态和回合开始 → 喂 ItemStarted,确认无事件 → 喂带动作的 ItemCompleted → 检查输出命令事件字段。

调用关系:由异步测试框架运行;它调用 ingest_review_prerequisites、sample_turn_started_notification、sample_command_execution_item_with_actions。

调用图:调用 4 个内部函数(ingest_review_prerequisites, sample_command_execution_item, sample_command_execution_item_with_actions, sample_turn_started_notification);外部调用 10 个(new, ItemCompleted, ItemStarted, new, Notification, default, assert!, assert_eq!, to_value, vec!)。

command_execution_approval_response_publishes_user_review_event2200–2253 ↗
async fn command_execution_approval_response_publishes_user_review_event()

作用:测试用户回复命令审批后会生成用户评审事件。它确认批准时间、耗时和状态被记录。

数据流:准备线程 → 喂命令审批请求,确认暂不发布 → 喂接受响应 → 检查产生 codex_review_event。

调用关系:由异步测试框架运行;它使用 sample_command_approval_request 和 sample_command_approval_response 配对。

调用图:调用 3 个内部函数(ingest_review_prerequisites, sample_command_approval_request, sample_command_approval_response);外部调用 6 个(new, new, default, assert!, assert_eq!, to_value)。

permissions_reviews_emit_events_without_denormalizing_onto_tool_items2256–2304 ↗
async fn permissions_reviews_emit_events_without_denormalizing_onto_tool_items()

作用:测试权限审批会单独发评审事件,但不会错误地算到同名工具项的审批数量里。

数据流:准备线程 → 喂权限请求和最终拒绝响应 → 检查权限 review event → 再完成一个 item_id 相同的命令项,确认 review_count 仍为 0。

调用关系:由异步测试框架运行;它调用 ingest_completed_command_execution_item 来验证工具项汇总不被污染。

调用图:调用 4 个内部函数(ingest_completed_command_execution_item, ingest_review_prerequisites, sample_effective_permissions_approval_response, sample_permissions_approval_request);外部调用 8 个(new, default, new, default, Integer, assert!, assert_eq!, to_value)。

effective_session_permissions_response_publishes_session_user_review_event2307–2349 ↗
async fn effective_session_permissions_response_publishes_session_user_review_event()

作用:测试用户把权限批准到整个会话时,评审事件的 resolution 会写成 session_approval。

数据流:准备线程 → 喂权限请求 → 喂带网络权限且范围为 Session 的响应 → 检查 review event 是 approved 和 session_approval。

调用关系:由异步测试框架运行;它复用 sample_permissions_approval_request 和 sample_effective_permissions_approval_response。

调用图:调用 3 个内部函数(ingest_review_prerequisites, sample_effective_permissions_approval_response, sample_permissions_approval_request);外部调用 6 个(new, new, default, Integer, assert_eq!, to_value)。

aborted_server_request_publishes_aborted_user_review_event_once2352–2398 ↗
async fn aborted_server_request_publishes_aborted_user_review_event_once()

作用:测试审批请求被中止时只发布一次 aborted 评审事件。后面如果迟到一个响应,不应再发第二个。

数据流:准备线程 → 喂命令审批请求 → 喂请求中止事实并检查 aborted 事件 → 清空后再喂接受响应,确认无事件。

调用关系:由异步测试框架运行;它使用 sample_command_approval_request 和 sample_command_approval_response。

调用图:调用 3 个内部函数(ingest_review_prerequisites, sample_command_approval_request, sample_command_approval_response);外部调用 7 个(new, new, default, Integer, assert!, assert_eq!, to_value)。

guardian_completed_notification_publishes_review_event_with_thread_metadata2401–2428 ↗
async fn guardian_completed_notification_publishes_review_event_with_thread_metadata()

作用:测试 Guardian 完成通知会发布评审事件,并补上线程来源等元数据。

数据流:准备线程 → 喂 Guardian review completed 通知 → 序列化第一个事件并检查 review_id、item_id、reviewer、状态和耗时。

调用关系:由异步测试框架运行;它调用 sample_guardian_review_completed。

调用图:调用 2 个内部函数(ingest_review_prerequisites, sample_guardian_review_completed);外部调用 6 个(new, new, Notification, default, assert_eq!, to_value)。

terminal_reviews_denormalize_counts_onto_tool_item_events2431–2471 ↗
async fn terminal_reviews_denormalize_counts_onto_tool_item_events()

作用:测试终态审批结果会汇总到后续工具项事件上。也就是命令事件里能看到它经过几次评审。

数据流:准备线程 → 喂命令审批请求和会话批准响应 → 清空事件 → 完成命令项 → 检查 review_count 和 final_approval_outcome。

调用关系:由异步测试框架运行;它调用 ingest_completed_command_execution_item 来触发工具项事件。

调用图:调用 4 个内部函数(ingest_completed_command_execution_item, ingest_review_prerequisites, sample_command_approval_request, sample_command_approval_response);外部调用 5 个(new, new, default, assert_eq!, to_value)。

item_review_summaries_do_not_cross_threads_with_reused_item_ids2474–2527 ↗
async fn item_review_summaries_do_not_cross_threads_with_reused_item_ids()

作用:测试不同线程里即使 item_id 相同,审批汇总也不能串线。否则一个线程的审批会污染另一个线程。

数据流:准备两个线程 → 在线程 1 做审批 → 在线程 2 完成同名 item → 检查线程 2 的 review_count 仍为 0。

调用关系:由异步测试框架运行;它用 sample_thread_start_response 建第二个线程,并用 ingest_completed_command_execution_item 完成工具项。

调用图:调用 5 个内部函数(ingest_completed_command_execution_item, ingest_review_prerequisites, sample_command_approval_request, sample_command_approval_response, sample_thread_start_response);外部调用 6 个(new, new, default, Integer, assert_eq!, to_value)。

subagent_thread_started_review_serializes_expected_shape2530–2573 ↗
fn subagent_thread_started_review_serializes_expected_shape()

作用:测试评审型子代理线程启动事件的 JSON。子代理就是主线程派出去做某件事的辅助线程。

数据流:构造 SubAgentThreadStartedInput,source 为 Review → 生成 ThreadInitialized 事件并序列化 → 检查 thread_source、rpc_transport、subagent_source 等字段。

调用关系:由测试框架运行;它调用 subagent_thread_started_event_request。

调用图:调用 1 个内部函数(subagent_thread_started_event_request);外部调用 3 个(ThreadInitialized, assert_eq!, to_value)。

subagent_thread_started_thread_spawn_serializes_thread_lineage2576–2618 ↗
fn subagent_thread_started_thread_spawn_serializes_thread_lineage()

作用:测试通过线程派生创建的子代理会记录父线程和 fork 来源。这样能追踪线程血缘。

数据流:准备父线程 ID 和 fork 来源 ID → 构造 ThreadSpawn 输入 → 序列化事件并检查 parent_thread_id、forked_from_thread_id。

调用关系:由测试框架运行;它调用 subagent_thread_started_event_request 和 from_string 构造合法 ID。

调用图:调用 2 个内部函数(subagent_thread_started_event_request, from_string);外部调用 3 个(ThreadInitialized, assert_eq!, to_value)。

subagent_thread_started_memory_consolidation_serializes_expected_shape2621–2645 ↗
fn subagent_thread_started_memory_consolidation_serializes_expected_shape()

作用:测试记忆整理型子代理的来源字段会写成 memory_consolidation。

数据流:构造 MemoryConsolidation 输入 → 生成并序列化线程初始化事件 → 检查 subagent_source 和 parent_thread_id。

调用关系:由测试框架运行;它直接验证 subagent_thread_started_event_request 的输出。

调用图:调用 1 个内部函数(subagent_thread_started_event_request);外部调用 3 个(ThreadInitialized, assert_eq!, to_value)。

subagent_thread_started_other_serializes_expected_shape2648–2668 ↗
fn subagent_thread_started_other_serializes_expected_shape()

作用:测试自定义来源的子代理会把来源字符串原样写入事件。比如 guardian。

数据流:构造 Other("guardian") 输入 → 生成事件并序列化 → 检查 subagent_source 是 guardian,父线程为空。

调用关系:由测试框架运行;它调用 subagent_thread_started_event_request。

调用图:调用 1 个内部函数(subagent_thread_started_event_request);外部调用 4 个(ThreadInitialized, assert_eq!, Other, to_value)。

subagent_thread_started_other_serializes_explicit_parent_thread_id2671–2697 ↗
fn subagent_thread_started_other_serializes_explicit_parent_thread_id()

作用:测试自定义来源子代理如果显式带父线程 ID,事件里会保留它。

数据流:构造合法父线程 ID 和 Other("guardian") 输入 → 序列化事件 → 检查 parent_thread_id 等于输入值。

调用关系:由测试框架运行;它用 from_string 创建 ID,再调用 subagent_thread_started_event_request。

调用图:调用 2 个内部函数(subagent_thread_started_event_request, from_string);外部调用 4 个(ThreadInitialized, assert_eq!, Other, to_value)。

subagent_thread_started_publishes_without_initialize2700–2734 ↗
async fn subagent_thread_started_publishes_without_initialize()

作用:测试子代理线程启动事实不依赖普通客户端初始化,也能直接发布线程初始化事件。

数据流:新建空 reducer → 喂 SubAgentThreadStarted 自定义事实 → 检查输出一个 codex_thread_initialized 事件。

调用关系:由异步测试框架运行;它直接把 CustomAnalyticsFact::SubAgentThreadStarted 交给 reducer。

调用图:外部调用 6 个(new, Custom, SubAgentThreadStarted, default, assert_eq!, to_value)。

subagent_events_use_inherited_connection_unless_turn_connection_is_explicit2737–2908 ↗
async fn subagent_events_use_inherited_connection_unless_turn_connection_is_explicit()

作用:测试子代理事件默认继承父线程连接信息,但如果子代理回合自己有连接,就用自己的连接。

数据流:先初始化父线程并启动子代理 → 喂压缩事实和子回合完成,检查使用父客户端信息 → 再为子线程显式初始化并开始回合,检查改用新连接信息。

调用关系:由异步测试框架运行;它调用 ingest_complete_child_turn、sample_initialize_fact、sample_turn_start_request、sample_turn_start_response 等。

调用图:调用 8 个内部函数(ingest_complete_child_turn, sample_initialize_fact, sample_runtime_metadata, sample_thread_start_response, sample_turn_start_request, sample_turn_start_response, sample_turn_token_usage_fact, from_string);外部调用 11 个(new, new, Custom, Compaction, SubAgentThreadStarted, TurnTokenUsage, default, Integer, assert_eq!, panic! (+1 more))。

subagent_tool_items_inherit_parent_connection_metadata2911–2992 ↗
async fn subagent_tool_items_inherit_parent_connection_metadata()

作用:测试子代理里的工具项事件会继承父线程的客户端元数据。这样后台能知道这些工具调用属于哪个产品入口。

数据流:准备父线程 → 喂子代理启动事实 → 在子线程里喂回合开始、工具项开始和完成 → 检查命令事件带 subagent 来源和父线程客户端信息。

调用关系:由异步测试框架运行;它调用 ingest_review_prerequisites、sample_turn_started_notification、sample_command_execution_item。

调用图:调用 3 个内部函数(ingest_review_prerequisites, sample_command_execution_item, sample_turn_started_notification);外部调用 10 个(new, ItemCompleted, ItemStarted, new, Custom, Notification, SubAgentThreadStarted, default, assert_eq!, to_value)。

plugin_used_event_serializes_expected_shape2995–3027 ↗
fn plugin_used_event_serializes_expected_shape()

作用:测试插件被使用事件的 JSON 格式。插件信息包括插件 ID、名字、MCP 服务数和连接器列表。

数据流:准备 tracking 和 sample_plugin_metadata → 调用 codex_plugin_used_metadata 构造事件 → 序列化并比较 JSON。

调用关系:由测试框架运行;它依赖 sample_plugin_metadata 提供固定插件资料。

调用图:调用 2 个内部函数(sample_plugin_metadata, codex_plugin_used_metadata);外部调用 3 个(PluginUsed, assert_eq!, to_value)。

plugin_management_event_serializes_expected_shape3030–3053 ↗
fn plugin_management_event_serializes_expected_shape()

作用:测试插件安装类管理事件的 JSON 格式。它确保插件基础信息字段稳定。

数据流:取 sample_plugin_metadata → 调用 codex_plugin_metadata 构造 PluginInstalled 事件 → 序列化后与期望 JSON 比较。

调用关系:由测试框架运行;它直接检查插件管理事件参数生成函数。

调用图:调用 2 个内部函数(sample_plugin_metadata, codex_plugin_metadata);外部调用 3 个(PluginInstalled, assert_eq!, to_value)。

plugin_management_event_can_use_remote_plugin_id_override3056–3072 ↗
fn plugin_management_event_can_use_remote_plugin_id_override()

作用:测试如果插件有远端 ID 覆盖值,事件会优先使用它。这样后台能按远端统一 ID 统计。

数据流:获取样本插件并设置 remote_plugin_id → 构造安装事件并序列化 → 检查 plugin_id 使用远端值,名字和市场不变。

调用关系:由测试框架运行;它基于 sample_plugin_metadata 修改一个字段后调用 codex_plugin_metadata。

调用图:调用 2 个内部函数(sample_plugin_metadata, codex_plugin_metadata);外部调用 3 个(PluginInstalled, assert_eq!, to_value)。

hook_run_event_serializes_expected_shape3075–3109 ↗
fn hook_run_event_serializes_expected_shape()

作用:测试 hook 运行事件的 JSON 格式。hook 是在某些时机自动触发的小脚本或规则。

数据流:准备 tracking 和 HookRunFact → 调用 codex_hook_run_metadata → 构造事件、序列化、比较 JSON。

调用关系:由测试框架运行;它直接验证 hook 事件字段名和值。

调用图:调用 1 个内部函数(codex_hook_run_metadata);外部调用 3 个(HookRun, assert_eq!, to_value)。

hook_run_metadata_maps_sources_and_statuses3112–3164 ↗
fn hook_run_metadata_maps_sources_and_statuses()

作用:测试 hook 来源和状态会映射成正确字符串,比如 system、project、blocked、failed。

数据流:分别构造系统、项目、云要求、未知来源的 HookRunFact → 转成 JSON → 检查 hook_source 和 status 字段。

调用关系:由测试框架运行;它反复调用 codex_hook_run_metadata。

调用图:调用 1 个内部函数(codex_hook_run_metadata);外部调用 2 个(assert_eq!, to_value)。

hook_run_metadata_maps_stopped_status3167–3186 ↗
fn hook_run_metadata_maps_stopped_status()

作用:测试 hook 的 stopped 状态会正确序列化。这个状态表示 hook 被停止而不是成功或失败。

数据流:构造 User 来源、Stop 事件、Stopped 状态的 HookRunFact → 转 JSON → 检查 status 是 stopped。

调用关系:由测试框架运行;它补充覆盖 hook 状态映射中的 stopped 分支。

调用图:调用 1 个内部函数(codex_hook_run_metadata);外部调用 2 个(assert_eq!, to_value)。

plugin_used_dedupe_is_keyed_by_turn_and_plugin3189–3212 ↗
fn plugin_used_dedupe_is_keyed_by_turn_and_plugin()

作用:测试插件使用事件的去重规则:同一回合、同一插件只发一次,不同回合可以再发。

数据流:创建队列和样本插件 → 对同一 turn 调两次 should_enqueue_plugin_used,再对另一个 turn 调一次 → 检查 true、false、true。

调用关系:由测试框架运行;它调用 sample_plugin_metadata 和队列去重方法。

调用图:调用 1 个内部函数(sample_plugin_metadata);外部调用 5 个(new, new, new, assert_eq!, channel)。

reducer_ingests_skill_invoked_fact3215–3266 ↗
async fn reducer_ingests_skill_invoked_fact()

作用:测试 reducer 收到技能调用事实后会发 skill_invocation 事件。技能可以理解成可复用的小能力说明文件。

数据流:准备 tracking、技能路径和预期 skill_id → 喂 SkillInvoked 自定义事实 → 检查输出事件包含技能名、范围、repo、模型等字段。

调用关系:由异步测试框架运行;它调用 skill_id_for_local_skill 计算期望 ID。

调用图:调用 1 个内部函数(skill_id_for_local_skill);外部调用 8 个(from, new, Custom, SkillInvoked, default, assert_eq!, to_value, vec!)。

reducer_includes_plugin_id_for_plugin_skill_invocations3269–3301 ↗
async fn reducer_includes_plugin_id_for_plugin_skill_invocations()

作用:测试插件提供的技能被调用时,事件会带 plugin_id。这样后台能把技能使用归因到插件。

数据流:准备插件缓存路径和带 plugin_id 的 SkillInvocation → 喂给 reducer → 检查输出 event_params.plugin_id。

调用关系:由异步测试框架运行;它直接构造 SkillInvoked fact。

调用图:外部调用 8 个(from, new, Custom, SkillInvoked, default, assert_eq!, to_value, vec!)。

reducer_ingests_hook_run_fact3304–3332 ↗
async fn reducer_ingests_hook_run_fact()

作用:测试 reducer 收到 hook 运行事实后会发 codex_hook_run 事件。

数据流:构造 HookRunInput,来源 Unknown、状态 Failed → 喂给 reducer → 检查输出事件类型、hook 名称、来源和状态。

调用关系:由异步测试框架运行;它走 reducer 的 CustomAnalyticsFact::HookRun 分支。

调用图:外部调用 6 个(new, Custom, HookRun, default, assert_eq!, to_value)。

reducer_ingests_app_and_plugin_facts3335–3385 ↗
async fn reducer_ingests_app_and_plugin_facts()

作用:测试 reducer 能处理应用提到、应用使用、插件使用三类自定义事实。

数据流:准备同一 tracking → 依次喂 AppMentioned、AppUsed、PluginUsed → 检查输出三个事件且类型顺序正确。

调用关系:由异步测试框架运行;它调用 sample_plugin_metadata 提供插件数据。

调用图:调用 1 个内部函数(sample_plugin_metadata);外部调用 9 个(new, Custom, AppMentioned, AppUsed, PluginUsed, default, assert_eq!, to_value, vec!)。

reducer_ingests_plugin_state_changed_fact3388–3420 ↗
async fn reducer_ingests_plugin_state_changed_fact()

作用:测试插件状态改变事实会变成对应管理事件。这里验证 Disabled 会变成 codex_plugin_disabled。

数据流:准备样本插件和 PluginState::Disabled → 喂给 reducer → 检查输出 JSON 的事件类型和插件元数据。

调用关系:由异步测试框架运行;它调用 sample_plugin_metadata。

调用图:调用 1 个内部函数(sample_plugin_metadata);外部调用 6 个(new, Custom, PluginStateChanged, default, assert_eq!, to_value)。

turn_event_serializes_expected_shape3423–3558 ↗
fn turn_event_serializes_expected_shape()

作用:测试完整回合事件的 JSON 格式。回合事件是一次对话运行结束后的总账单。

数据流:手动构造 CodexTurnEventRequest,包含配置、状态、token、耗时等大量字段 → 序列化 → 与期望 JSON 比较。

调用关系:由测试框架运行;它使用 sample_app_server_client_metadata 和 sample_runtime_metadata。

调用图:调用 2 个内部函数(sample_app_server_client_metadata, sample_runtime_metadata);外部调用 4 个(new, TurnEvent, assert_eq!, to_value)。

accepted_turn_steer_emits_expected_event3561–3628 ↗
async fn accepted_turn_steer_emits_expected_event()

作用:测试 steer 请求被接受时会发 codex_turn_steer_event。它记录用户中途补充输入是否成功。

数据流:准备回合前置状态 → 喂 steer 请求和成功响应 → 检查输出一个 accepted 的 steer 事件,包含图片数、线程信息、客户端信息。

调用关系:由异步测试框架运行;它调用 ingest_turn_prerequisites、sample_turn_steer_request、sample_turn_steer_response。

调用图:调用 3 个内部函数(ingest_turn_prerequisites, sample_turn_steer_request, sample_turn_steer_response);外部调用 7 个(new, new, default, Integer, assert!, assert_eq!, to_value)。

rejected_turn_steer_uses_request_connection_metadata3631–3669 ↗
async fn rejected_turn_steer_uses_request_connection_metadata()

作用:测试 steer 被拒绝时,事件使用发起请求那条连接的客户端元数据。

数据流:调用 ingest_rejected_turn_steer 模拟 no active turn 错误 → 检查事件是 rejected,拒绝原因、线程来源和客户端字段正确。

调用关系:由异步测试框架运行;它使用 no_active_turn_steer_error 和 no_active_turn_steer_error_type。

调用图:调用 3 个内部函数(ingest_rejected_turn_steer, no_active_turn_steer_error, no_active_turn_steer_error_type);外部调用 4 个(new, default, assert!, assert_eq!)。

rejected_turn_steer_maps_active_turn_not_steerable_error_type3672–3687 ↗
async fn rejected_turn_steer_maps_active_turn_not_steerable_error_type()

作用:测试“评审回合不可 steer”的错误类型会映射成 non_steerable_review。

数据流:调用 ingest_rejected_turn_steer,传入 non_steerable_review 错误和错误分类 → 检查 rejection_reason。

调用关系:由异步测试框架运行;它依赖 non_steerable_review_error 和 non_steerable_review_error_type。

调用图:调用 3 个内部函数(ingest_rejected_turn_steer, non_steerable_review_error, non_steerable_review_error_type);外部调用 3 个(new, default, assert_eq!)。

rejected_turn_steer_maps_input_too_large_error_type3690–3705 ↗
async fn rejected_turn_steer_maps_input_too_large_error_type()

作用:测试输入过大的 steer 错误会映射成 input_too_large。

数据流:调用 ingest_rejected_turn_steer,传入输入过大错误和分类 → 检查输出事件的 rejection_reason。

调用关系:由异步测试框架运行;它调用 input_too_large_steer_error 和 input_too_large_error_type。

调用图:调用 3 个内部函数(ingest_rejected_turn_steer, input_too_large_error_type, input_too_large_steer_error);外部调用 3 个(new, default, assert_eq!)。

turn_steer_does_not_emit_without_pending_request3708–3725 ↗
async fn turn_steer_does_not_emit_without_pending_request()

作用:测试如果没有先记录 steer 请求,单独收到错误响应不会发事件。这样可以避免乱配对。

数据流:新建 reducer → 直接喂 ErrorResponse → 检查输出为空。

调用关系:由异步测试框架运行;它用 no_active_turn_steer_error 和 no_active_turn_steer_error_type 构造错误。

调用图:调用 2 个内部函数(no_active_turn_steer_error, no_active_turn_steer_error_type);外部调用 4 个(new, default, Integer, assert!)。

turn_start_error_response_discards_pending_start_request3728–3790 ↗
async fn turn_start_error_response_discards_pending_start_request()

作用:测试回合开始请求失败后,pending 状态会被丢弃。迟到的成功响应不能把失败请求“复活”。

数据流:初始化后喂 TurnStart 请求 → 喂错误响应 → 再喂同 request_id 的成功响应、配置和完成通知 → 确认没有事件输出。

调用关系:由异步测试框架运行;它调用 ingest_initialize、sample_turn_start_request、sample_turn_start_response、sample_turn_resolved_config。

调用图:调用 6 个内部函数(ingest_initialize, no_active_turn_steer_error, sample_turn_completed_notification, sample_turn_resolved_config, sample_turn_start_request, sample_turn_start_response);外部调用 8 个(new, new, Custom, Notification, TurnResolvedConfig, default, Integer, assert!)。

turn_lifecycle_emits_turn_event3793–3874 ↗
async fn turn_lifecycle_emits_turn_event()

作用:测试完整正常回合生命周期会输出一个 codex_turn_event。它检查客户端、运行时、状态、计数、token 等总账字段。

数据流:准备初始化、线程、回合配置、开始通知、token、profile → 喂完成通知 → 检查输出事件所有关键字段。

调用关系:由异步测试框架运行;它用 ingest_turn_prerequisites 搭好状态,再用 sample_turn_completed_notification 触发。

调用图:调用 2 个内部函数(ingest_turn_prerequisites, sample_turn_completed_notification);外部调用 7 个(new, new, Notification, default, assert!, assert_eq!, to_value)。

turn_event_counts_completed_tool_items3877–4017 ↗
async fn turn_event_counts_completed_tool_items()

作用:测试回合事件会统计已完成的各种工具项数量,比如 shell、文件修改、MCP、子代理、网页搜索、图片生成。

数据流:准备回合 → 喂一个进行中的 MCP item,再喂多种完成 item → 检查 MCP 单项事件的 plugin_id → 完成回合后检查总工具计数。

调用关系:由异步测试框架运行;它调用 ingest_turn_prerequisites 和 sample_turn_completed_notification。

调用图:调用 2 个内部函数(ingest_turn_prerequisites, sample_turn_completed_notification);外部调用 9 个(new, ItemCompleted, ItemStarted, new, Notification, default, assert_eq!, to_value, vec!)。

item_completed_without_turn_state_does_not_create_turn_state4020–4055 ↗
async fn item_completed_without_turn_state_does_not_create_turn_state()

作用:测试单独收到工具项完成通知,不会凭空创建回合状态。否则后续完成回合可能误发事件。

数据流:新建 reducer → 喂 ItemCompleted → 再喂 TurnCompleted → 检查事件数组仍为空。

调用关系:由异步测试框架运行;它调用 sample_command_execution_item 和 sample_turn_completed_notification。

调用图:调用 2 个内部函数(sample_command_execution_item, sample_turn_completed_notification);外部调用 6 个(new, ItemCompleted, new, Notification, default, assert!)。

accepted_steers_increment_turn_steer_count4058–4160 ↗
async fn accepted_steers_increment_turn_steer_count()

作用:测试只有被接受的 steer 会增加最终回合事件里的 steer_count,被拒绝的不算。

数据流:准备回合 → 喂两次成功 steer 和一次失败 steer → 完成回合 → 在 turn event 里检查 steer_count 为 2。

调用关系:由异步测试框架运行;它使用 sample_turn_steer_request、sample_turn_steer_response、no_active_turn_steer_error 等。

调用图:调用 6 个内部函数(ingest_turn_prerequisites, no_active_turn_steer_error, no_active_turn_steer_error_type, sample_turn_completed_notification, sample_turn_steer_request, sample_turn_steer_response);外部调用 7 个(new, new, Notification, default, Integer, assert_eq!, to_value)。

turn_does_not_emit_without_required_prerequisites4163–4213 ↗
async fn turn_does_not_emit_without_required_prerequisites()

作用:测试缺少必要前置材料时,回合完成也不会发布 turn event。比如没有初始化或没有 resolved config。

数据流:分别构造两个不完整场景 → 喂完成通知 → 都断言输出为空。

调用关系:由异步测试框架运行;它调用 ingest_turn_prerequisites 来有意省略部分前置条件。

调用图:调用 2 个内部函数(ingest_turn_prerequisites, sample_turn_completed_notification);外部调用 5 个(new, new, Notification, default, assert!)。

turn_lifecycle_emits_failed_turn_event4216–4265 ↗
async fn turn_lifecycle_emits_failed_turn_event()

作用:测试失败回合会输出 turn event,并带上错误类型。这样后台能区分失败原因。

数据流:准备回合 → 喂 TurnCodexError 自定义事实 → 喂 Failed 完成通知和 BadRequest 信息 → 检查 status、turn_error、codex_error_kind。

调用关系:由异步测试框架运行;它调用 ingest_turn_prerequisites、sample_turn_completed_notification 和 TurnCodexErrorFact::from_codex_err。

调用图:调用 3 个内部函数(ingest_turn_prerequisites, sample_turn_completed_notification, from_codex_err);外部调用 9 个(new, new, Custom, Notification, TurnCodexError, default, assert_eq!, InvalidRequest, to_value)。

turn_lifecycle_emits_interrupted_turn_event_without_error4268–4298 ↗
async fn turn_lifecycle_emits_interrupted_turn_event_without_error()

作用:测试中断回合也会输出事件,但错误字段为空。中断不一定代表程序错误。

数据流:准备完整回合前置状态 → 喂 Interrupted 完成通知 → 检查 status 为 interrupted,错误字段是 null。

调用关系:由异步测试框架运行;它调用 ingest_turn_prerequisites 和 sample_turn_completed_notification。

调用图:调用 2 个内部函数(ingest_turn_prerequisites, sample_turn_completed_notification);外部调用 6 个(new, new, Notification, default, assert_eq!, to_value)。

turn_completed_without_started_notification_emits_null_started_at4301–4337 ↗
async fn turn_completed_without_started_notification_emits_null_started_at()

作用:测试如果没收到回合开始通知,完成事件仍可发布,但 started_at 和 token 等缺失字段保持 null。

数据流:准备初始化和 resolved config,但不喂 started 和 token → 喂完成通知 → 检查 started_at 为 null、duration 保留、token 为 null。

调用关系:由异步测试框架运行;它用 ingest_turn_prerequisites 的开关刻意跳过 started 通知。

调用图:调用 2 个内部函数(ingest_turn_prerequisites, sample_turn_completed_notification);外部调用 6 个(new, new, Notification, default, assert_eq!, to_value)。

sample_plugin_metadata4339–4355 ↗
fn sample_plugin_metadata() -> PluginTelemetryMetadata

作用:造一份固定的插件遥测元数据。它包含插件 ID、显示名、技能、MCP 服务名和应用连接器。

数据流:没有输入 → 解析 sample@test,填入 capability_summary → 返回 PluginTelemetryMetadata。

调用关系:插件使用、插件管理、插件去重、reducer 自定义事实测试都会调用它,作为统一插件样本。

调用图:调用 1 个内部函数(parse);被 6 处调用(plugin_management_event_can_use_remote_plugin_id_override, plugin_management_event_serializes_expected_shape, plugin_used_dedupe_is_keyed_by_turn_and_plugin, plugin_used_event_serializes_expected_shape, reducer_ingests_app_and_plugin_facts, reducer_ingests_plugin_state_changed_fact);外部调用 1 个(vec!)。

app-server/tests/suite/v2/analytics.rs源码 ↗
testtest execution

这份文件主要解决一个很实际的问题:分析事件如果发错了,轻则统计不准,重则可能在用户没同意时上传数据。文件里先测试一个关键规则:配置里没写是否开启分析时,要看 app-server 传进来的默认开关;默认关就没有指标,默认开就有指标。后半部分是一组测试辅助函数,像搭临时收件箱一样,用 wiremock(一个假 HTTP 服务器,用来接住测试里的网络请求)拦住分析上报接口,再把测试用的登录凭据写进临时目录。之后它会反复查看假服务器收到的请求,等到指定的分析包或事件出现,再把 JSON(一种常见的数据格式)解析出来给别的测试检查。最后还有专门检查“线程初始化事件”的小工具,确认里面有线程 ID、会话 ID、客户端名、模型名、来源等基础字段。

函数细节10
set_metrics_exporter24–31 ↗
fn set_metrics_exporter(config: &mut codex_core::config::Config)

作用:这个函数把测试配置里的指标上报出口固定成一个本地 HTTP 地址。这样测试不用真的连外网,只要后面接一个假服务器就能观察会不会发指标。

数据流:进去的是一份可修改的配置 → 它把配置里的 OpenTelemetry 指标导出器改成 OTLP HTTP JSON 方式,目标地址是 localhost:4318,且没有额外请求头和 TLS 加密设置 → 出来时没有返回值,但这份配置已经变成“会尝试用本地 HTTP 发送指标”的样子。

调用关系:两个默认分析开关测试都会先调用它,把环境调成可观察指标是否启用的状态;之后真正判断是否启用的活儿交给 codex_core::otel_init::build_provider。

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

app_server_default_analytics_disabled_without_flag34–56 ↗
async fn app_server_default_analytics_disabled_without_flag() -> Result<()>

作用:这是一个自动化测试,用来确认:如果用户配置里没有写分析开关,而 app-server 给的默认值是关闭,那么指标采集必须关闭。它防止系统在没有明确允许或默认允许时偷偷打开统计。

数据流:进去没有业务输入,只创建一个临时 codex_home 目录和默认配置 → 它设置本地指标导出器,再把 analytics_enabled 设成空值,表示配置里没写;然后调用 build_provider 建立遥测提供者(遥测就是指标、日志、追踪这类运行数据)→ 最后检查 provider 里是否真的没有 metrics,并用断言确认结果是 false。

调用关系:它是测试运行器直接执行的测试用例。它先借 set_metrics_exporter 准备配置,再把判断交给 build_provider,最后自己只检查“指标模块有没有被装上”。

调用图:调用 2 个内部函数(set_metrics_exporter, build_provider);外部调用 3 个(new, assert_eq!, default)。

app_server_default_analytics_enabled_with_flag59–80 ↗
async fn app_server_default_analytics_enabled_with_flag() -> Result<()>

作用:这是另一个自动化测试,用来确认:如果用户配置里没有写分析开关,但 app-server 给的默认值是开启,那么指标采集会开启。它保证默认开启的产品行为没有被配置加载逻辑误伤。

数据流:进去没有业务输入,只新建临时目录和默认配置 → 它把指标出口设成本地 HTTP,再让 analytics_enabled 保持空值;随后调用 build_provider,并把默认分析开关传成 true → 出来时通过检查 provider 里的 metrics 是否存在,确认指标确实启用了。

调用关系:它和关闭默认值的测试是一对镜像测试。它同样先调用 set_metrics_exporter,再依赖 build_provider 根据默认开关做决定,最后用断言守住预期行为。

调用图:调用 2 个内部函数(set_metrics_exporter, build_provider);外部调用 3 个(new, assert_eq!, default)。

mount_analytics_capture82–99 ↗
async fn mount_analytics_capture(server: &MockServer, codex_home: &Path) -> Result<()>

作用:这个函数给其他测试搭好“分析事件收件箱”。它让假服务器接收指定的分析上报请求,并准备一份测试登录信息,让 app-server 有身份信息可写进事件里。

数据流:进去的是一个 MockServer(假 HTTP 服务器)和一个 codex_home 路径 → 它在假服务器上登记规则:凡是 POST 到 /codex/analytics-events/events 的请求都返回 200;然后把 ChatGPT 测试凭据写到 codex_home 里,包含账号 ID 和用户 ID → 出来时返回成功或错误,副作用是假服务器已能接收分析请求,临时目录里也已有测试认证文件。

调用关系:很多线程、目标、回合相关测试在开始前会调用它,相当于先摆好接收分析事件的邮箱。后续测试再用 wait_for_analytics_payload、wait_for_analytics_event 或 wait_for_goal_event 去这个邮箱里找具体内容。

调用图:调用 1 个内部函数(new);被 10 处调用(thread_fork_tracks_thread_initialized_analytics, thread_goal_lifecycle_emits_analytics_and_clear_deletes_goal, thread_resume_tracks_thread_initialized_analytics, thread_start_tracks_thread_initialized_analytics, turn_profile_tracks_blocking_tool_and_follow_up_sampling, turn_start_tracks_turn_event_analytics, turn_steer_rejects_context_only_input_without_merging_context, turn_steer_rejects_oversized_text_input, turn_steer_requires_active_turn, turn_steer_returns_active_turn_id);外部调用 5 个(given, new, write_chatgpt_auth, method, path)。

wait_for_analytics_payload101–121 ↗
async fn wait_for_analytics_payload(
    server: &MockServer,
    read_timeout: Duration,
) -> Result<Value>

作用:这个函数等待并取回一整包分析上报内容。它适合测试只关心“有没有发一包分析 JSON”,或者要自己从整包里挑事件的时候使用。

数据流:进去的是假服务器和最长等待时间 → 它反复查看假服务器收到的请求;如果还没有请求,或者还没看到 POST 到分析接口的请求,就短暂睡 25 毫秒再查;一旦找到,就拿出请求体 → 最后把请求体从 JSON 字节解析成 serde_json::Value 返回,如果超时或 JSON 坏了就返回错误。

调用关系:线程启动、恢复、派生等测试会调用它来拿到完整分析包。它不挑具体事件,只负责等到分析接口收到数据,并把原始包交给上层测试继续检查。

调用图:被 3 处调用(thread_fork_tracks_thread_initialized_analytics, thread_resume_tracks_thread_initialized_analytics, thread_start_tracks_thread_initialized_analytics);外部调用 5 个(from_millis, received_requests, from_slice, sleep, timeout)。

wait_for_analytics_event123–132 ↗
async fn wait_for_analytics_event(
    server: &MockServer,
    read_timeout: Duration,
    event_type: &str,
) -> Result<Value>

作用:这个函数等待某一种事件类型出现。比如测试想确认“回合开始事件”真的发出,就可以告诉它要等哪个 event_type。

数据流:进去的是假服务器、最长等待时间和目标 event_type 字符串 → 它把“event["event_type"] 等于目标类型”这个判断条件交给 wait_for_matching_analytics_event → 出来的是匹配到的单个事件 JSON,或者等待失败时返回错误。

调用关系:它是更通用等待函数的便捷包装。回合开始、回合控制、工具采样等测试会用它按事件类型找事件,真正轮询服务器和解析 JSON 的工作交给 wait_for_matching_analytics_event。

调用图:调用 1 个内部函数(wait_for_matching_analytics_event);被 4 处调用(turn_profile_tracks_blocking_tool_and_follow_up_sampling, turn_start_tracks_turn_event_analytics, turn_steer_requires_active_turn, turn_steer_returns_active_turn_id)。

wait_for_goal_event134–146 ↗
async fn wait_for_goal_event(
    server: &MockServer,
    read_timeout: Duration,
    event_kind: &str,
    goal_status: &str,
) -> Result<Value>

作用:这个函数专门等待“目标生命周期”相关的分析事件。它不只看事件大类,还会确认目标事件的种类和状态都符合预期。

数据流:进去的是假服务器、最长等待时间、目标事件种类 event_kind 和目标状态 goal_status → 它组装一个判断条件:事件类型必须是 codex_goal_event,并且 event_params 里的 event_kind、goal_status 都匹配 → 出来的是找到的那条目标事件 JSON,找不到或超时就报错。

调用关系:目标创建、更新、清理之类的测试会调用它。它把“目标事件该长什么样”的判断写清楚,再把等待和查找过程交给 wait_for_matching_analytics_event。

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

wait_for_matching_analytics_event148–178 ↗
async fn wait_for_matching_analytics_event(
    server: &MockServer,
    read_timeout: Duration,
    matches: impl Fn(&Value) -> bool,
) -> Result<Value>

作用:这是等待分析事件的核心函数。调用者给它一个“什么算匹配”的条件,它就在假服务器收到的分析包里一直找,直到找到或超时。

数据流:进去的是假服务器、最长等待时间,以及一个匹配函数 matches → 它循环读取假服务器收到的请求,只处理 POST 到分析上报路径的请求;每个请求体会被解析成 JSON,然后从 payload["events"] 数组里逐个检查;只要某个事件让 matches 返回 true,就复制这条事件并返回 → 如果一直没有匹配事件,就每 25 毫秒等一下继续查,直到 timeout 触发错误。

调用关系:wait_for_analytics_event 和 wait_for_goal_event 都把具体匹配规则交给它。它位于测试辅助流程的底层,承担“从网络请求里翻找指定分析事件”的脏活累活。

调用图:被 2 处调用(wait_for_analytics_event, wait_for_goal_event);外部调用 5 个(from_millis, received_requests, from_slice, sleep, timeout)。

thread_initialized_event180–188 ↗
fn thread_initialized_event(payload: &Value) -> Result<&Value>

作用:这个函数从一整包分析数据里找出“线程已初始化”事件。线程可以理解成一次对话或任务的上下文,这个事件用来证明新线程信息已经被记录。

数据流:进去的是一整包 JSON payload → 它先确认 payload 里有 events 数组;然后在数组里查找 event_type 等于 codex_thread_initialized 的事件 → 找到就返回这条事件的引用,缺 events 或找不到事件就返回带说明的错误。

调用关系:线程启动、恢复、派生相关测试会先用 wait_for_analytics_payload 拿到整包数据,再调用它挑出线程初始化事件,随后通常交给 assert_basic_thread_initialized_event 做字段检查。

调用图:被 3 处调用(thread_fork_tracks_thread_initialized_analytics, thread_resume_tracks_thread_initialized_analytics, thread_start_tracks_thread_initialized_analytics)。

assert_basic_thread_initialized_event190–231 ↗
fn assert_basic_thread_initialized_event(
    event: &Value,
    thread_id: &str,
    session_id: &str,
    expected_model: &str,
    initialization_mode: &str,
    expected_thread_source: &str,
)

作用:这个函数检查“线程初始化事件”的基础字段是不是都对。它像一张验收清单,确保事件里带着正确的线程、会话、客户端、模型和来源信息。

数据流:进去的是一条事件 JSON,以及期望的 thread_id、session_id、模型名、初始化方式和线程来源 → 它逐项比较 event_params 里的字段:线程 ID、会话 ID、客户端名、传输方式、模型、是否临时线程、线程来源、父线程、子代理来源、初始化模式和创建时间 → 它没有正常返回值;如果任何字段不符合预期,测试会立刻失败。

调用关系:线程启动、恢复、派生测试在找到 codex_thread_initialized 事件后会调用它做统一检查。这样多个测试不用重复写同一大串断言,也能保证这些基础字段的标准一致。

调用图:被 3 处调用(thread_fork_tracks_thread_initialized_analytics, thread_resume_tracks_thread_initialized_analytics, thread_start_tracks_thread_initialized_analytics);外部调用 2 个(assert!, assert_eq!)。

应用遥测回归

这些测试检查核心应用辅助工具、任务指标、请求处理和持久化日志过滤所发出的遥测。

core/src/tasks/mod_tests.rs源码 ↗
test测试运行时

这是一组自动测试,目标是防止任务模块把运行数据记错。比如一次对话里网络代理是不是开启、记忆功能是不是允许读取、压缩任务是手动还是自动触发,这些都会被写成指标。文件先搭一个假的内存指标系统,也就是不把数据发到外部服务,而是留在测试里检查。然后每个测试触发一次真正的上报函数,再抓取当前指标快照,确认数值是 1,并且标签完全符合预期。这里的标签就像账本上的备注,比如 active=true、manual=false。这样做很重要,因为指标通常用于排查问题和统计产品行为;一旦标签写错,后面看到的统计图就会误导人。

函数细节10
test_session_telemetry21–41 ↗
fn test_session_telemetry() -> SessionTelemetry

作用:造出一个专门给测试用的会话遥测对象。遥测就是收集运行信息的工具,这里重点是让指标先存在内存里,方便测试马上读取。

数据流:进去没有外部输入;它新建一个内存指标导出器,配置一个测试用的 MetricsClient,再创建一个带线程编号、模型名、来源等基本信息的 SessionTelemetry;出来的是一个可记录、可快照查看指标的测试会话对象。

调用关系:所有具体测试开始前都会先调用它,相当于先摆好一张干净的测试账本。之后测试会把这个对象交给 emit_turn_network_proxy_metric、emit_turn_memory_metric 或 emit_compact_metric 这些真正的上报函数使用。

调用图:调用 4 个内部函数(new, new, in_memory, new);被 6 处调用(emit_compact_metric_records_auto_local, emit_compact_metric_records_manual_remote_v2, emit_turn_memory_metric_records_config_disabled_without_citations, emit_turn_memory_metric_records_read_allowed_with_citations, emit_turn_network_proxy_metric_records_active_turn, emit_turn_network_proxy_metric_records_inactive_turn);外部调用 2 个(default, env!)。

find_metric43–52 ↗
fn find_metric(resource_metrics: &'a ResourceMetrics, name: &str) -> &'a Metric

作用:从一大包指标数据里按名字找到目标指标。如果找不到,就直接让测试失败。

数据流:进去的是一次指标快照和要找的指标名;它逐层翻看快照里的 scope metrics,再检查每个 metric 的名字;出来的是匹配的 Metric 引用,如果没有匹配项就报错停止。

调用关系:它是 metric_point 的第一步。具体测试不会直接找指标,而是让 metric_point 调它来定位指标,再继续读取这个指标里的数值和标签。

调用图:被 1 处调用(metric_point);外部调用 2 个(scope_metrics, panic!)。

attributes_to_map54–60 ↗
fn attributes_to_map(
    attributes: impl Iterator<Item = &'a KeyValue>,
) -> BTreeMap<String, String>

作用:把指标上的标签整理成一张按键排序的小表,方便测试做精确比较。

数据流:进去的是一串 KeyValue 标签;它把每个标签的键和值都转成普通字符串,并收进 BTreeMap;出来的是一个稳定排序的字符串到字符串映射。

调用关系:它由 metric_point 调用。metric_point 找到指标点后,用它把标签变成容易和预期结果 assert_eq 比较的格式。

调用图:被 1 处调用(metric_point);外部调用 1 个(map)。

metric_point62–76 ↗
fn metric_point(resource_metrics: &ResourceMetrics, name: &str) -> (BTreeMap<String, String>, u64)

作用:读取某个指标唯一的一条计数记录,拿到它的标签和计数值。它把底层比较复杂的指标结构,变成测试好懂的“标签表 + 数字”。

数据流:进去的是指标快照和指标名;它先用 find_metric 找到指标,再确认这个指标是 u64 计数器的求和数据,并且只有一个数据点;然后用 attributes_to_map 整理标签;出来的是标签映射和计数值。如果形状不符合预期,就让测试失败。

调用关系:每个测试在触发指标上报后都会调用它取结果。它把底层 OpenTelemetry 指标结构,也就是通用的指标数据格式,转换成测试能直接断言的结果。

调用图:调用 2 个内部函数(attributes_to_map, find_metric);被 6 处调用(emit_compact_metric_records_auto_local, emit_compact_metric_records_manual_remote_v2, emit_turn_memory_metric_records_config_disabled_without_citations, emit_turn_memory_metric_records_read_allowed_with_citations, emit_turn_network_proxy_metric_records_active_turn, emit_turn_network_proxy_metric_records_inactive_turn);外部调用 2 个(assert_eq!, panic!)。

emit_turn_network_proxy_metric_records_active_turn79–101 ↗
fn emit_turn_network_proxy_metric_records_active_turn()

作用:验证当一次对话回合使用了网络代理时,网络代理指标会记录 active=true,并且计数加 1。

数据流:进去没有参数;它先创建测试遥测对象,再调用 emit_turn_network_proxy_metric,传入网络代理开启和 tmp_mem_enabled=true;随后取指标快照,用 metric_point 读出 TURN_NETWORK_PROXY_METRIC;最后确认数值是 1,标签包含 active=true 和 tmp_mem_enabled=true。

调用关系:这是针对 emit_turn_network_proxy_metric 的一个场景测试。它依赖 test_session_telemetry 准备环境,依赖 metric_point 读取结果,并用 assert_eq 确认真正上报函数写出的内容没偏差。

调用图:调用 2 个内部函数(metric_point, test_session_telemetry);外部调用 2 个(assert_eq!, emit_turn_network_proxy_metric)。

emit_turn_network_proxy_metric_records_inactive_turn104–126 ↗
fn emit_turn_network_proxy_metric_records_inactive_turn()

作用:验证当一次对话回合没有使用网络代理时,网络代理指标会记录 active=false,并且计数加 1。

数据流:进去没有参数;它创建测试遥测对象,调用 emit_turn_network_proxy_metric,传入网络代理关闭和 tmp_mem_enabled=false;然后抓取指标快照,读取 TURN_NETWORK_PROXY_METRIC;出来的检查结果必须是计数 1,标签为 active=false 和 tmp_mem_enabled=false。

调用关系:这是网络代理指标的另一个分支测试,和 active_turn 测试互补。它同样通过 test_session_telemetry 搭环境,通过 metric_point 把上报后的指标读出来。

调用图:调用 2 个内部函数(metric_point, test_session_telemetry);外部调用 2 个(assert_eq!, emit_turn_network_proxy_metric)。

emit_turn_memory_metric_records_read_allowed_with_citations129–154 ↗
fn emit_turn_memory_metric_records_read_allowed_with_citations()

作用:验证记忆功能在功能开关和配置都开启、并且有引用来源时,会被记录为允许读取。

数据流:进去没有参数;它创建测试遥测对象,调用 emit_turn_memory_metric,传入 feature_enabled=true、config_enabled=true、has_citations=true;随后读取 TURN_MEMORY_METRIC;最终确认计数是 1,并且标签写明功能开启、配置允许、有引用、read_allowed=true。

调用关系:这是记忆指标的正向场景测试。它检查 emit_turn_memory_metric 不只是照抄输入,还能正确推导 read_allowed 这个结果标签。

调用图:调用 2 个内部函数(metric_point, test_session_telemetry);外部调用 2 个(assert_eq!, emit_turn_memory_metric)。

emit_turn_memory_metric_records_config_disabled_without_citations157–182 ↗
fn emit_turn_memory_metric_records_config_disabled_without_citations()

作用:验证即使记忆功能本身可用,只要配置关闭且没有引用,指标也会记录为不允许读取。

数据流:进去没有参数;它创建测试遥测对象,调用 emit_turn_memory_metric,传入 feature_enabled=true、config_enabled=false、has_citations=false;然后取快照并读取 TURN_MEMORY_METRIC;最后确认计数为 1,标签中 config_use_memories=false、has_citations=false、read_allowed=false。

调用关系:这是记忆指标的关闭场景测试,和 read_allowed_with_citations 形成对照。它帮助确认 emit_turn_memory_metric 在配置不允许时不会错误地把读取状态记成 true。

调用图:调用 2 个内部函数(metric_point, test_session_telemetry);外部调用 2 个(assert_eq!, emit_turn_memory_metric)。

emit_compact_metric_records_manual_remote_v2185–203 ↗
fn emit_compact_metric_records_manual_remote_v2()

作用:验证手动触发的 remote_v2 类型压缩任务,会按正确类型和手动标记写入指标。

数据流:进去没有参数;它创建测试遥测对象,调用 emit_compact_metric,传入 type=remote_v2 和 manual=true;随后读取 TASK_COMPACT_METRIC;最后确认计数为 1,标签为 type=remote_v2、manual=true。

调用关系:这是压缩任务指标的手动远程场景测试。它把测试环境交给 emit_compact_metric 写指标,再让 metric_point 读取账本,最后用断言核对。

调用图:调用 2 个内部函数(metric_point, test_session_telemetry);外部调用 2 个(assert_eq!, emit_compact_metric)。

emit_compact_metric_records_auto_local206–224 ↗
fn emit_compact_metric_records_auto_local()

作用:验证自动触发的 local 类型压缩任务,会按正确类型和非手动标记写入指标。

数据流:进去没有参数;它创建测试遥测对象,调用 emit_compact_metric,传入 type=local 和 manual=false;然后读取 TASK_COMPACT_METRIC;出来的检查结果必须是计数 1,标签为 type=local、manual=false。

调用关系:这是压缩任务指标的自动本地场景测试,和 manual_remote_v2 测试一起覆盖不同压缩来源。它同样依靠 test_session_telemetry 准备内存指标系统,并靠 metric_point 检查上报结果。

调用图:调用 2 个内部函数(metric_point, test_session_telemetry);外部调用 2 个(assert_eq!, emit_compact_metric)。

core/src/util_tests.rs源码 ↗
testtest time

这个文件不是产品运行时的主逻辑,而是给工具函数做“验收检查”。项目里会把请求端点、认证方式、401 未授权错误、环境变量状态等信息打成 tracing 事件里的标签;这些标签通常会被 Sentry 这类错误追踪系统拿去帮助排查问题。测试里自己做了一个临时“收集器”:TagCollectorLayer 像一个监听器,只接收目标名是 feedback_tags 的事件;TagCollectorVisitor 像抄表员,把事件里的字段抄进一个有序字典。然后各个测试发出不同场景的反馈标签,检查字段有没有写对、空值有没有被清成空字符串、旧的 401 信息会不会残留、老式发送方式是否还能保留认证环境信息。最后还测了 normalize_thread_name,确保线程名会去掉前后空格,并拒绝全是空格的名字。

函数细节11
feedback_tags_macro_compiles19–24 ↗
fn feedback_tags_macro_compiles()

作用:这个测试只确认 feedback_tags! 这个宏能正常编译。宏就是一种在编译时展开的代码模板;这里还故意放了一个只支持调试打印的值,确保宏能接受这类输入。

数据流:进去的是几个写在宏里的标签值,比如模型名、布尔值,以及一个 OnlyDebug 类型的值 → 编译器展开 feedback_tags! 宏并检查类型能否通过 → 如果能编译,测试就算通过;它不检查运行结果,也不改外部状态。

调用关系:它是最轻量的防线,专门守住宏的用法别被改坏。它直接使用外部的 feedback_tags! 宏,不把工作交给本文件里的收集器。

调用图:外部调用 1 个(feedback_tags!)。

TagCollectorVisitor::record_bool32–35 ↗
fn record_bool(&mut self, field: &tracing::field::Field, value: bool)

作用:这个函数负责接收 tracing 事件里的布尔字段,也就是 true 或 false,并把它存成文字。这样后面的测试就能像查表一样检查字段值。

数据流:进去的是一个字段名和一个布尔值 → 它读取字段名,把布尔值转成字符串,比如 true 变成 "true" → 出来的是内部 tags 字典多了一条“字段名到字段值”的记录。

调用关系:它会在 TagCollectorLayer::on_event 调用 event.record 时被 tracing 框架间接调用。它只负责记录布尔值这一类字段,和 record_str、record_debug 一起组成测试用的抄表员。

调用图:外部调用 1 个(name)。

TagCollectorVisitor::record_str37–40 ↗
fn record_str(&mut self, field: &tracing::field::Field, value: &str)

作用:这个函数负责接收 tracing 事件里的字符串字段,并把字段名和值保存起来。它让测试能验证 endpoint、错误码、请求 ID 这类文字标签是否正确。

数据流:进去的是一个字段名和一个字符串值 → 它取出字段名,把字符串复制成自己的数据 → 出来的是 tags 字典里新增或覆盖对应字段。

调用关系:它也是在 TagCollectorLayer::on_event 记录事件内容时被 tracing 框架间接调用。它和其他 record_* 函数分工,专门处理字符串。

调用图:外部调用 1 个(name)。

TagCollectorVisitor::record_debug42–45 ↗
fn record_debug(&mut self, field: &tracing::field::Field, value: &dyn std::fmt::Debug)

作用:这个函数负责接收只能用“调试格式”打印的字段。调试格式可以理解成“给程序员看的文字版本”,常用于 Option、数字或自定义类型。

数据流:进去的是字段名和一个可调试打印的值 → 它把字段名取出来,再用 format! 把值转成类似 "\"req-123\"" 或 "200" 的文字 → 出来的是 tags 字典里保存了这个字段的文字表示。

调用关系:tracing 在遇到不是普通字符串或布尔值的字段时,会通过 event.record 间接走到这里。很多测试断言里的引号形式,正是因为字段是用调试格式记录下来的。

调用图:外部调用 2 个(name, format!)。

TagCollectorLayer::on_event58–66 ↗
fn on_event(&self, event: &Event<'_>, _ctx: Context<'_, S>)

作用:这个函数是测试里的事件监听入口。每当 tracing 发出一个事件,它会筛选出反馈标签事件,并把里面的字段收集起来。

数据流:进去的是一个 tracing 事件和上下文 → 它先看事件目标是不是 feedback_tags;不是就直接忽略 → 是的话就新建 TagCollectorVisitor 抄字段,把结果合并进共享 tags 字典,并把 event_count 加一。

调用关系:各个测试会把 TagCollectorLayer 装到 tracing_subscriber::registry 里;之后 emit_feedback_request_tags 或 emit_feedback_auth_recovery_tags 发事件时,tracing 框架会回调这个函数。它再把具体字段读取工作交给 TagCollectorVisitor。

调用图:外部调用 3 个(default, metadata, record)。

emit_feedback_request_tags_records_sentry_feedback_fields70–170 ↗
fn emit_feedback_request_tags_records_sentry_feedback_fields()

作用:这个测试确认一次完整的反馈请求,会把 Sentry 需要看的关键字段都发出来。Sentry 可以理解成线上错误记录本,字段越准,排查问题越容易。

数据流:进去的是测试手写的一组请求标签和认证环境信息,比如 endpoint、是否带认证头、API key 环境变量是否存在 → 测试安装临时收集器,调用 emit_feedback_request_tags_with_auth_env 发事件 → 出来的是收集到的 tags 字典;测试逐项检查字段值,并确认只发了 1 个事件。

调用关系:它通过 tracing_subscriber::registry 挂上 TagCollectorLayer,然后调用外部的 emit_feedback_request_tags_with_auth_env。事件发出后由 TagCollectorLayer::on_event 收集,再用 assert_eq! 做核对。

调用图:外部调用 6 个(new, new, new, assert_eq!, emit_feedback_request_tags_with_auth_env, registry)。

emit_feedback_auth_recovery_tags_preserves_401_specific_fields173–211 ↗
fn emit_feedback_auth_recovery_tags_preserves_401_specific_fields()

作用:这个测试确认认证恢复流程里,401 未授权相关的专用字段会被保留下来。401 是服务器说“你没有正确认证”的状态码,这些字段对找出登录或令牌问题很关键。

数据流:进去的是恢复模式、恢复阶段、恢复结果,以及 401 当时的请求 ID、Cloudflare Ray ID、错误信息和错误码 → 测试发出认证恢复标签事件 → 出来的是收集器里的 auth_401_* 字段;测试确认它们都等于传入值,并且事件数是 1。

调用关系:它依赖测试专用的 TagCollectorLayer 来抓事件。真正发标签的函数来自被测试代码,本测试负责模拟一个 401 恢复场景并检查结果。

调用图:外部调用 5 个(new, new, new, assert_eq!, registry)。

emit_feedback_auth_recovery_tags_clears_stale_401_fields214–258 ↗
fn emit_feedback_auth_recovery_tags_clears_stale_401_fields()

作用:这个测试确认旧的 401 错误信息不会赖在标签里。否则后一次请求明明没有某些错误,也可能被旧标签误导,像病历里没擦掉上一次的诊断。

数据流:先进去一组带完整 401 信息的恢复标签 → 再进去一组新的恢复标签,其中部分 401 信息是 None,也就是没有值 → 收集结果应该显示新的请求 ID,同时缺失的 Ray ID、错误、错误码被写成空字符串;事件计数变成 2。

调用关系:它连续调用两次认证恢复标签发送函数,用 TagCollectorLayer 观察第二次是否覆盖第一次留下的字段。这个测试重点不是只看能不能写入,而是看能不能正确清理。

调用图:外部调用 5 个(new, new, new, assert_eq!, registry)。

emit_feedback_request_tags_preserves_latest_auth_fields_after_unauthorized261–311 ↗
fn emit_feedback_request_tags_preserves_latest_auth_fields_after_unauthorized()

作用:这个测试确认遇到未授权并尝试恢复后,最新的认证相关信息仍然会被记录下来。这样排查时能看到最近一次失败和跟进请求的真实情况。

数据流:进去的是一个反馈请求标签,里面包含 401 后重试、请求 ID、Ray ID、错误码、后续请求是否成功等信息 → 测试调用 emit_feedback_request_tags 发事件 → 出来的是收集到的 auth_* 字段;测试确认它们没有丢失,并且只产生 1 个事件。

调用关系:它挂上本文件的 TagCollectorLayer,然后调用外部 emit_feedback_request_tags。TagCollectorLayer 收到 feedback_tags 事件后把字段存起来,测试再逐项检查。

调用图:外部调用 6 个(new, new, new, assert_eq!, emit_feedback_request_tags, registry)。

emit_feedback_request_tags_preserves_auth_env_fields_for_legacy_emitters314–425 ↗
fn emit_feedback_request_tags_preserves_auth_env_fields_for_legacy_emitters()

作用:这个测试检查“新旧两种发送方式混用”时,认证环境信息不会被老方式清掉。老方式这里指不再显式带认证环境参数的 emit_feedback_request_tags。

数据流:先进去一组带认证环境信息的完整标签,通过 emit_feedback_request_tags_with_auth_env 发出 → 再进去一组很多认证字段为空的标签,通过老式 emit_feedback_request_tags 发出 → 最终 tags 里普通认证字段应被清成空字符串,但 auth_env_* 环境字段仍保留第一次的值;事件数是 2。

调用关系:它先调用带环境信息的发送函数,再调用不带环境信息的发送函数,模拟兼容旧调用方的情况。TagCollectorLayer 负责记录两次事件的最终字段状态,assert_eq! 负责证明兼容性没被破坏。

调用图:外部调用 7 个(new, new, new, assert_eq!, emit_feedback_request_tags, emit_feedback_request_tags_with_auth_env, registry)。

normalize_thread_name_trims_and_rejects_empty428–434 ↗
fn normalize_thread_name_trims_and_rejects_empty()

作用:这个测试确认线程名整理函数会去掉前后空格,并拒绝空名字。线程名可以理解成给后台任务贴的名字,太脏或空白会让日志难读。

数据流:进去的是两个例子:一个全是空格,一个前后带空格的正常名字 → normalize_thread_name 应该把全空格变成 None,表示没有可用名字;把正常名字修剪成 "my thread" → 测试用 assert_eq! 检查结果。

调用关系:它直接测试上层 util 模块里的 normalize_thread_name,不依赖 tracing 收集器。它补上了本文件中和反馈标签无关的一个小工具行为检查。

调用图:外部调用 1 个(assert_eq!)。

core/tests/suite/otel.rs源码 ↗
testtest run

这个测试文件把 Codex 放进一个可控的假环境里运行:先启动一个假的服务器,喂给它模拟的 SSE(服务器持续推送事件的文本流)响应,再让测试版 Codex 像真实用户聊天一样提交输入。随后测试去看日志里有没有出现应该出现的遥测字段,比如请求发出了、模型返回了什么事件、解析失败怎么记、token 用量是多少、工具调用成功还是失败、shell 命令是配置自动批准还是用户批准。它还直接测试一些小工具函数,用来从日志行里抠字段、生成跨平台命令。整体像给“黑匣子记录仪”做验收:不仅要飞机会飞,还要每个关键动作都被准确记录下来。

函数细节31
extract_log_field41–59 ↗
fn extract_log_field(line: &str, key: &str) -> Option<String>

作用:从一行日志文字里取出某个字段的值。它既能读带引号的写法,也能读不带引号的写法,方便测试检查日志内容。

数据流:进去的是一整行日志和字段名 → 它先找 key="value" 这种形式,找不到再按空格拆开找 key=value → 出来的是字段值;如果日志里没有这个字段,就返回空。

调用关系:它是底层小帮手,主要被 assert_empty_mcp_tool_fields 调用,用来确认工具结果日志里的 MCP 字段是否存在且为空。

调用图:被 1 处调用(assert_empty_mcp_tool_fields);外部调用 1 个(format!)。

assert_empty_mcp_tool_fields61–77 ↗
fn assert_empty_mcp_tool_fields(line: &str) -> Result<(), String>

作用:检查一行工具结果日志里,MCP 相关字段是不是都存在但内容为空。MCP 可以理解成外部工具服务器协议,这里要确认普通工具调用没有误填 MCP 信息。

数据流:进去的是一行日志 → 它用 extract_log_field 分别取 mcp_servermcp_server_origin → 如果字段缺失或不是空字符串,就返回错误;都正确就返回成功。

调用关系:它被多个工具结果测试间接使用,用来统一检查日志没有把非 MCP 工具误标成 MCP 工具。

调用图:调用 1 个内部函数(extract_log_field);外部调用 1 个(format!)。

shell_command_call79–82 ↗
fn shell_command_call(call_id: &str, command: &str) -> serde_json::Value

作用:快速造一个“模型要求执行 shell 命令”的假响应事件。shell 命令就是让系统命令行执行一段命令。

数据流:进去的是调用编号和命令文本 → 它把命令包成 JSON 参数,再交给 ev_function_call 生成函数调用事件 → 出来的是一段可放进假 SSE 响应里的 JSON 值。

调用关系:多个 shell 命令相关测试用它准备模拟数据,让 Codex 以为模型要求调用 shell_command 工具。

调用图:调用 1 个内部函数(ev_function_call);外部调用 1 个(json!)。

touch_command84–90 ↗
fn touch_command(path: &str) -> String

作用:生成一个适合当前操作系统的“创建文件”命令。这样同一组测试在 Windows 和类 Unix 系统上都能跑。

数据流:进去的是文件路径 → 它判断当前是否是 Windows → Windows 返回 PowerShell 的 New-Item 命令,其他系统返回 /usr/bin/touch 命令。

调用关系:所有需要触发真实 shell 审批流程的测试都会调用它,避免测试因为操作系统不同而命令写错。

调用图:被 6 处调用(handle_sandbox_error_user_approves_for_session_records_tool_decision, handle_sandbox_error_user_approves_retry_records_tool_decision, handle_sandbox_error_user_denies_records_tool_decision, handle_shell_command_user_approved_for_session_records_tool_decision, handle_shell_command_user_approved_records_tool_decision, handle_shell_command_user_denies_records_tool_decision);外部调用 2 个(cfg!, format!)。

extract_log_field_handles_empty_bare_values93–100 ↗
fn extract_log_field_handles_empty_bare_values()

作用:确认 extract_log_field 能正确读出没有引号、但值为空的日志字段。空值也是有效信息,不能被当成不存在。

数据流:进去的是一行包含 mcp_server= 的假日志 → 测试调用字段提取函数 → 预期拿到空字符串,而不是空结果。

调用关系:这是给 extract_log_field 的单元测试,保证后面检查空 MCP 字段的测试不会误判。

调用图:外部调用 1 个(assert_eq!)。

extract_log_field_does_not_confuse_similar_keys103–110 ↗
fn extract_log_field_does_not_confuse_similar_keys()

作用:确认字段名相似时不会拿错,比如查 mcp_server 时不能误读成 mcp_server_origin

数据流:进去的是只含 mcp_server_origin 的日志行 → 测试分别查询两个字段 → mcp_server 应该不存在,mcp_server_origin 应该取到正确值。

调用关系:这是 extract_log_field 的边界测试,防止日志字段检查因为前缀相同而产生假阳性。

调用图:外部调用 1 个(assert_eq!)。

responses_api_emits_api_request_event114–152 ↗
async fn responses_api_emits_api_request_event()

作用:验证 Codex 调用 Responses API 时,会记录“发起 API 请求”和“会话开始”的遥测事件。

数据流:测试启动假服务器并挂载一个完成响应 → 构建测试版 Codex,提交一条用户输入 → 等到回合完成后检查日志里有 codex.api_requestcodex.conversation_starts

调用关系:它把 start_mock_servermount_sse_oncetest_codexwait_for_event 串起来,模拟一次最简单的聊天请求,然后验收遥测记录。

调用图:调用 4 个内部函数(mount_sse_once, sse, start_mock_server, test_codex);外部调用 3 个(default, wait_for_event, vec!)。

process_sse_emits_tracing_for_output_item156–193 ↗
async fn process_sse_emits_tracing_for_output_item()

作用:验证处理 SSE 输出项时,会把模型输出完成事件写进追踪日志。追踪日志可以理解成程序运行路径的详细脚印。

数据流:假服务器推送一条助手消息和完成事件 → Codex 处理用户输入 → 测试等待回合结束,再检查日志中是否有 response.output_item.done

调用关系:它覆盖 SSE 正常输出路径,确保处理模型消息时会经过遥测记录环节。

调用图:调用 4 个内部函数(mount_sse_once, sse, start_mock_server, test_codex);外部调用 3 个(default, wait_for_event, vec!)。

process_sse_emits_failed_event_on_parse_error197–240 ↗
async fn process_sse_emits_failed_event_on_parse_error()

作用:验证 SSE 数据不是合法 JSON 时,Codex 会记录解析失败,而不是静默吞掉错误。

数据流:假服务器返回 data: not-json → Codex 尝试解析并完成回合 → 测试检查日志里有 codex.sse_event,并包含解析错误信息。

调用关系:它通过 mount_sse_once 注入坏数据,用来测试 SSE 解析失败这条异常路径。

调用图:调用 3 个内部函数(mount_sse_once, start_mock_server, test_codex);外部调用 3 个(default, wait_for_event, vec!)。

process_sse_records_failed_event_when_stream_closes_without_completed244–287 ↗
async fn process_sse_records_failed_event_when_stream_closes_without_completed()

作用:验证服务器推送流提前结束、没有发完成事件时,会被记录成失败事件。

数据流:假服务器只发助手消息,不发 response.completed → Codex 处理到流关闭 → 测试检查日志里写了“stream closed before response.completed”。

调用关系:它测试网络流不完整的情况,保证 Codex 的遥测能说明“不是正常完成,而是流断了”。

调用图:调用 4 个内部函数(mount_sse_once, sse, start_mock_server, test_codex);外部调用 3 个(default, wait_for_event, vec!)。

process_sse_failed_event_records_response_error_message291–355 ↗
async fn process_sse_failed_event_records_response_error_message()

作用:验证模型返回 response.failed 时,日志会记录服务端给出的错误消息。

数据流:假服务器先返回带 boom 错误消息的失败事件,再返回一次正常收尾响应 → Codex 跑完整个流程 → 测试检查日志里有失败事件和 boom

调用关系:它覆盖服务端明确报错的路径,确认错误内容不会在遥测中丢失。

调用图:调用 4 个内部函数(mount_sse_once, sse, start_mock_server, test_codex);外部调用 3 个(default, wait_for_event, vec!)。

process_sse_failed_event_logs_parse_error359–417 ↗
async fn process_sse_failed_event_logs_parse_error()

作用:验证 response.failed 结构不符合预期时,仍然会留下失败事件日志。

数据流:假服务器返回一个错误字段格式不对的失败事件 → Codex 尝试解析 → 测试只要求日志里出现 response.failed,说明异常格式也被看见了。

调用关系:它测试失败事件本身格式损坏的情况,防止遥测因为解析不完整而完全没有记录。

调用图:调用 4 个内部函数(mount_sse_once, sse, start_mock_server, test_codex);外部调用 3 个(default, wait_for_event, vec!)。

process_sse_failed_event_logs_missing_error421–469 ↗
async fn process_sse_failed_event_logs_missing_error()

作用:验证 response.failed 里缺少错误详情时,也会记录失败事件。

数据流:假服务器返回没有 error 字段的失败响应 → Codex 处理这段流 → 测试检查日志至少记录了 response.failed

调用关系:它和其他失败事件测试一起覆盖服务端异常响应的各种残缺形态。

调用图:调用 4 个内部函数(mount_sse_once, sse, start_mock_server, test_codex);外部调用 3 个(default, wait_for_event, vec!)。

process_sse_failed_event_logs_response_completed_parse_error473–533 ↗
async fn process_sse_failed_event_logs_response_completed_parse_error()

作用:验证 response.completed 看起来完成了、但内容格式不对时,会把解析失败写入日志。

数据流:假服务器返回缺少必要内容的完成事件 → Codex 解析失败后继续测试流程 → 日志应包含 response.completed 和“failed to parse ResponseCompleted”。

调用关系:它检查完成事件的坏格式路径,保证“完成事件也可能解析失败”这种情况有可查记录。

调用图:调用 4 个内部函数(mount_sse_once, sse, start_mock_server, test_codex);外部调用 3 个(default, wait_for_event, vec!)。

process_sse_emits_completed_telemetry537–591 ↗
async fn process_sse_emits_completed_telemetry()

作用:验证模型完成响应里带的 token 用量,会被写进遥测日志。token 可以简单理解成模型读写文字时计费和计量的小单位。

数据流:假服务器返回包含输入、输出、缓存、推理 token 数的完成事件 → Codex 处理完成 → 测试检查日志里这些数字都被记录到对应字段。

调用关系:它覆盖正常完成后的用量统计路径,帮助确认账单、性能分析和模型消耗统计不会丢数。

调用图:调用 4 个内部函数(mount_sse_once, sse, start_mock_server, test_codex);外部调用 3 个(default, wait_for_event, vec!)。

turn_and_completed_response_spans_record_token_usage594–683 ↗
async fn turn_and_completed_response_spans_record_token_usage()

作用:验证一次对话回合和一次模型完成响应的追踪 span 都记录了 token 用量。span 可以理解成一段被计时、带标签的程序执行片段。

数据流:测试先搭一个专门收集追踪日志的缓冲区 → 假服务器返回带 token 用量的完成事件 → Codex 处理用户输入 → 测试从缓冲区读日志,确认完成响应 span 和整轮 turn span 都有正确用量字段。

调用关系:它自己设置 tracing subscriber,也就是日志接收器;再用 start_mock_servermount_sse_oncetest_codex 跑完整流程,最后直接检查底层追踪输出。

调用图:调用 4 个内部函数(mount_sse_once, sse, start_mock_server, test_codex);外部调用 12 个(leak, new, default, new, new, from_utf8, new, assert!, wait_for_event, set_default (+2 more))。

handle_responses_span_records_response_kind_and_tool_name686–760 ↗
async fn handle_responses_span_records_response_kind_and_tool_name()

作用:验证处理模型响应时,追踪 span 会标明事件类型,以及函数调用的工具名。

数据流:假服务器先返回一个不存在工具的函数调用,再返回正常消息 → Codex 处理后,测试读取追踪日志 → 确认 span 里有 function_call、工具名 nonexistent 和完成事件。

调用关系:它测试 handle_responses 这段处理流程的元信息记录,尤其是工具调用这类需要额外排查的事件。

调用图:调用 4 个内部函数(mount_sse_once, sse, start_mock_server, test_codex);外部调用 12 个(leak, new, default, new, new, from_utf8, new, assert!, wait_for_event, set_default (+2 more))。

record_responses_sets_span_fields_for_response_events763–871 ↗
async fn record_responses_sets_span_fields_for_response_events()

作用:验证不同种类的响应事件都会给追踪 span 填上正确字段,比如创建、文本增量、推理内容、工具调用、完成等。

数据流:测试拼出一长串模拟 SSE 事件 → Codex 处理后还会跟进一次响应 → 测试扫描追踪日志,逐项确认每类事件都有预期的 otel.name、来源字段和工具名字段。

调用关系:它是覆盖面最广的响应遥测测试,使用 mount_response_oncesse_response 构造更接近真实 HTTP 响应的 SSE 流。

调用图:调用 5 个内部函数(mount_response_once, sse, sse_response, start_mock_server, test_codex);外部调用 13 个(leak, new, default, new, new, from_utf8, new, assert!, wait_for_event, format! (+3 more))。

handle_response_item_records_tool_result_for_custom_tool_call875–950 ↗
async fn handle_response_item_records_tool_result_for_custom_tool_call()

作用:验证模型发起不支持的自定义工具调用时,日志会记录一条失败的工具结果。

数据流:假服务器返回一个名为 unsupported_tool 的自定义工具调用 → Codex 处理失败并继续收尾 → 测试检查 codex.tool_result 里有调用编号、工具名、参数、失败输出和 success=false

调用关系:它覆盖自定义工具调用路径,并复用 assert_empty_mcp_tool_fields 确认这不是 MCP 工具调用。

调用图:调用 4 个内部函数(mount_sse_once, sse, start_mock_server, test_codex);外部调用 3 个(default, wait_for_event, vec!)。

handle_response_item_records_tool_result_for_function_call954–1026 ↗
async fn handle_response_item_records_tool_result_for_function_call()

作用:验证普通函数工具调用不存在时,会记录失败的工具结果。

数据流:假服务器返回一个不存在的函数调用 → Codex 处理后产生工具结果 → 测试等待 token 统计事件,再检查日志里的工具名、参数、失败输出和成功标记。

调用关系:它和自定义工具测试类似,但覆盖普通 function_call 路径,用来确认不同工具类型都写同样可靠的结果日志。

调用图:调用 4 个内部函数(mount_sse_once, sse, start_mock_server, test_codex);外部调用 3 个(default, wait_for_event, vec!)。

handle_response_item_records_tool_result_for_shell_command_call1030–1104 ↗
async fn handle_response_item_records_tool_result_for_shell_command_call()

作用:验证 shell 命令工具调用后,会记录工具结果日志,包括命令参数、输出和是否成功。

数据流:测试生成一个 echo shell 的 shell 调用,并配置不需要审批 → Codex 执行处理 → 日志里应有 shell_command 的结果、非空输出、参数和成功状态字段。

调用关系:它使用 shell_command_call 准备事件,测试真实工具处理路径里的遥测结果。

调用图:调用 4 个内部函数(mount_sse_once, sse, start_mock_server, test_codex);外部调用 3 个(default, wait_for_event, vec!)。

tool_decision_assertion1106–1136 ↗
fn tool_decision_assertion(
    call_id: &'a str,
    expected_decision: &'a str,
    expected_source: &'a str,
) -> impl Fn(&[&str]) -> Result<(), String> + 'a

作用:生成一个日志检查器,用来确认某个 shell 工具调用的审批决定是否被正确记录。

数据流:进去的是调用编号、期望决定、期望来源 → 它返回一个闭包,也就是可以稍后执行的小检查函数 → 这个检查函数扫描日志,确认 codex.tool_decision 里有正确工具名、决定和来源。

调用关系:多个审批相关测试都会调用它,把重复的日志检查逻辑集中起来,避免每个测试都手写一遍。

调用图:被 7 处调用(handle_sandbox_error_user_approves_for_session_records_tool_decision, handle_sandbox_error_user_approves_retry_records_tool_decision, handle_sandbox_error_user_denies_records_tool_decision, handle_shell_command_autoapprove_from_config_records_tool_decision, handle_shell_command_user_approved_for_session_records_tool_decision, handle_shell_command_user_approved_records_tool_decision, handle_shell_command_user_denies_records_tool_decision)。

sandbox_outcome_assertion1138–1170 ↗
fn sandbox_outcome_assertion(
    call_id: &'a str,
    expected_outcome: &'a str,
) -> impl Fn(&[&str]) -> Result<(), String> + 'a

作用:生成一个日志检查器,用来确认沙箱执行结果是否被正确记录。沙箱可以理解成限制命令权限的安全隔离盒子。

数据流:进去的是调用编号和期望结果 → 它返回一个扫描日志的检查函数 → 这个函数确认 codex.sandbox_outcome 里有工具名、结果,以及初次执行和升级执行的耗时字段。

调用关系:它被 sandbox_outcome_event_records_outcome 使用,专门检查沙箱结果遥测。

调用图:被 1 处调用(sandbox_outcome_event_records_outcome)。

sandbox_outcome_event_records_outcome1174–1200 ↗
fn sandbox_outcome_event_records_outcome()

作用:直接测试 SessionTelemetry 记录沙箱结果的能力,不依赖完整 Codex 对话流程。

数据流:测试创建一个遥测会话对象 → 调用 sandbox_outcome,传入工具名、调用编号、结果和耗时 → 再用 sandbox_outcome_assertion 检查日志内容。

调用关系:它走的是遥测对象的直接接口,比端到端测试更短,专门确认沙箱结果事件本身会正确落日志。

调用图:调用 3 个内部函数(sandbox_outcome_assertion, new, new);外部调用 1 个(from_millis)。

handle_shell_command_autoapprove_from_config_records_tool_decision1204–1257 ↗
async fn handle_shell_command_autoapprove_from_config_records_tool_decision()

作用:验证 shell 命令因为配置规则自动批准时,会记录“由配置批准”的工具决定。

数据流:测试配置权限策略允许按规则自动通过,并关闭沙箱限制 → 模型请求执行 shell 命令 → Codex 完成后,日志应写明该调用被批准,来源是 config

调用关系:它用 tool_decision_assertion 检查结果,覆盖不需要用户手动点击同意的审批路径。

调用图:调用 5 个内部函数(mount_sse_once, sse, start_mock_server, test_codex, tool_decision_assertion);外部调用 3 个(default, wait_for_event, vec!)。

handle_shell_command_user_approved_records_tool_decision1261–1327 ↗
async fn handle_shell_command_user_approved_records_tool_decision()

作用:验证用户手动批准一次 shell 命令时,日志会记录决定为批准、来源为用户。

数据流:测试用 touch_command 生成创建文件命令 → Codex 发出执行审批请求 → 测试提交 Approved 决定 → 等处理继续后检查日志里的审批决定。

调用关系:它模拟真实用户点“允许一次”的场景,和 tool_decision_assertion 配合确认遥测字段。

调用图:调用 6 个内部函数(mount_sse_once, sse, start_mock_server, test_codex, tool_decision_assertion, touch_command);外部调用 4 个(default, wait_for_event, panic!, vec!)。

handle_shell_command_user_approved_for_session_records_tool_decision1331–1397 ↗
async fn handle_shell_command_user_approved_for_session_records_tool_decision()

作用:验证用户选择“本会话都允许”时,shell 工具决定会被记录为会话级批准。

数据流:测试触发一个需要审批的 shell 命令 → 收到审批请求后提交 ApprovedForSession → Codex 继续处理 → 日志应显示决定为 approvedforsession,来源为用户。

调用关系:它覆盖比单次批准更长期的审批选择,仍通过 tool_decision_assertion 做统一检查。

调用图:调用 6 个内部函数(mount_sse_once, sse, start_mock_server, test_codex, tool_decision_assertion, touch_command);外部调用 4 个(default, wait_for_event, panic!, vec!)。

handle_sandbox_error_user_approves_retry_records_tool_decision1401–1467 ↗
async fn handle_sandbox_error_user_approves_retry_records_tool_decision()

作用:验证命令在沙箱里遇到问题后,用户批准重试时,也会记录工具决定。

数据流:测试触发一个 shell 命令并等待审批请求 → 用户提交批准 → Codex 重试并继续流程 → 日志应记录该调用被用户批准。

调用关系:它和普通用户批准测试相似,但语义上覆盖沙箱失败后升级或重试的审批路径。

调用图:调用 6 个内部函数(mount_sse_once, sse, start_mock_server, test_codex, tool_decision_assertion, touch_command);外部调用 4 个(default, wait_for_event, panic!, vec!)。

handle_shell_command_user_denies_records_tool_decision1471–1537 ↗
async fn handle_shell_command_user_denies_records_tool_decision()

作用:验证用户拒绝 shell 命令时,日志会记录拒绝决定。

数据流:测试触发需要审批的 shell 命令 → 收到审批请求后提交 Denied → Codex 继续处理失败结果 → 日志应显示决定为 denied,来源为用户。

调用关系:它覆盖用户不同意执行命令的安全路径,使用 tool_decision_assertion 检查日志。

调用图:调用 6 个内部函数(mount_sse_once, sse, start_mock_server, test_codex, tool_decision_assertion, touch_command);外部调用 4 个(default, wait_for_event, panic!, vec!)。

handle_sandbox_error_user_approves_for_session_records_tool_decision1541–1607 ↗
async fn handle_sandbox_error_user_approves_for_session_records_tool_decision()

作用:验证沙箱相关审批中,用户选择本会话批准时,会正确记录为用户的会话级批准。

数据流:测试触发 shell 命令并等待审批 → 提交 ApprovedForSession → Codex 继续处理 → 日志应包含对应调用编号、approvedforsessionuser 来源。

调用关系:它覆盖沙箱错误或升级场景下的会话级批准路径,复用 touch_commandtool_decision_assertion

调用图:调用 6 个内部函数(mount_sse_once, sse, start_mock_server, test_codex, tool_decision_assertion, touch_command);外部调用 4 个(default, wait_for_event, panic!, vec!)。

handle_sandbox_error_user_denies_records_tool_decision1611–1678 ↗
async fn handle_sandbox_error_user_denies_records_tool_decision()

作用:验证沙箱相关审批中,用户拒绝执行时,会记录拒绝决定。

数据流:测试触发 shell 命令审批 → 用户提交拒绝 → Codex 收到决定后继续结束流程 → 日志应记录 denied,并标明来源是用户。

调用关系:它是沙箱审批系列里的拒绝分支,和批准、会话批准测试一起保证所有用户选择都有遥测记录。

调用图:调用 6 个内部函数(mount_sse_once, sse, start_mock_server, test_codex, tool_decision_assertion, touch_command);外部调用 4 个(default, wait_for_event, panic!, vec!)。

state/src/log_db_filter_tests.rs源码 ↗
testtest

这个测试像是在检查一个“门卫”:日志来了以后,门卫要判断哪些能进数据库,哪些太琐碎要拦掉。测试先创建一个临时的状态目录,启动 StateRuntime,也就是这套状态和日志存储的运行环境。然后它启动日志写入层,并把全局日志级别放到 TRACE,意思是理论上所有日志都允许产生。接着它故意发出几条日志:两条来自 opentelemetry_sdk 的低级 TRACE、DEBUG 日志,一条来自同一目标的 INFO 日志,还有一条来自 codex_state 的 TRACE 日志。之后强制把日志刷入数据库,再查询数据库里的日志。最后断言数据库里只剩两条:OpenTelemetry SDK 的 INFO,以及 codex_state 的 TRACE。也就是说,这个文件验证了一个重要规则:只过滤掉特定来源的低级噪音,而不是粗暴地丢掉所有低级日志。

函数细节1
sqlite_sink_drops_low_level_opentelemetry_sdk_logs10–53 ↗
async fn sqlite_sink_drops_low_level_opentelemetry_sdk_logs()

作用:这个测试函数确认 SQLite 日志接收端会过滤掉 opentelemetry_sdk 目标下的 TRACE 和 DEBUG 日志,但保留更重要的 INFO 日志,也保留项目自身的 TRACE 日志。有人改日志过滤规则时,这个测试能立刻发现是不是把该留的删了,或者把该丢的留下了。

数据流:进去的是一个新建的临时目录和测试用的 provider 名字;函数用它们初始化运行环境,挂上日志写入层,然后发出四条不同来源、不同等级的日志。它把日志层 flush,也就是强制把缓冲里的日志写完,再从日志数据库查询结果。出来的是一次断言:查询到的日志必须刚好等于两条预期记录;最后它还删除临时目录,清理测试留下的文件。

调用关系:这个函数由 Tokio 的异步测试框架在跑测试时调用。它先调用 StateRuntime::init 准备临时数据库环境,再通过 start 拿到负责写日志的 layer,并把它接到 tracing_subscriber 这套日志订阅系统上。随后 tracing::trace、debug、info 这些宏负责制造日志,layer.flush 负责把日志落库,runtime.query_logs 负责读回结果,pretty_assertions::assert_eq! 负责用更清楚的方式比较实际结果和预期结果。最后 tokio::fs::remove_dir_all 接手清理临时目录。

调用图:调用 1 个内部函数(init);外部调用 10 个(new, assert_eq!, format!, default, temp_dir, remove_dir_all, debug!, info!, trace!, registry)。