Skip to content

Commit 1b54666

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 aea5808 commit 1b54666

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
@@ -360,22 +360,27 @@ mod test {
360360

361361
/// Setup both [`BlockingClient`] and [`AsyncClient`].
362362
fn setup_clients(&self) -> (BlockingClient, AsyncClient) {
363-
self.setup_clients_with_headers(HashMap::new())
363+
self.setup_clients_with_headers(
364+
self.electrsd.esplora_url.as_ref().unwrap(),
365+
HashMap::new(),
366+
)
364367
}
365368

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
}
@@ -1094,14 +1099,41 @@ mod test {
10941099

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

11061138
let address = env.get_legacy_address();
11071139
let txid = env
@@ -1112,9 +1144,45 @@ mod test {
11121144
.unwrap();
11131145
env.mine_and_wait(1);
11141146

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

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

0 commit comments

Comments
 (0)