#![cfg(feature = "_async")]
use std::time::Duration;
use http::StatusCode;
use redfish::{Auth, Client, RetryPolicy};
use wiremock::matchers::{method, path};
use wiremock::{Mock, MockServer, ResponseTemplate};
#[tokio::test]
async fn service_root_get_works() {
let server = MockServer::start().await;
Mock::given(method("GET"))
.and(path("/redfish/v1"))
.respond_with(ResponseTemplate::new(200).set_body_raw(
r#"{"RedfishVersion":"1.9.0","UUID":"test"}"#,
"application/json",
))
.mount(&server)
.await;
let client = Client::builder(&server.uri())
.unwrap()
.auth(Auth::none())
.build()
.unwrap();
let root = client.service_root().get().await.unwrap();
assert_eq!(root.redfish_version, "1.9.0");
assert_eq!(root.uuid.as_deref(), Some("test"));
}
#[tokio::test]
async fn retries_on_503_for_idempotent_methods() {
let server = MockServer::start().await;
Mock::given(method("GET"))
.and(path("/redfish/v1/Systems"))
.respond_with(ResponseTemplate::new(503))
.up_to_n_times(1)
.expect(1)
.mount(&server)
.await;
Mock::given(method("GET"))
.and(path("/redfish/v1/Systems"))
.respond_with(ResponseTemplate::new(200).set_body_raw(
r#"{"Members":[{"@odata.id":"/redfish/v1/Systems/1"}],"Members@odata.count":1}"#,
"application/json",
))
.expect(1)
.mount(&server)
.await;
let retry = RetryPolicy::default()
.with_max_retries(2)
.with_base_delay(Duration::from_millis(1))
.with_max_delay(Duration::from_millis(1))
.with_jitter(false);
let client = Client::builder(&server.uri())
.unwrap()
.retry_policy(retry)
.build()
.unwrap();
let systems = client.systems().list().await.unwrap();
assert_eq!(systems.members.len(), 1);
}
#[tokio::test]
async fn does_not_retry_on_500() {
let server = MockServer::start().await;
Mock::given(method("GET"))
.and(path("/redfish/v1/Systems"))
.respond_with(ResponseTemplate::new(500))
.expect(1)
.mount(&server)
.await;
let retry = RetryPolicy::default()
.with_max_retries(2)
.with_base_delay(Duration::from_millis(1))
.with_max_delay(Duration::from_millis(1))
.with_jitter(false);
let client = Client::builder(&server.uri())
.unwrap()
.retry_policy(retry)
.build()
.unwrap();
let err = client
.systems()
.list()
.await
.expect_err("expected 500 error");
assert_eq!(err.status(), Some(StatusCode::INTERNAL_SERVER_ERROR));
let requests = server.received_requests().await.expect("request history");
assert_eq!(requests.len(), 1);
}
#[tokio::test]
async fn session_create_parses_token_and_location() {
let server = MockServer::start().await;
Mock::given(method("POST"))
.and(path("/redfish/v1/SessionService/Sessions"))
.respond_with(
ResponseTemplate::new(StatusCode::CREATED.as_u16())
.insert_header("X-Auth-Token", "abc123")
.insert_header("Location", "/redfish/v1/SessionService/Sessions/1")
.set_body_raw(
r#"{"Id":"1","Name":"Session","UserName":"admin"}"#,
"application/json",
),
)
.mount(&server)
.await;
let client = Client::builder(&server.uri()).unwrap().build().unwrap();
let login = client.sessions().create("admin", "pw").await.unwrap();
let _auth = redfish::Auth::SessionToken(login.token.clone());
assert_eq!(login.location, "/redfish/v1/SessionService/Sessions/1");
assert_eq!(login.session.unwrap().id.as_deref(), Some("1"));
}