Skip to content

Commit 5bdab27

Browse files
luisschwaboleonardolima
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 d9c2a1f commit 5bdab27

File tree

1 file changed

+84
-16
lines changed

1 file changed

+84
-16
lines changed

src/lib.rs

Lines changed: 84 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -359,23 +359,28 @@ mod test {
359359
#[cfg(all(feature = "blocking", feature = "async"))]
360360
/// Setup both [`BlockingClient`] and [`AsyncClient`].
361361
fn setup_clients(&self) -> (BlockingClient, AsyncClient) {
362-
self.setup_clients_with_headers(HashMap::new())
362+
self.setup_clients_with_headers(
363+
self.electrsd.esplora_url.as_ref().unwrap(),
364+
HashMap::new(),
365+
)
363366
}
364367

365368
#[cfg(all(feature = "blocking", feature = "async"))]
366369
/// Setup both [`BlockingClient`] and [`AsyncClient`] with custom HTTP headers.
367370
fn setup_clients_with_headers(
368371
&self,
372+
url: &str,
369373
headers: HashMap<String, String>,
370374
) -> (BlockingClient, AsyncClient) {
371-
let esplora_url = self.electrsd.esplora_url.as_ref().unwrap();
372-
373-
let mut builder = Builder::new(&format!("http://{esplora_url}"));
375+
let mut builder = Builder::new(&format!("http://{url}"));
374376
for (k, v) in &headers {
375377
builder = builder.header(k, v);
376378
}
377-
let blocking_client = builder.clone().build_blocking();
378-
let async_client = builder.build_async().unwrap();
379+
let blocking_client = builder
380+
.clone()
381+
.header("User-Agent", "blocking")
382+
.build_blocking();
383+
let async_client = builder.header("User-Agent", "async").build_async().unwrap();
379384

380385
(blocking_client, async_client)
381386
}
@@ -1069,14 +1074,41 @@ mod test {
10691074

10701075
#[cfg(all(feature = "blocking", feature = "async"))]
10711076
#[tokio::test]
1072-
async fn test_get_tx_with_http_header() {
1077+
async fn test_get_tx_with_http_headers() {
1078+
use corepc_node::get_available_port;
1079+
use tokio::io::AsyncReadExt;
1080+
use tokio::net::TcpListener;
1081+
1082+
async fn handle_requests(listener: TcpListener, count: usize) -> Vec<[u8; 4096]> {
1083+
let mut raw_requests = vec![];
1084+
for _ in 0..count {
1085+
let (mut stream, _) = listener.accept().await.expect("should accept connection!");
1086+
let mut buf = [0u8; 4096];
1087+
AsyncReadExt::read(&mut stream, &mut buf)
1088+
.await
1089+
.expect("should read from stream");
1090+
raw_requests.push(buf);
1091+
}
1092+
raw_requests
1093+
}
1094+
1095+
// setup a mocked HTTP server.
1096+
let base_url = format!(
1097+
"127.0.0.1:{}",
1098+
get_available_port().expect("should get an available port successfully!")
1099+
);
1100+
1101+
let listener = TcpListener::bind(&base_url)
1102+
.await
1103+
.expect("should bind the TCP listener successfully");
1104+
1105+
// setup `TestEnv` and expected HTTP headers.
10731106
let env = TestEnv::new();
1074-
let headers = [(
1075-
"Authorization".to_string(),
1076-
"Basic QWxhZGRpbjpvcGVuIHNlc2FtZQ==".to_string(),
1077-
)]
1078-
.into();
1079-
let (blocking_client, async_client) = env.setup_clients_with_headers(headers);
1107+
let exp_header_key = "Authorization";
1108+
let exp_header_value = "Basic QWxhZGRpbjpvcGVuIHNlc2FtZQ==";
1109+
let headers = HashMap::from([(exp_header_key.to_string(), exp_header_value.to_string())]);
1110+
1111+
let (blocking_client, async_client) = env.setup_clients_with_headers(&base_url, headers);
10801112

10811113
let address = env.get_legacy_address();
10821114
let txid = env
@@ -1087,9 +1119,45 @@ mod test {
10871119
.unwrap();
10881120
env.mine_and_wait(1);
10891121

1090-
let tx = blocking_client.get_tx(&txid).unwrap();
1091-
let tx_async = async_client.get_tx(&txid).await.unwrap();
1092-
assert_eq!(tx, tx_async);
1122+
let blocking_task = tokio::task::spawn_blocking(move || blocking_client.get_tx(&txid));
1123+
let async_task = tokio::task::spawn(async move { async_client.get_tx(&txid).await });
1124+
1125+
let raw_requests = handle_requests(listener, 2).await;
1126+
let requests = raw_requests
1127+
.iter()
1128+
.map(|raw| {
1129+
String::from_utf8(raw.to_vec()).expect("should parse HTTP requests successfully")
1130+
})
1131+
.collect::<Vec<String>>();
1132+
1133+
assert_eq!(
1134+
requests.len(),
1135+
2,
1136+
"it MUST contain ONLY two requests (i.e a single one from each client)"
1137+
);
1138+
1139+
let assert_request = |user_agent: &str, header_key: &str| {
1140+
let expected_path = format!("GET /tx/{txid}/raw");
1141+
let expected_auth = format!("{header_key}: {exp_header_value}");
1142+
1143+
assert!(
1144+
requests.iter().any(|req| {
1145+
req.contains(&expected_path)
1146+
&& req.contains(&expected_auth)
1147+
&& req.contains(user_agent)
1148+
}),
1149+
"request MUST call `{expected_path}` with `{user_agent}` and expected authorization header"
1150+
);
1151+
};
1152+
1153+
// minreq's blocking client sends title-case headers: "Authorization"
1154+
assert_request("User-Agent: blocking", exp_header_key);
1155+
// reqwest's async client sends lowercase headers: "authorization"
1156+
assert_request("user-agent: async", &exp_header_key.to_lowercase());
1157+
1158+
// cleanup any remaining spawned tasks
1159+
let _ = blocking_task.await.expect("blocking task should not panic");
1160+
let _ = async_task.await.expect("async task should not panic");
10931161
}
10941162

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

0 commit comments

Comments
 (0)