use braintrust_sdk_rust::{
extract_anthropic_usage, extract_openai_usage, BraintrustClient, SpanLog,
};
use serde_json::{json, Value};
use wiremock::matchers::{method, path};
use wiremock::{Mock, MockServer, ResponseTemplate};
#[tokio::test]
async fn span_lifecycle_flushes_to_logs_endpoint() {
let server = MockServer::start().await;
Mock::given(method("POST"))
.and(path("/api/project/register"))
.respond_with(ResponseTemplate::new(200).set_body_json(json!({
"project": { "id": "proj-id" }
})))
.expect(1)
.mount(&server)
.await;
Mock::given(method("POST"))
.and(path("/logs3"))
.respond_with(ResponseTemplate::new(200).set_body_string("{}"))
.mount(&server)
.await;
let client = BraintrustClient::builder()
.api_key("test-key")
.api_url(server.uri())
.app_url(server.uri())
.build()
.await
.expect("client");
let span = client
.span_builder_with_credentials("token", "org-id")
.org_name("org-name")
.project_name("demo-project")
.build();
span.log(SpanLog {
name: Some("integration-span".into()),
input: Some(Value::String("input".into())),
output: Some(Value::String("output".into())),
..Default::default()
})
.await;
span.flush().await.expect("flush");
client.flush().await.expect("client flush");
let logs_requests: Vec<_> = server
.received_requests()
.await
.unwrap()
.into_iter()
.filter(|request| request.url.path() == "/logs3")
.collect();
assert_eq!(logs_requests.len(), 1);
let body: Value = serde_json::from_slice(&logs_requests[0].body).expect("json body");
assert_eq!(body["api_version"], 2);
let row = body["rows"]
.as_array()
.and_then(|rows| rows.first())
.expect("row");
assert_eq!(row["span_attributes"]["name"], "integration-span");
assert_eq!(row["project_id"], "proj-id");
}
#[test]
fn usage_extractors_return_expected_metrics() {
let openai_usage = extract_openai_usage(&json!({
"usage": {
"prompt_tokens": 10,
"completion_tokens": 5,
"total_tokens": 15,
"reasoning_tokens": 2
}
}));
assert_eq!(openai_usage.prompt_tokens, Some(10));
assert_eq!(openai_usage.completion_tokens, Some(5));
assert_eq!(openai_usage.total_tokens, Some(15));
assert_eq!(openai_usage.reasoning_tokens, Some(2));
let anthropic_usage = extract_anthropic_usage(&json!({
"usage": {
"input_tokens": 3,
"output_tokens": 7
}
}));
assert_eq!(anthropic_usage.prompt_tokens, Some(3));
assert_eq!(anthropic_usage.completion_tokens, Some(7));
assert_eq!(anthropic_usage.total_tokens, Some(10));
}