mirror of
https://github.com/logos-blockchain/logos-blockchain-testing.git
synced 2026-01-07 15:53:10 +00:00
core: add non-panicking testing-endpoint APIs
This commit is contained in:
parent
8a6d7236ef
commit
e7093df4e5
@ -21,6 +21,14 @@ use tracing::error;
|
|||||||
pub const DA_GET_TESTING_ENDPOINT_ERROR: &str = "Failed to connect to testing endpoint. The binary was likely built without the 'testing' \
|
pub const DA_GET_TESTING_ENDPOINT_ERROR: &str = "Failed to connect to testing endpoint. The binary was likely built without the 'testing' \
|
||||||
feature. Try: cargo build --workspace --all-features";
|
feature. Try: cargo build --workspace --all-features";
|
||||||
|
|
||||||
|
#[derive(Debug, thiserror::Error)]
|
||||||
|
pub enum ApiClientError {
|
||||||
|
#[error("{DA_GET_TESTING_ENDPOINT_ERROR}")]
|
||||||
|
TestingEndpointUnavailable,
|
||||||
|
#[error(transparent)]
|
||||||
|
Request(#[from] reqwest::Error),
|
||||||
|
}
|
||||||
|
|
||||||
/// Thin async client for node HTTP/testing endpoints.
|
/// Thin async client for node HTTP/testing endpoints.
|
||||||
#[derive(Clone)]
|
#[derive(Clone)]
|
||||||
pub struct ApiClient {
|
pub struct ApiClient {
|
||||||
@ -154,6 +162,26 @@ impl ApiClient {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// POST JSON to the testing API and return the raw response.
|
/// POST JSON to the testing API and return the raw response.
|
||||||
|
pub async fn post_testing_json_response_checked<T>(
|
||||||
|
&self,
|
||||||
|
path: &str,
|
||||||
|
body: &T,
|
||||||
|
) -> Result<Response, ApiClientError>
|
||||||
|
where
|
||||||
|
T: Serialize + Sync + ?Sized,
|
||||||
|
{
|
||||||
|
let testing_url = self
|
||||||
|
.testing_url
|
||||||
|
.as_ref()
|
||||||
|
.ok_or(ApiClientError::TestingEndpointUnavailable)?;
|
||||||
|
self.client
|
||||||
|
.post(Self::join_url(testing_url, path))
|
||||||
|
.json(body)
|
||||||
|
.send()
|
||||||
|
.await
|
||||||
|
.map_err(ApiClientError::Request)
|
||||||
|
}
|
||||||
|
|
||||||
pub async fn post_testing_json_response<T>(
|
pub async fn post_testing_json_response<T>(
|
||||||
&self,
|
&self,
|
||||||
path: &str,
|
path: &str,
|
||||||
@ -162,27 +190,39 @@ impl ApiClient {
|
|||||||
where
|
where
|
||||||
T: Serialize + Sync + ?Sized,
|
T: Serialize + Sync + ?Sized,
|
||||||
{
|
{
|
||||||
let testing_url = self
|
match self.post_testing_json_response_checked(path, body).await {
|
||||||
.testing_url
|
Ok(resp) => Ok(resp),
|
||||||
.as_ref()
|
Err(ApiClientError::Request(err)) => Err(err),
|
||||||
.expect(DA_GET_TESTING_ENDPOINT_ERROR);
|
Err(ApiClientError::TestingEndpointUnavailable) => {
|
||||||
self.client
|
panic!("{DA_GET_TESTING_ENDPOINT_ERROR}")
|
||||||
.post(Self::join_url(testing_url, path))
|
}
|
||||||
.json(body)
|
}
|
||||||
.send()
|
|
||||||
.await
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// GET from the testing API and return the raw response.
|
/// GET from the testing API and return the raw response.
|
||||||
pub async fn get_testing_response(&self, path: &str) -> reqwest::Result<Response> {
|
pub async fn get_testing_response_checked(
|
||||||
|
&self,
|
||||||
|
path: &str,
|
||||||
|
) -> Result<Response, ApiClientError> {
|
||||||
let testing_url = self
|
let testing_url = self
|
||||||
.testing_url
|
.testing_url
|
||||||
.as_ref()
|
.as_ref()
|
||||||
.expect(DA_GET_TESTING_ENDPOINT_ERROR);
|
.ok_or(ApiClientError::TestingEndpointUnavailable)?;
|
||||||
self.client
|
self.client
|
||||||
.get(Self::join_url(testing_url, path))
|
.get(Self::join_url(testing_url, path))
|
||||||
.send()
|
.send()
|
||||||
.await
|
.await
|
||||||
|
.map_err(ApiClientError::Request)
|
||||||
|
}
|
||||||
|
|
||||||
|
pub async fn get_testing_response(&self, path: &str) -> reqwest::Result<Response> {
|
||||||
|
match self.get_testing_response_checked(path).await {
|
||||||
|
Ok(resp) => Ok(resp),
|
||||||
|
Err(ApiClientError::Request(err)) => Err(err),
|
||||||
|
Err(ApiClientError::TestingEndpointUnavailable) => {
|
||||||
|
panic!("{DA_GET_TESTING_ENDPOINT_ERROR}")
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Block a peer via the DA testing API.
|
/// Block a peer via the DA testing API.
|
||||||
@ -258,6 +298,19 @@ impl ApiClient {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// Query DA membership via testing API.
|
/// Query DA membership via testing API.
|
||||||
|
pub async fn da_get_membership_checked(
|
||||||
|
&self,
|
||||||
|
session_id: &SessionNumber,
|
||||||
|
) -> Result<MembershipResponse, ApiClientError> {
|
||||||
|
self.post_testing_json_response_checked(DA_GET_MEMBERSHIP, session_id)
|
||||||
|
.await?
|
||||||
|
.error_for_status()
|
||||||
|
.map_err(ApiClientError::Request)?
|
||||||
|
.json()
|
||||||
|
.await
|
||||||
|
.map_err(ApiClientError::Request)
|
||||||
|
}
|
||||||
|
|
||||||
pub async fn da_get_membership(
|
pub async fn da_get_membership(
|
||||||
&self,
|
&self,
|
||||||
session_id: &SessionNumber,
|
session_id: &SessionNumber,
|
||||||
|
|||||||
@ -5,7 +5,7 @@ pub mod validator;
|
|||||||
|
|
||||||
use std::sync::LazyLock;
|
use std::sync::LazyLock;
|
||||||
|
|
||||||
pub use api_client::ApiClient;
|
pub use api_client::{ApiClient, ApiClientError};
|
||||||
use tempfile::TempDir;
|
use tempfile::TempDir;
|
||||||
|
|
||||||
pub(crate) const LOGS_PREFIX: &str = "__logs";
|
pub(crate) const LOGS_PREFIX: &str = "__logs";
|
||||||
|
|||||||
@ -4,7 +4,7 @@ use reqwest::{Client, Url};
|
|||||||
use thiserror::Error;
|
use thiserror::Error;
|
||||||
|
|
||||||
use super::ReadinessCheck;
|
use super::ReadinessCheck;
|
||||||
use crate::topology::deployment::Topology;
|
use crate::{nodes::ApiClientError, topology::deployment::Topology};
|
||||||
|
|
||||||
#[derive(Debug, Error)]
|
#[derive(Debug, Error)]
|
||||||
pub enum MembershipError {
|
pub enum MembershipError {
|
||||||
@ -15,7 +15,9 @@ pub enum MembershipError {
|
|||||||
message: String,
|
message: String,
|
||||||
},
|
},
|
||||||
#[error(transparent)]
|
#[error(transparent)]
|
||||||
Request(#[from] reqwest::Error),
|
Http(#[from] reqwest::Error),
|
||||||
|
#[error(transparent)]
|
||||||
|
ApiClient(#[from] ApiClientError),
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
@ -50,7 +52,7 @@ impl<'a> ReadinessCheck<'a> for MembershipReadiness<'a> {
|
|||||||
async move {
|
async move {
|
||||||
let result = node
|
let result = node
|
||||||
.api()
|
.api()
|
||||||
.da_get_membership(&self.session)
|
.da_get_membership_checked(&self.session)
|
||||||
.await
|
.await
|
||||||
.map_err(MembershipError::from);
|
.map_err(MembershipError::from);
|
||||||
NodeMembershipStatus { label, result }
|
NodeMembershipStatus { label, result }
|
||||||
@ -72,7 +74,7 @@ impl<'a> ReadinessCheck<'a> for MembershipReadiness<'a> {
|
|||||||
async move {
|
async move {
|
||||||
let result = node
|
let result = node
|
||||||
.api()
|
.api()
|
||||||
.da_get_membership(&self.session)
|
.da_get_membership_checked(&self.session)
|
||||||
.await
|
.await
|
||||||
.map_err(MembershipError::from);
|
.map_err(MembershipError::from);
|
||||||
NodeMembershipStatus { label, result }
|
NodeMembershipStatus { label, result }
|
||||||
@ -164,12 +166,12 @@ pub async fn try_fetch_membership(
|
|||||||
.json(&session)
|
.json(&session)
|
||||||
.send()
|
.send()
|
||||||
.await
|
.await
|
||||||
.map_err(MembershipError::Request)?
|
.map_err(MembershipError::Http)?
|
||||||
.error_for_status()
|
.error_for_status()
|
||||||
.map_err(MembershipError::Request)?
|
.map_err(MembershipError::Http)?
|
||||||
.json()
|
.json()
|
||||||
.await
|
.await
|
||||||
.map_err(MembershipError::Request)
|
.map_err(MembershipError::Http)
|
||||||
}
|
}
|
||||||
|
|
||||||
#[deprecated(note = "use try_fetch_membership to avoid panics and preserve error details")]
|
#[deprecated(note = "use try_fetch_membership to avoid panics and preserve error details")]
|
||||||
@ -181,7 +183,7 @@ pub async fn fetch_membership(
|
|||||||
try_fetch_membership(client, base, session)
|
try_fetch_membership(client, base, session)
|
||||||
.await
|
.await
|
||||||
.map_err(|err| match err {
|
.map_err(|err| match err {
|
||||||
MembershipError::Request(source) => source,
|
MembershipError::Http(source) => source,
|
||||||
MembershipError::JoinUrl {
|
MembershipError::JoinUrl {
|
||||||
base,
|
base,
|
||||||
path,
|
path,
|
||||||
@ -189,6 +191,7 @@ pub async fn fetch_membership(
|
|||||||
} => {
|
} => {
|
||||||
panic!("failed to join url {base} with path {path}: {message}")
|
panic!("failed to join url {base} with path {path}: {message}")
|
||||||
}
|
}
|
||||||
|
MembershipError::ApiClient(err) => panic!("{err}"),
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user