use super::emit_turn_network_proxy_metric; use codex_otel::SessionTelemetry; use codex_otel::metrics::MetricsClient; use codex_otel::metrics::MetricsConfig; use codex_otel::metrics::names::TURN_NETWORK_PROXY_METRIC; use codex_protocol::ThreadId; use codex_protocol::protocol::SessionSource; use opentelemetry::KeyValue; use opentelemetry_sdk::metrics::InMemoryMetricExporter; use opentelemetry_sdk::metrics::data::AggregatedMetrics; use opentelemetry_sdk::metrics::data::Metric; use opentelemetry_sdk::metrics::data::MetricData; use opentelemetry_sdk::metrics::data::ResourceMetrics; use pretty_assertions::assert_eq; use std::collections::BTreeMap; fn test_session_telemetry() -> SessionTelemetry { let exporter = InMemoryMetricExporter::default(); let metrics = MetricsClient::new( MetricsConfig::in_memory("test", "codex-core", env!("CARGO_PKG_VERSION"), exporter) .with_runtime_reader(), ) .expect("in-memory metrics client"); SessionTelemetry::new( ThreadId::new(), "gpt-5.1", "gpt-5.1", None, None, None, "test_originator".to_string(), false, "tty".to_string(), SessionSource::Cli, ) .with_metrics_without_metadata_tags(metrics) } fn find_metric<'a>(resource_metrics: &'a ResourceMetrics, name: &str) -> &'a Metric { for scope_metrics in resource_metrics.scope_metrics() { for metric in scope_metrics.metrics() { if metric.name() == name { return metric; } } } panic!("metric {name} missing"); } fn attributes_to_map<'a>( attributes: impl Iterator, ) -> BTreeMap { attributes .map(|kv| (kv.key.as_str().to_string(), kv.value.as_str().to_string())) .collect() } fn metric_point(resource_metrics: &ResourceMetrics) -> (BTreeMap, u64) { let metric = find_metric(resource_metrics, TURN_NETWORK_PROXY_METRIC); match metric.data() { AggregatedMetrics::U64(data) => match data { MetricData::Sum(sum) => { let points: Vec<_> = sum.data_points().collect(); assert_eq!(points.len(), 1); let point = points[0]; (attributes_to_map(point.attributes()), point.value()) } _ => panic!("unexpected counter aggregation"), }, _ => panic!("unexpected counter data type"), } } #[test] fn emit_turn_network_proxy_metric_records_active_turn() { let session_telemetry = test_session_telemetry(); emit_turn_network_proxy_metric(&session_telemetry, true, ("tmp_mem_enabled", "true")); let snapshot = session_telemetry .snapshot_metrics() .expect("runtime metrics snapshot"); let (attrs, value) = metric_point(&snapshot); assert_eq!(value, 1); assert_eq!( attrs, BTreeMap::from([ ("active".to_string(), "true".to_string()), ("tmp_mem_enabled".to_string(), "true".to_string()), ]) ); } #[test] fn emit_turn_network_proxy_metric_records_inactive_turn() { let session_telemetry = test_session_telemetry(); emit_turn_network_proxy_metric(&session_telemetry, false, ("tmp_mem_enabled", "false")); let snapshot = session_telemetry .snapshot_metrics() .expect("runtime metrics snapshot"); let (attrs, value) = metric_point(&snapshot); assert_eq!(value, 1); assert_eq!( attrs, BTreeMap::from([ ("active".to_string(), "false".to_string()), ("tmp_mem_enabled".to_string(), "false".to_string()), ]) ); }