Your browser sucks, JavaScript disabled! Gunnar's console needs JavaScript and WebAssembly. Git over SSH on port 2222 does not.

nordisk/edda

crates/nornir-claude/tests/transport.rs

//! Integration tests exercising `nornir-claude` through the public
//! [`ClaudeTransport`] trait boundary — the same seam a UI host drives.

use nornir_claude::{ClaudeRequest, ClaudeTransport, OfflineTransport, WireMsg};

/// A host holds `Box<dyn ClaudeTransport>` (exactly what `ClaudeTab::new` wants).
/// Drive a full conversation over that boxed seam with no network, no key.
#[test]
fn boxed_offline_transport_drives_a_conversation() {
    let transport: Box<dyn ClaudeTransport> = Box::new(OfflineTransport::echoing());
    let convo = vec![
        WireMsg::user("hello"),
        WireMsg::assistant("hi"),
        WireMsg::user("what is 2+2?"),
    ];
    // Rich typed path.
    let reply = transport.send(&ClaudeRequest::new("claude-opus-4-8", convo.clone())).unwrap();
    assert_eq!(reply, "[offline · claude-opus-4-8] what is 2+2?");
    // Stringly-typed facett-seam-shaped path.
    let reply2 = transport.send_wire("claude-opus-4-8", &convo).unwrap();
    assert_eq!(reply2, reply);
}

/// The session token rides on the request but is NEVER serialized into the body
/// (`x-api-key` is a header) — a `#[serde(skip)]` guard that would leak the key
/// into JSON if broken.
#[test]
fn session_key_is_not_serialized_into_the_request_body() {
    let req = ClaudeRequest::new("claude-opus-4-8", vec![WireMsg::user("x")])
        .with_session_key(Some("sk-ant-secret".into()));
    let json = serde_json::to_string(&req).unwrap();
    assert!(!json.contains("sk-ant-secret"), "session key leaked into body: {json}");
    assert!(json.contains("\"model\":\"claude-opus-4-8\""), "{json}");
}

/// LIVE network round-trip against the real Anthropic API. Gated `#[ignore]` so
/// CI never hits the network; run explicitly with a key:
/// `ANTHROPIC_API_KEY=sk-ant-… cargo test --features http -- --ignored live`.
#[cfg(feature = "http")]
#[test]
#[ignore = "hits the live Anthropic API; needs a credential and network"]
fn live_http_transport_answers() {
    use nornir_claude::HttpTransport;
    let reply = HttpTransport
        .send(&ClaudeRequest::new(
            nornir_claude::DEFAULT_MODEL,
            vec![WireMsg::user("Reply with exactly the word: pong")],
        ))
        .expect("live send failed");
    assert!(!reply.trim().is_empty(), "empty reply");
}