mod common; use outline::ErrorKind; use serde_json::json; use wiremock::matchers::{method, path}; use wiremock::{Mock, MockServer, ResponseTemplate}; #[tokio::test] async fn maps_401_to_unauthenticated() { let server = MockServer::start().await; let client = common::client_for(&server).await; Mock::given(method("POST")) .and(path("/api/auth.info")) .respond_with(ResponseTemplate::new(401).set_body_json(json!({ "ok": false, "status": 401, "error": "authentication_required", "message": "Authentication required" }))) .mount(&server) .await; let err = client.auth().info().await.unwrap_err(); assert_eq!(err.kind(), ErrorKind::Unauthenticated); assert_eq!(err.status(), Some(http::StatusCode::UNAUTHORIZED)); assert!(!err.is_retryable()); } #[tokio::test] async fn maps_404_to_not_found() { let server = MockServer::start().await; let client = common::client_for(&server).await; Mock::given(method("POST")) .and(path("/api/collections.info")) .respond_with(ResponseTemplate::new(404).set_body_json(json!({ "ok": false, "status": 404, "error": "not_found", "message": "Collection not found" }))) .mount(&server) .await; let err = client.collections().info("missing-id").await.unwrap_err(); assert!(err.is_not_found()); assert_eq!(err.kind(), ErrorKind::NotFound); } #[tokio::test] async fn maps_429_to_rate_limited_and_parses_retry_after() { let server = MockServer::start().await; let client = common::client_for(&server).await; Mock::given(method("POST")) .and(path("/api/documents.list")) .respond_with( ResponseTemplate::new(429) .insert_header("Retry-After", "12") .set_body_json(json!({ "ok": false, "status": 429, "error": "rate_limit_exceeded", "message": "Rate limit exceeded" })), ) .mount(&server) .await; let err = client.documents().list().send().await.unwrap_err(); assert_eq!(err.kind(), ErrorKind::RateLimited); assert!(err.is_retryable()); assert_eq!(err.retry_after(), Some(std::time::Duration::from_secs(12))); } #[tokio::test] async fn maps_5xx_to_server_error() { let server = MockServer::start().await; let client = common::client_for(&server).await; Mock::given(method("POST")) .and(path("/api/auth.info")) .respond_with(ResponseTemplate::new(503).set_body_string("Service Unavailable")) .mount(&server) .await; let err = client.auth().info().await.unwrap_err(); assert_eq!(err.kind(), ErrorKind::Server); assert!(err.is_retryable()); } #[tokio::test] async fn malformed_success_body_yields_decode_error() { let server = MockServer::start().await; let client = common::client_for(&server).await; Mock::given(method("POST")) .and(path("/api/auth.info")) .respond_with(ResponseTemplate::new(200).set_body_string("not json")) .mount(&server) .await; let err = client.auth().info().await.unwrap_err(); assert_eq!(err.kind(), ErrorKind::Decode); }