@@ -34,14 +34,127 @@ async fn run() -> Result<(), BoxError> {
3434 } ) ;
3535
3636 let wait = tokio:: task:: spawn_blocking ( otel_conformance_scenario:: wait_for_eof) . await ?;
37- shutdown_sender. send ( ( ) ) . map_err ( |( ) | {
38- io:: Error :: new (
37+ shutdown_server ( shutdown_sender, server, wait) . await
38+ }
39+
40+ async fn shutdown_server (
41+ shutdown_sender : oneshot:: Sender < ( ) > ,
42+ server : tokio:: task:: JoinHandle < io:: Result < ( ) > > ,
43+ wait : io:: Result < ( ) > ,
44+ ) -> Result < ( ) , BoxError > {
45+ if shutdown_sender. send ( ( ) ) . is_err ( ) {
46+ server. await ??;
47+ return Err ( io:: Error :: new (
3948 io:: ErrorKind :: BrokenPipe ,
4049 "Tower server stopped before the shutdown signal" ,
4150 )
42- } ) ?;
51+ . into ( ) ) ;
52+ }
4353 let server_result = server. await ?;
4454 wait?;
4555 server_result?;
4656 Ok ( ( ) )
4757}
58+
59+ #[ cfg( test) ]
60+ mod tests {
61+ use super :: shutdown_server;
62+ use std:: io;
63+ use tokio:: sync:: oneshot;
64+ use tokio:: task:: JoinError ;
65+
66+ #[ tokio:: test]
67+ async fn closed_shutdown_channel_preserves_server_error ( ) {
68+ let ( sender, receiver) = oneshot:: channel ( ) ;
69+ drop ( receiver) ;
70+ let server = tokio:: spawn ( async { Err ( io:: Error :: other ( "server failed" ) ) } ) ;
71+
72+ let error = shutdown_server ( sender, server, Ok ( ( ) ) ) . await . unwrap_err ( ) ;
73+
74+ assert_eq ! (
75+ error. downcast_ref:: <io:: Error >( ) . unwrap( ) . kind( ) ,
76+ io:: ErrorKind :: Other
77+ ) ;
78+ assert_eq ! ( error. to_string( ) , "server failed" ) ;
79+ }
80+
81+ #[ tokio:: test]
82+ async fn closed_shutdown_channel_preserves_server_panic ( ) {
83+ let ( sender, receiver) = oneshot:: channel ( ) ;
84+ drop ( receiver) ;
85+ let server = tokio:: spawn ( async { panic ! ( "server task panicked" ) } ) ;
86+
87+ let error = shutdown_server ( sender, server, Ok ( ( ) ) ) . await . unwrap_err ( ) ;
88+
89+ assert ! ( error. downcast_ref:: <JoinError >( ) . unwrap( ) . is_panic( ) ) ;
90+ }
91+
92+ #[ tokio:: test]
93+ async fn closed_shutdown_channel_preserves_server_cancellation ( ) {
94+ let ( sender, receiver) = oneshot:: channel ( ) ;
95+ drop ( receiver) ;
96+ let server = tokio:: spawn ( std:: future:: pending ( ) ) ;
97+ server. abort ( ) ;
98+
99+ let error = shutdown_server ( sender, server, Ok ( ( ) ) ) . await . unwrap_err ( ) ;
100+
101+ assert ! ( error. downcast_ref:: <JoinError >( ) . unwrap( ) . is_cancelled( ) ) ;
102+ }
103+
104+ #[ tokio:: test]
105+ async fn unexpected_successful_exit_reports_broken_pipe ( ) {
106+ let ( sender, receiver) = oneshot:: channel ( ) ;
107+ drop ( receiver) ;
108+ let server = tokio:: spawn ( async { Ok ( ( ) ) } ) ;
109+
110+ let error = shutdown_server ( sender, server, Ok ( ( ) ) ) . await . unwrap_err ( ) ;
111+
112+ assert_eq ! (
113+ error. downcast_ref:: <io:: Error >( ) . unwrap( ) . kind( ) ,
114+ io:: ErrorKind :: BrokenPipe
115+ ) ;
116+ assert_eq ! (
117+ error. to_string( ) ,
118+ "Tower server stopped before the shutdown signal"
119+ ) ;
120+ }
121+
122+ #[ tokio:: test]
123+ async fn graceful_shutdown_succeeds ( ) {
124+ let ( sender, receiver) = oneshot:: channel ( ) ;
125+ let server = tokio:: spawn ( async {
126+ receiver. await . expect ( "shutdown signal" ) ;
127+ Ok ( ( ) )
128+ } ) ;
129+
130+ shutdown_server ( sender, server, Ok ( ( ) ) ) . await . unwrap ( ) ;
131+ }
132+
133+ #[ tokio:: test]
134+ async fn graceful_shutdown_preserves_server_error ( ) {
135+ let ( sender, receiver) = oneshot:: channel ( ) ;
136+ let server = tokio:: spawn ( async {
137+ receiver. await . expect ( "shutdown signal" ) ;
138+ Err ( io:: Error :: other ( "server failed" ) )
139+ } ) ;
140+
141+ let error = shutdown_server ( sender, server, Ok ( ( ) ) ) . await . unwrap_err ( ) ;
142+
143+ assert_eq ! ( error. to_string( ) , "server failed" ) ;
144+ }
145+
146+ #[ tokio:: test]
147+ async fn graceful_shutdown_preserves_eof_error_priority ( ) {
148+ let ( sender, receiver) = oneshot:: channel ( ) ;
149+ let server = tokio:: spawn ( async {
150+ receiver. await . expect ( "shutdown signal" ) ;
151+ Err ( io:: Error :: other ( "server failed" ) )
152+ } ) ;
153+
154+ let error = shutdown_server ( sender, server, Err ( io:: Error :: other ( "stdin failed" ) ) )
155+ . await
156+ . unwrap_err ( ) ;
157+
158+ assert_eq ! ( error. to_string( ) , "stdin failed" ) ;
159+ }
160+ }
0 commit comments