asterdex-sdk 0.1.5

AsterDex Futures SDK v3 — Rust async client for REST and WebSocket APIs
Documentation
// US-006: M1 unit tests — no network required (mockito mock server)
// Run with: cargo test --test m1_unit_tests

use asterdex_sdk::{AsterDexError, FuturesClient};

#[tokio::test]
async fn server_time_returns_millis() {
    let mut server = mockito::Server::new_async().await;
    let _mock = server
        .mock("GET", "/fapi/v3/time")
        .with_status(200)
        .with_header("content-type", "application/json")
        .with_body(r#"{"serverTime":1700000000000}"#)
        .create_async()
        .await;
    let client = FuturesClient::new_public(&server.url()).unwrap();
    let resp = client.get_server_time().await.unwrap();
    assert_eq!(resp.data.server_time, 1_700_000_000_000u64);
}

#[tokio::test]
async fn http_418_maps_to_ip_banned() {
    let mut server = mockito::Server::new_async().await;
    let _mock = server
        .mock("GET", "/fapi/v3/time")
        .with_status(418)
        .with_header("Retry-After", "7200")
        .create_async()
        .await;
    let client = FuturesClient::new_public(&server.url()).unwrap();
    let result = client.get_server_time().await;
    match result {
        Err(AsterDexError::IpBanned { retry_after: Some(d) }) => {
            assert_eq!(d.as_secs(), 7200);
        }
        other => panic!("expected IpBanned(7200s), got: {:?}", other),
    }
}

#[tokio::test]
async fn api_error_body_maps_correctly() {
    let mut server = mockito::Server::new_async().await;
    let _mock = server
        .mock("GET", "/fapi/v3/time")
        .with_status(400)
        .with_header("content-type", "application/json")
        .with_body(r#"{"code":-1102,"msg":"param error"}"#)
        .create_async()
        .await;
    let client = FuturesClient::new_public(&server.url()).unwrap();
    let result = client.get_server_time().await;
    match result {
        Err(AsterDexError::ApiError { code: -1102, msg }) => {
            assert_eq!(msg, "param error");
        }
        other => panic!("expected ApiError(-1102), got: {:?}", other),
    }
}

#[tokio::test]
async fn http_429_maps_to_rate_limited() {
    let mut server = mockito::Server::new_async().await;
    let _mock = server
        .mock("GET", "/fapi/v3/time")
        .with_status(429)
        .with_header("Retry-After", "60")
        .create_async()
        .await;
    let client = FuturesClient::new_public(&server.url()).unwrap();
    let result = client.get_server_time().await;
    match result {
        Err(AsterDexError::RateLimited { retry_after: Some(d) }) => {
            assert_eq!(d.as_secs(), 60);
        }
        other => panic!("expected RateLimited(60s), got: {:?}", other),
    }
}

#[tokio::test]
async fn server_time_ignores_extra_fields() {
    let mut server = mockito::Server::new_async().await;
    let _mock = server
        .mock("GET", "/fapi/v3/time")
        .with_status(200)
        .with_header("content-type", "application/json")
        .with_body(r#"{"serverTime":1700000000000,"timezone":"UTC","extra":"ignored"}"#)
        .create_async()
        .await;
    let client = FuturesClient::new_public(&server.url()).unwrap();
    let resp = client.get_server_time().await.unwrap();
    assert_eq!(resp.data.server_time, 1_700_000_000_000u64);
}