use mockito::{Matcher, Server};
use polyoxide_binance::spot::{Spot, SpotError};
use polyoxide_core::RetryConfig;
use polyoxide_test_support::fixtures;
use polyoxide_venue::{Class, Classify};
async fn fail(status: usize, body: &str) -> SpotError {
let mut server = Server::new_async().await;
let _mock = server
.mock("GET", "/api/v3/time")
.match_query(Matcher::Any)
.with_status(status)
.with_body(body)
.create_async()
.await;
let spot = Spot::builder()
.base_url(server.url())
.with_retry_config(RetryConfig {
max_retries: 0,
..RetryConfig::default()
})
.build()
.unwrap();
spot.health().time().send().await.unwrap_err()
}
#[tokio::test]
async fn every_status_reaches_the_caller_with_its_class() {
let refusal = Class::VenueRefusal { code: None };
let unavailable = Class::Unavailable { code: None };
let rows = [
(400, refusal.clone(), true),
(401, Class::Unauthorized, true),
(403, Class::Restricted, true),
(404, refusal, true),
(408, unavailable.clone(), true),
(418, Class::Restricted, true),
(425, unavailable.clone(), true),
(429, Class::RateLimited { retry_after: None }, true),
(451, Class::Restricted, false),
(500, unavailable.clone(), true),
(503, unavailable, true),
];
for (status, class, fault) in rows {
let err = fail(status, "<html>x</html>").await;
assert_eq!(err.class(), class, "{status}: {err:?}");
assert_eq!(err.is_fault(), fault, "{status}: {err:?}");
}
}
#[tokio::test]
async fn binance_s_body_carries_its_code_into_the_class() {
let err = fail(400, r#"{"code":-1121,"msg":"Invalid symbol."}"#).await;
assert_eq!(
err.class(),
Class::VenueRefusal {
code: Some(std::sync::Arc::from("-1121"))
},
"{err:?}"
);
assert!(err.is_fault(), "{err:?}");
}
#[tokio::test]
async fn the_captured_invalid_symbol_body_carries_its_code_into_the_class() {
let err = fail(400, &fixtures!("spot/rest").text("error_invalid_symbol")).await;
assert_eq!(
err.class(),
Class::VenueRefusal {
code: Some(std::sync::Arc::from("-1121"))
},
"{err:?}"
);
assert_eq!(err.code(), Some(-1121));
}
#[tokio::test]
async fn a_2xx_body_that_does_not_decode_is_decode() {
let err = fail(200, "not json").await;
assert_eq!(err.class(), Class::Decode, "{err:?}");
assert!(err.is_fault(), "{err:?}");
}