use akribes_sdk::{AkribesClient, AkribesError};
use mockito::Server;
fn make_client(server: &Server) -> AkribesClient {
AkribesClient::builder(server.url())
.name("exec-test")
.id("exec-id")
.build()
}
#[tokio::test]
async fn tasks_hits_route_and_parses_envelope() {
let mut server = Server::new_async().await;
let _m = server
.mock("GET", "/executions/exec_1/tasks")
.with_status(200)
.with_header("content-type", "application/json")
.with_body(
r#"{
"execution_id": "exec_1",
"tasks": [
{
"task_name": "classify",
"model": "gpt-5.4",
"provider": "openai",
"input_tokens": 120,
"output_tokens": 45,
"cached_input_tokens": 10,
"cache_write_input_tokens": 0,
"cost_usd": 0.0021,
"duration_ms": 812,
"attempt": 1,
"finished_at": "2026-01-01T00:00:00Z"
}
]
}"#,
)
.create_async()
.await;
let resp = make_client(&server)
.executions()
.tasks("exec_1")
.await
.unwrap()
.expect("200 should yield Some");
assert_eq!(resp.execution_id, "exec_1");
assert_eq!(resp.tasks.len(), 1);
let t = &resp.tasks[0];
assert_eq!(t.task_name, "classify");
assert_eq!(t.model.as_deref(), Some("gpt-5.4"));
assert_eq!(t.provider.as_deref(), Some("openai"));
assert_eq!(t.input_tokens, 120);
assert_eq!(t.output_tokens, 45);
assert_eq!(t.cached_input_tokens, 10);
assert_eq!(t.cache_write_input_tokens, 0);
assert_eq!(t.cost_usd, Some(0.0021));
assert_eq!(t.duration_ms, Some(812));
assert_eq!(t.attempt, 1);
assert_eq!(t.finished_at, "2026-01-01T00:00:00Z");
}
#[tokio::test]
async fn tasks_404_yields_none() {
let mut server = Server::new_async().await;
let _m = server
.mock("GET", "/executions/missing/tasks")
.with_status(404)
.create_async()
.await;
let resp = make_client(&server)
.executions()
.tasks("missing")
.await
.unwrap();
assert!(resp.is_none(), "404 should map to Ok(None)");
}
#[tokio::test]
async fn document_markdown_returns_string() {
let mut server = Server::new_async().await;
let _m = server
.mock("GET", "/documents/doc_1/markdown")
.with_status(200)
.with_header("content-type", "application/json")
.with_body(r##"{"markdown":"# Title body"}"##)
.create_async()
.await;
let md = make_client(&server)
.executions()
.get_document_markdown("doc_1")
.await
.unwrap();
assert_eq!(md, "# Title body");
}
#[tokio::test]
async fn document_markdown_missing_field_errors() {
let mut server = Server::new_async().await;
let _m = server
.mock("GET", "/documents/doc_2/markdown")
.with_status(200)
.with_header("content-type", "application/json")
.with_body(r#"{"not_markdown":"oops"}"#)
.create_async()
.await;
let err = make_client(&server)
.executions()
.get_document_markdown("doc_2")
.await
.expect_err("missing markdown field should error");
match err {
AkribesError::Other(msg) => {
assert!(msg.contains("doc_2"), "error should mention doc id: {msg}");
assert!(
msg.contains("malformed"),
"error should describe the contract violation: {msg}"
);
}
other => panic!("expected AkribesError::Other, got {other:?}"),
}
}
#[tokio::test]
async fn document_markdown_wrong_type_errors() {
let mut server = Server::new_async().await;
let _m = server
.mock("GET", "/documents/doc_3/markdown")
.with_status(200)
.with_header("content-type", "application/json")
.with_body(r#"{"markdown":null}"#)
.create_async()
.await;
let err = make_client(&server)
.executions()
.get_document_markdown("doc_3")
.await
.expect_err("non-string markdown field should error");
assert!(matches!(err, AkribesError::Other(_)));
}