@@ -5,9 +5,15 @@ use std::net::SocketAddr;
55use tokio:: net:: TcpStream ;
66
77async fn start_test_server ( ) -> ( SocketAddr , tokio:: sync:: oneshot:: Sender < ( ) > ) {
8+ start_test_server_with_upstream ( "http://127.0.0.1:1" ) . await
9+ }
10+
11+ async fn start_test_server_with_upstream (
12+ upstream : & str ,
13+ ) -> ( SocketAddr , tokio:: sync:: oneshot:: Sender < ( ) > ) {
814 let config = s3_cache:: Config {
915 listen_addr : "127.0.0.1:0" . parse ( ) . unwrap ( ) ,
10- upstream_endpoint : "http://127.0.0.1:1" . to_string ( ) ,
16+ upstream_endpoint : upstream . to_string ( ) ,
1117 upstream_access_key_id : "test" . to_string ( ) ,
1218 upstream_secret_access_key : "test" . to_string ( ) ,
1319 upstream_region : "us-east-1" . to_string ( ) ,
@@ -60,6 +66,37 @@ async fn http_get(addr: SocketAddr, path: &str) -> (u16, String) {
6066 ( status, String :: from_utf8_lossy ( & body) . to_string ( ) )
6167}
6268
69+ async fn start_fake_upstream ( status : u16 ) -> ( SocketAddr , tokio:: sync:: oneshot:: Sender < ( ) > ) {
70+ let listener = tokio:: net:: TcpListener :: bind ( "127.0.0.1:0" ) . await . unwrap ( ) ;
71+ let addr = listener. local_addr ( ) . unwrap ( ) ;
72+
73+ let ( shutdown_tx, mut shutdown_rx) = tokio:: sync:: oneshot:: channel :: < ( ) > ( ) ;
74+
75+ tokio:: spawn ( async move {
76+ loop {
77+ let ( stream, _) = tokio:: select! {
78+ result = listener. accept( ) => result. unwrap( ) ,
79+ _ = & mut shutdown_rx => break ,
80+ } ;
81+ tokio:: spawn ( async move {
82+ let service = hyper:: service:: service_fn ( move |_req| {
83+ let resp = hyper:: Response :: builder ( )
84+ . status ( status)
85+ . body ( http_body_util:: Empty :: < Bytes > :: new ( ) )
86+ . unwrap ( ) ;
87+ std:: future:: ready ( Ok :: < _ , std:: convert:: Infallible > ( resp) )
88+ } ) ;
89+ hyper:: server:: conn:: http1:: Builder :: new ( )
90+ . serve_connection ( TokioIo :: new ( stream) , service)
91+ . await
92+ . ok ( ) ;
93+ } ) ;
94+ }
95+ } ) ;
96+
97+ ( addr, shutdown_tx)
98+ }
99+
63100// MARK: - Health
64101
65102#[ tokio:: test( flavor = "multi_thread" ) ]
@@ -69,25 +106,51 @@ async fn health_check_ok() {
69106 let ( status, body) = http_get ( addr, "/health" ) . await ;
70107
71108 assert_eq ! ( status, 200 ) ;
72- assert_eq ! ( body, "Status OK " ) ;
109+ assert_eq ! ( body, "" ) ;
73110}
74111
75112#[ tokio:: test( flavor = "multi_thread" ) ]
76- async fn health_check_root_ok ( ) {
113+ async fn health_check_does_not_require_auth ( ) {
77114 let ( addr, _shutdown) = start_test_server ( ) . await ;
78115
79- let ( status, body) = http_get ( addr, "/" ) . await ;
116+ // No Authorization header — must still succeed
117+ let ( status, _) = http_get ( addr, "/health" ) . await ;
80118
81119 assert_eq ! ( status, 200 ) ;
82- assert_eq ! ( body, "Status OK" ) ;
83120}
84121
85122#[ tokio:: test( flavor = "multi_thread" ) ]
86- async fn health_check_does_not_require_auth ( ) {
87- let ( addr, _shutdown) = start_test_server ( ) . await ;
123+ async fn upstream_health_returns_ok_when_upstream_is_healthy ( ) {
124+ let ( upstream_addr, _upstream_shutdown) = start_fake_upstream ( 200 ) . await ;
125+ let upstream_url = format ! ( "http://{upstream_addr}" ) ;
88126
89- // No Authorization header — must still succeed
90- let ( status, _) = http_get ( addr, "/health" ) . await ;
127+ let ( addr , _shutdown ) = start_test_server_with_upstream ( & upstream_url ) . await ;
128+ let ( status, _) = http_get ( addr, "/upstream- health" ) . await ;
91129
92130 assert_eq ! ( status, 200 ) ;
93131}
132+
133+ #[ tokio:: test( flavor = "multi_thread" ) ]
134+ async fn upstream_health_returns_same_status_code_as_upstream ( ) {
135+ let random_http_status_code = 201 ;
136+ let ( upstream_addr, _upstream_shutdown) = start_fake_upstream ( random_http_status_code) . await ;
137+ let upstream_url = format ! ( "http://{upstream_addr}" ) ;
138+
139+ let ( addr, _shutdown) = start_test_server_with_upstream ( & upstream_url) . await ;
140+ let ( status, _) = http_get ( addr, "/upstream-health" ) . await ;
141+
142+ assert_eq ! ( status, random_http_status_code) ;
143+ }
144+
145+ #[ tokio:: test( flavor = "multi_thread" ) ]
146+ async fn upstream_health_returns_500_when_upstream_is_unreachable ( ) {
147+ let listener = tokio:: net:: TcpListener :: bind ( "127.0.0.1:0" ) . await . unwrap ( ) ;
148+ let dead_addr = listener. local_addr ( ) . unwrap ( ) ;
149+ drop ( listener) ;
150+
151+ let upstream_url = format ! ( "http://{dead_addr}" ) ;
152+ let ( addr, _shutdown) = start_test_server_with_upstream ( & upstream_url) . await ;
153+ let ( status, _) = http_get ( addr, "/upstream-health" ) . await ;
154+
155+ assert_eq ! ( status, 500 ) ;
156+ }
0 commit comments