Codex Handbook
otel/tests/suite/validation.rs 91 lines
use codex_otel::MetricsClient;use codex_otel::MetricsConfig;use codex_otel::MetricsError;use codex_otel::Result;use opentelemetry_sdk::metrics::InMemoryMetricExporter;fn build_in_memory_client() -> Result<MetricsClient> {    let exporter = InMemoryMetricExporter::default();    let config = MetricsConfig::in_memory("test", "codex-cli", env!("CARGO_PKG_VERSION"), exporter);    MetricsClient::new(config)}// Ensures invalid tag components are rejected during config build.#[test]fn invalid_tag_component_is_rejected() -> Result<()> {    let err = MetricsConfig::in_memory(        "test",        "codex-cli",        env!("CARGO_PKG_VERSION"),        InMemoryMetricExporter::default(),    )    .with_tag("bad key", "value")    .unwrap_err();    assert!(matches!(        err,        MetricsError::InvalidTagComponent { label, value }            if label == "tag key" && value == "bad key"    ));    Ok(())}// Ensures per-metric tag keys are validated.#[test]fn counter_rejects_invalid_tag_key() -> Result<()> {    let metrics = build_in_memory_client()?;    let err = metrics        .counter("codex.turns", /*inc*/ 1, &[("bad key", "value")])        .unwrap_err();    assert!(matches!(        err,        MetricsError::InvalidTagComponent { label, value }            if label == "tag key" && value == "bad key"    ));    metrics.shutdown()?;    Ok(())}// Ensures per-metric tag values are validated.#[test]fn histogram_rejects_invalid_tag_value() -> Result<()> {    let metrics = build_in_memory_client()?;    let err = metrics        .histogram(            "codex.request_latency",            /*value*/ 3,            &[("route", "bad value")],        )        .unwrap_err();    assert!(matches!(        err,        MetricsError::InvalidTagComponent { label, value }            if label == "tag value" && value == "bad value"    ));    metrics.shutdown()?;    Ok(())}// Ensures invalid metric names are rejected.#[test]fn counter_rejects_invalid_metric_name() -> Result<()> {    let metrics = build_in_memory_client()?;    let err = metrics.counter("bad name", /*inc*/ 1, &[]).unwrap_err();    assert!(matches!(        err,        MetricsError::InvalidMetricName { name } if name == "bad name"    ));    metrics.shutdown()?;    Ok(())}#[test]fn counter_rejects_negative_increment() -> Result<()> {    let metrics = build_in_memory_client()?;    let err = metrics.counter("codex.turns", /*inc*/ -1, &[]).unwrap_err();    assert!(matches!(        err,        MetricsError::NegativeCounterIncrement { name, inc } if name == "codex.turns" && inc == -1    ));    metrics.shutdown()?;    Ok(())}