@@ -60,11 +60,13 @@ pub struct Builder {
6060enum Action {
6161 Read ( Vec < u8 > ) ,
6262 Write ( Vec < u8 > ) ,
63+ Shutdown ,
6364 Wait ( Duration ) ,
6465 // Wrapped in Arc so that Builder can be cloned and Send.
6566 // Mock is not cloned as does not need to check Rc for ref counts.
6667 ReadError ( Option < Arc < io:: Error > > ) ,
6768 WriteError ( Option < Arc < io:: Error > > ) ,
69+ ShutdownError ( Option < Arc < io:: Error > > ) ,
6870}
6971
7072struct Inner {
@@ -76,6 +78,13 @@ struct Inner {
7678 name : String ,
7779}
7880
81+ enum Shutdown {
82+ ShutdownSuccess ,
83+ ShutdownError ( io:: Error ) ,
84+ NeedWait ,
85+ NoActions ,
86+ }
87+
7988impl Builder {
8089 /// Return a new, empty `Builder`.
8190 pub fn new ( ) -> Self {
@@ -130,6 +139,25 @@ impl Builder {
130139 self
131140 }
132141
142+ /// Sequence a shutdown operation.
143+ ///
144+ /// The next operation in the mock's script will be to expect a
145+ /// [`AsyncWrite::poll_shutdown`] call.
146+ pub fn shutdown ( & mut self ) -> & mut Self {
147+ self . actions . push_back ( Action :: Shutdown ) ;
148+ self
149+ }
150+
151+ /// Sequence a shutdown operation that produces an error.
152+ ///
153+ /// The next operation in the mock's script will be to expect a
154+ /// [`AsyncWrite::poll_shutdown`] call that returns `error`.
155+ pub fn shutdown_error ( & mut self , error : io:: Error ) -> & mut Self {
156+ let error = Some ( error. into ( ) ) ;
157+ self . actions . push_back ( Action :: ShutdownError ( error) ) ;
158+ self
159+ }
160+
133161 /// Set name of the mock IO object to include in panic messages and debug output
134162 pub fn name ( & mut self , name : impl Into < String > ) -> & mut Self {
135163 self . name = name. into ( ) ;
@@ -198,6 +226,10 @@ impl Inner {
198226
199227 let rx = UnboundedReceiverStream :: new ( rx) ;
200228
229+ // Actually, we should deny any write action after the shutdown action.
230+ // However, since we currently doesn't check the write action after the error
231+ // like BrokenPipe error, we ignore this case to keep the behavior consistent.
232+
201233 let inner = Inner {
202234 actions,
203235 sleep : None ,
@@ -242,6 +274,9 @@ impl Inner {
242274 // Either waiting or expecting a write
243275 Err ( io:: ErrorKind :: WouldBlock . into ( ) )
244276 }
277+ Some ( & mut Action :: Shutdown ) | Some ( & mut Action :: ShutdownError ( _) ) => {
278+ panic ! ( "unexpected read, expect poll_shutdown" ) ;
279+ }
245280 None => Ok ( ( ) ) ,
246281 }
247282 }
@@ -284,6 +319,9 @@ impl Inner {
284319 break ;
285320 }
286321 Action :: Read ( _) | Action :: ReadError ( _) => ( ) ,
322+ Action :: Shutdown | Action :: ShutdownError ( _) => {
323+ panic ! ( "unexpected write, expect poll_shutdown" ) ;
324+ }
287325 }
288326 }
289327
@@ -297,6 +335,25 @@ impl Inner {
297335 }
298336 }
299337
338+ fn shutdown ( & mut self ) -> Shutdown {
339+ match self . action ( ) {
340+ Some ( & mut Action :: Shutdown ) => Shutdown :: ShutdownSuccess ,
341+ Some ( & mut Action :: ShutdownError ( ref mut err) ) => {
342+ let err = err. take ( ) . expect ( "Should have been removed from actions." ) ;
343+ let err = Arc :: try_unwrap ( err) . expect ( "There are no other references." ) ;
344+ Shutdown :: ShutdownError ( err)
345+ }
346+ Some ( & mut Action :: Read ( _) ) | Some ( & mut Action :: ReadError ( _) ) => {
347+ panic ! ( "unexpected poll_shutdown, expect read" ) ;
348+ }
349+ Some ( & mut Action :: Write ( _) ) | Some ( & mut Action :: WriteError ( _) ) => {
350+ panic ! ( "unexpected poll_shutdown, expect write" ) ;
351+ }
352+ Some ( & mut Action :: Wait ( _) ) => Shutdown :: NeedWait ,
353+ None => Shutdown :: NoActions ,
354+ }
355+ }
356+
300357 fn action ( & mut self ) -> Option < & mut Action > {
301358 loop {
302359 if self . actions . is_empty ( ) {
@@ -333,6 +390,12 @@ impl Inner {
333390 break ;
334391 }
335392 }
393+ Action :: Shutdown => break ,
394+ Action :: ShutdownError ( ref mut error) => {
395+ if error. is_some ( ) {
396+ break ;
397+ }
398+ }
336399 }
337400
338401 let _action = self . actions . pop_front ( ) ;
@@ -472,8 +535,49 @@ impl AsyncWrite for Mock {
472535 Poll :: Ready ( Ok ( ( ) ) )
473536 }
474537
475- fn poll_shutdown ( self : Pin < & mut Self > , _cx : & mut task:: Context < ' _ > ) -> Poll < io:: Result < ( ) > > {
476- Poll :: Ready ( Ok ( ( ) ) )
538+ fn poll_shutdown (
539+ mut self : Pin < & mut Self > ,
540+ cx : & mut task:: Context < ' _ > ,
541+ ) -> Poll < io:: Result < ( ) > > {
542+ loop {
543+ if let Some ( ref mut sleep) = self . inner . sleep {
544+ ready ! ( Pin :: new( sleep) . poll( cx) ) ;
545+ }
546+
547+ // If a sleep is set, it has already fired
548+ self . inner . sleep = None ;
549+
550+ match self . inner . shutdown ( ) {
551+ Shutdown :: ShutdownSuccess => {
552+ assert ! ( matches!( self . inner. actions. pop_front( ) , Some ( Action :: Shutdown ) ) ) ;
553+ self . maybe_wakeup_reader ( ) ;
554+ return Poll :: Ready ( Ok ( ( ) ) ) ;
555+ }
556+ Shutdown :: ShutdownError ( e) => {
557+ assert ! ( matches!( self . inner. actions. pop_front( ) , Some ( Action :: ShutdownError ( _) ) ) ) ;
558+ self . maybe_wakeup_reader ( ) ;
559+ return Poll :: Ready ( Err ( e) ) ;
560+ }
561+ Shutdown :: NeedWait => {
562+ if let Some ( rem) = self . inner . remaining_wait ( ) {
563+ let until = Instant :: now ( ) + rem;
564+ self . inner . sleep = Some ( Box :: pin ( time:: sleep_until ( until) ) ) ;
565+ } else {
566+ panic ! (
567+ "unexpected poll_shutdown, expect read or write {}" ,
568+ self . pmsg( )
569+ ) ;
570+ }
571+ }
572+ Shutdown :: NoActions => {
573+ if let Some ( action) = ready ! ( self . inner. poll_action( cx) ) {
574+ self . inner . actions . push_back ( action) ;
575+ } else {
576+ panic ! ( "unexpected poll_shutdown, but actually no more sequenced actions {}" , self . pmsg( ) ) ;
577+ }
578+ }
579+ }
580+ }
477581 }
478582}
479583
@@ -496,7 +600,11 @@ impl Drop for Mock {
496600 "There is still data left to write. {}" ,
497601 self . pmsg( )
498602 ) ,
603+ Action :: Shutdown => panic ! ( "AsyncWrite::poll_shutdown was not called. {}" , self . pmsg( ) ) ,
499604 Action :: ReadError ( _) | Action :: WriteError ( _) | Action :: Wait ( _) => ( ) ,
605+ // Since the existing implementation ignores the read/write error, so we also ignore the
606+ // shutdown error here to keep the behavior consistent.
607+ Action :: ShutdownError ( _) => ( ) ,
500608 } ) ;
501609 }
502610}
0 commit comments