Skip to content

Commit 65d1324

Browse files
apollo_l1_gas_price: rate oracle query checks status code (#13417)
1 parent 2e1f541 commit 65d1324

2 files changed

Lines changed: 52 additions & 1 deletion

File tree

crates/apollo_l1_gas_price/src/exchange_rate_oracle.rs

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -125,6 +125,13 @@ impl ExchangeRateOracleClient {
125125
.headers(headers.peek_secret().clone())
126126
.send()
127127
.await?;
128+
if !response.status().is_success() {
129+
return Err(ExchangeRateOracleClientError::RequestError(format!(
130+
"Request failed with status {}: {}",
131+
response.status(),
132+
response.text().await?
133+
)));
134+
}
128135
let body = response.text().await?;
129136
let rate = resolve_query(body)?;
130137
Ok::<_, ExchangeRateOracleClientError>(rate)

crates/apollo_l1_gas_price/src/exchange_rate_oracle_test.rs

Lines changed: 45 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -12,8 +12,17 @@ use url::Url;
1212
use crate::exchange_rate_oracle::{ExchangeRateOracleClient, ExchangeRateOracleConfig};
1313

1414
async fn make_server(server: &mut ServerGuard, body: serde_json::Value) -> Mock {
15+
make_server_with_status(server, body, 200).await
16+
}
17+
18+
async fn make_server_with_status(
19+
server: &mut ServerGuard,
20+
body: serde_json::Value,
21+
status: usize,
22+
) -> Mock {
1523
server
16-
.mock("GET", mockito::Matcher::Any) // Match any GET request.
24+
.mock("GET", mockito::Matcher::Any)
25+
.with_status(status)
1726
.with_header("Content-Type", "application/json")
1827
.with_body(body.to_string())
1928
.create()
@@ -219,3 +228,38 @@ async fn eth_to_fri_rate_two_urls() {
219228
tokio::task::yield_now().await; // Don't block the executor.
220229
}
221230
}
231+
232+
#[tokio::test]
233+
async fn eth_to_fri_rate_non_success_status_code() {
234+
const LAG_INTERVAL_SECONDS: u64 = 60;
235+
const TIMESTAMP: u64 = 1234567890;
236+
237+
let mut server = mockito::Server::new_async().await;
238+
239+
let _mock_response =
240+
make_server_with_status(&mut server, json!({"error": "rate limit exceeded"}), 429).await;
241+
242+
let url_and_headers =
243+
UrlAndHeaders { url: Url::parse(&server.url()).unwrap(), headers: BTreeMap::new() };
244+
let config = ExchangeRateOracleConfig {
245+
url_header_list: Some(vec![url_and_headers.into()]),
246+
lag_interval_seconds: LAG_INTERVAL_SECONDS,
247+
..Default::default()
248+
};
249+
let client = ExchangeRateOracleClient::new(config);
250+
251+
// First call triggers the background query and returns QueryNotReadyError.
252+
assert!(matches!(
253+
client.fetch_rate(TIMESTAMP).await,
254+
Err(ExchangeRateOracleClientError::QueryNotReadyError(_))
255+
));
256+
// Wait for the query to resolve with AllUrlsFailedError.
257+
loop {
258+
match client.fetch_rate(TIMESTAMP).await {
259+
Err(ExchangeRateOracleClientError::QueryNotReadyError(_)) => {}
260+
Err(ExchangeRateOracleClientError::AllUrlsFailedError(..)) => break,
261+
other => panic!("Expected AllUrlsFailedError, got: {other:?}"),
262+
}
263+
tokio::task::yield_now().await;
264+
}
265+
}

0 commit comments

Comments
 (0)