@@ -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