Codex Handbook
app-server-test-client/src/plugin_analytics_capture_tests.rs 93 lines
use super::PluginEventIdentity;use super::read_events_for_remote_plugin;use super::validate_mutation_events;use serde_json::Value;use serde_json::json;use std::fs;use std::path::PathBuf;use std::process;use std::time::SystemTime;const REMOTE_PLUGIN_ID: &str = "plugins~Plugin_test";#[test]fn reads_and_validates_remote_plugin_mutation_events() {    let path = unique_capture_path("valid");    let installed = mutation_event("codex_plugin_installed");    let unrelated = json!({        "event_type": "codex_plugin_installed",        "event_params": {            "plugin_id": "plugins~Plugin_other"        }    });    let contents = [        json!({"events": [unrelated]}),        json!({"events": [installed]}),    ]    .into_iter()    .map(|payload| serde_json::to_string(&payload).expect("serialize capture payload"))    .collect::<Vec<_>>()    .join("\n");    fs::write(&path, contents).expect("write capture file");    let events = read_events_for_remote_plugin(&path, REMOTE_PLUGIN_ID)        .expect("read matching plugin events");    let validated =        validate_mutation_events(events, expected_identity()).expect("validate mutation events");    assert_eq!(validated, vec![installed]);    fs::remove_file(path).expect("remove capture file");}#[test]fn rejects_duplicate_mutation_events() {    let installed = mutation_event("codex_plugin_installed");    let error = validate_mutation_events(vec![installed.clone(), installed], expected_identity())        .expect_err("duplicate install events should fail validation");    assert!(error.to_string().contains("found 2"));}#[test]fn rejects_missing_capability_metadata() {    let mut installed = mutation_event("codex_plugin_installed");    installed["event_params"]["has_skills"] = Value::Null;    let error = validate_mutation_events(vec![installed], expected_identity())        .expect_err("missing capability metadata should fail validation");    assert!(error.to_string().contains("has_skills"));}fn mutation_event(event_type: &str) -> Value {    json!({        "event_type": event_type,        "event_params": {            "plugin_id": REMOTE_PLUGIN_ID,            "plugin_name": "sample",            "marketplace_name": "openai-curated-remote",            "has_skills": true,            "mcp_server_count": 0,            "connector_ids": [],            "product_client_id": "test-client"        }    })}fn expected_identity() -> PluginEventIdentity<'static> {    PluginEventIdentity {        plugin_id: REMOTE_PLUGIN_ID,        plugin_name: "sample",        marketplace_name: "openai-curated-remote",    }}fn unique_capture_path(name: &str) -> PathBuf {    let nonce = SystemTime::now()        .duration_since(SystemTime::UNIX_EPOCH)        .expect("system clock should be after Unix epoch")        .as_nanos();    std::env::temp_dir().join(format!(        "codex-plugin-analytics-capture-{name}-{}-{nonce}.jsonl",        process::id()    ))}