Skip to content

Commit 5748132

Browse files
oleonardolimaluisschwab
authored andcommitted
refactor(test): properly assert for HTTP headers
- updates the `test_get_tx_with_http_header` to assert for expected HTTP headers in final request. - updates `setup_clients_with_headers` to expect custom `url`.
1 parent ed9d7ad commit 5748132

1 file changed

Lines changed: 84 additions & 16 deletions

File tree

src/lib.rs

Lines changed: 84 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -358,22 +358,27 @@ mod test {
358358

359359
/// Setup both [`BlockingClient`] and [`AsyncClient`].
360360
fn setup_clients(&self) -> (BlockingClient, AsyncClient) {
361-
self.setup_clients_with_headers(HashMap::new())
361+
self.setup_clients_with_headers(
362+
self.electrsd.esplora_url.as_ref().unwrap(),
363+
HashMap::new(),
364+
)
362365
}
363366

364367
/// Setup both [`BlockingClient`] and [`AsyncClient`] with custom HTTP headers.
365368
fn setup_clients_with_headers(
366369
&self,
370+
url: &str,
367371
headers: HashMap<String, String>,
368372
) -> (BlockingClient, AsyncClient) {
369-
let esplora_url = self.electrsd.esplora_url.as_ref().unwrap();
370-
371-
let mut builder = Builder::new(&format!("http://{esplora_url}"));
373+
let mut builder = Builder::new(&format!("http://{url}"));
372374
for (k, v) in &headers {
373375
builder = builder.header(k, v);
374376
}
375-
let blocking_client = builder.clone().build_blocking();
376-
let async_client = builder.build_async().unwrap();
377+
let blocking_client = builder
378+
.clone()
379+
.header("User-Agent", "blocking")
380+
.build_blocking();
381+
let async_client = builder.header("User-Agent", "async").build_async().unwrap();
377382

378383
(blocking_client, async_client)
379384
}
@@ -1092,14 +1097,41 @@ mod test {
10921097

10931098
#[cfg(all(feature = "blocking", feature = "async"))]
10941099
#[tokio::test]
1095-
async fn test_get_tx_with_http_header() {
1100+
async fn test_get_tx_with_http_headers() {
1101+
use corepc_node::get_available_port;
1102+
use tokio::io::AsyncReadExt;
1103+
use tokio::net::TcpListener;
1104+
1105+
async fn handle_requests(listener: TcpListener, count: usize) -> Vec<[u8; 4096]> {
1106+
let mut raw_requests = vec![];
1107+
for _ in 0..count {
1108+
let (mut stream, _) = listener.accept().await.expect("should accept connection!");
1109+
let mut buf = [0u8; 4096];
1110+
AsyncReadExt::read(&mut stream, &mut buf)
1111+
.await
1112+
.expect("should read from stream");
1113+
raw_requests.push(buf);
1114+
}
1115+
raw_requests
1116+
}
1117+
1118+
// setup a mocked HTTP server.
1119+
let base_url = format!(
1120+
"127.0.0.1:{}",
1121+
get_available_port().expect("should get an available port successfully!")
1122+
);
1123+
1124+
let listener = TcpListener::bind(&base_url)
1125+
.await
1126+
.expect("should bind the TCP listener successfully");
1127+
1128+
// setup `TestEnv` and expected HTTP headers.
10961129
let env = TestEnv::new();
1097-
let headers = [(
1098-
"Authorization".to_string(),
1099-
"Basic QWxhZGRpbjpvcGVuIHNlc2FtZQ==".to_string(),
1100-
)]
1101-
.into();
1102-
let (blocking_client, async_client) = env.setup_clients_with_headers(headers);
1130+
let exp_header_key = "Authorization";
1131+
let exp_header_value = "Basic QWxhZGRpbjpvcGVuIHNlc2FtZQ==";
1132+
let headers = HashMap::from([(exp_header_key.to_string(), exp_header_value.to_string())]);
1133+
1134+
let (blocking_client, async_client) = env.setup_clients_with_headers(&base_url, headers);
11031135

11041136
let address = env.get_legacy_address();
11051137
let txid = env
@@ -1110,9 +1142,45 @@ mod test {
11101142
.unwrap();
11111143
env.mine_and_wait(1);
11121144

1113-
let tx = blocking_client.get_tx(&txid).unwrap();
1114-
let tx_async = async_client.get_tx(&txid).await.unwrap();
1115-
assert_eq!(tx, tx_async);
1145+
let blocking_task = tokio::task::spawn_blocking(move || blocking_client.get_tx(&txid));
1146+
let async_task = tokio::task::spawn(async move { async_client.get_tx(&txid).await });
1147+
1148+
let raw_requests = handle_requests(listener, 2).await;
1149+
let requests = raw_requests
1150+
.iter()
1151+
.map(|raw| {
1152+
String::from_utf8(raw.to_vec()).expect("should parse HTTP requests successfully")
1153+
})
1154+
.collect::<Vec<String>>();
1155+
1156+
assert_eq!(
1157+
requests.len(),
1158+
2,
1159+
"it MUST contain ONLY two requests (i.e a single one from each client)"
1160+
);
1161+
1162+
let assert_request = |user_agent: &str, header_key: &str| {
1163+
let expected_path = format!("GET /tx/{txid}/raw");
1164+
let expected_auth = format!("{header_key}: {exp_header_value}");
1165+
1166+
assert!(
1167+
requests.iter().any(|req| {
1168+
req.contains(&expected_path)
1169+
&& req.contains(&expected_auth)
1170+
&& req.contains(user_agent)
1171+
}),
1172+
"request MUST call `{expected_path}` with `{user_agent}` and expected authorization header"
1173+
);
1174+
};
1175+
1176+
// minreq's blocking client sends title-case headers: "Authorization"
1177+
assert_request("User-Agent: blocking", exp_header_key);
1178+
// reqwest's async client sends lowercase headers: "authorization"
1179+
assert_request("user-agent: async", &exp_header_key.to_lowercase());
1180+
1181+
// cleanup any remaining spawned tasks
1182+
let _ = blocking_task.await.expect("blocking task should not panic");
1183+
let _ = async_task.await.expect("async task should not panic");
11161184
}
11171185

11181186
#[cfg(all(feature = "blocking", feature = "async"))]

0 commit comments

Comments
 (0)