This makes the tests much less brittle, by not depending on the exact order of the HTTP headers, nor always requiring to check for every single header.
		
			
				
	
	
		
			81 lines
		
	
	
		
			2.1 KiB
		
	
	
	
		
			Rust
		
	
	
	
	
	
			
		
		
	
	
			81 lines
		
	
	
		
			2.1 KiB
		
	
	
	
		
			Rust
		
	
	
	
	
	
| use std::convert::Infallible;
 | |
| use std::future::Future;
 | |
| use std::net;
 | |
| use std::sync::mpsc as std_mpsc;
 | |
| use std::thread;
 | |
| use std::time::Duration;
 | |
| 
 | |
| use tokio::sync::oneshot;
 | |
| 
 | |
| pub use http::Response;
 | |
| 
 | |
| pub struct Server {
 | |
|     addr: net::SocketAddr,
 | |
|     panic_rx: std_mpsc::Receiver<()>,
 | |
|     shutdown_tx: Option<oneshot::Sender<()>>,
 | |
| }
 | |
| 
 | |
| impl Server {
 | |
|     pub fn addr(&self) -> net::SocketAddr {
 | |
|         self.addr
 | |
|     }
 | |
| }
 | |
| 
 | |
| impl Drop for Server {
 | |
|     fn drop(&mut self) {
 | |
|         if let Some(tx) = self.shutdown_tx.take() {
 | |
|             let _ = tx.send(());
 | |
|         }
 | |
| 
 | |
|         if !::std::thread::panicking() {
 | |
|             self.panic_rx
 | |
|                 .recv_timeout(Duration::from_secs(3))
 | |
|                 .expect("test server should not panic");
 | |
|         }
 | |
|     }
 | |
| }
 | |
| 
 | |
| pub fn http<F, Fut>(func: F) -> Server
 | |
| where
 | |
|     F: Fn(http::Request<hyper::Body>) -> Fut + Clone + Send + 'static,
 | |
|     Fut: Future<Output = http::Response<hyper::Body>> + Send + 'static,
 | |
| {
 | |
|     let srv = hyper::Server::bind(&([127, 0, 0, 1], 0).into()).serve(
 | |
|         hyper::service::make_service_fn(move |_| {
 | |
|             let func = func.clone();
 | |
|             async move {
 | |
|                 Ok::<_, Infallible>(hyper::service::service_fn(move |req| {
 | |
|                     let fut = func(req);
 | |
|                     async move { Ok::<_, Infallible>(fut.await) }
 | |
|                 }))
 | |
|             }
 | |
|         }),
 | |
|     );
 | |
| 
 | |
|     let addr = srv.local_addr();
 | |
|     let (shutdown_tx, shutdown_rx) = oneshot::channel();
 | |
|     let srv = srv.with_graceful_shutdown(async move {
 | |
|         let _ = shutdown_rx.await;
 | |
|     });
 | |
| 
 | |
|     let (panic_tx, panic_rx) = std_mpsc::channel();
 | |
|     let tname = format!(
 | |
|         "test({})-support-server",
 | |
|         thread::current().name().unwrap_or("<unknown>")
 | |
|     );
 | |
|     thread::Builder::new()
 | |
|         .name(tname)
 | |
|         .spawn(move || {
 | |
|             let mut rt = tokio::runtime::current_thread::Runtime::new().expect("rt new");
 | |
|             rt.block_on(srv).unwrap();
 | |
|             let _ = panic_tx.send(());
 | |
|         })
 | |
|         .expect("thread spawn");
 | |
| 
 | |
|     Server {
 | |
|         addr,
 | |
|         panic_rx,
 | |
|         shutdown_tx: Some(shutdown_tx),
 | |
|     }
 | |
| }
 |