@@ -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+ ShouldSuccess ,
83+ ShouldError ( 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 :: ShouldSuccess ,
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 :: ShouldError ( 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,55 @@ 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 ( mut self : Pin < & mut Self > , cx : & mut task:: Context < ' _ > ) -> Poll < io:: Result < ( ) > > {
539+ loop {
540+ if let Some ( ref mut sleep) = self . inner . sleep {
541+ ready ! ( Pin :: new( sleep) . poll( cx) ) ;
542+ }
543+
544+ // If a sleep is set, it has already fired
545+ self . inner . sleep = None ;
546+
547+ match self . inner . shutdown ( ) {
548+ Shutdown :: ShouldSuccess => {
549+ assert ! ( matches!(
550+ self . inner. actions. pop_front( ) ,
551+ Some ( Action :: Shutdown )
552+ ) ) ;
553+ self . maybe_wakeup_reader ( ) ;
554+ return Poll :: Ready ( Ok ( ( ) ) ) ;
555+ }
556+ Shutdown :: ShouldError ( e) => {
557+ assert ! ( matches!(
558+ self . inner. actions. pop_front( ) ,
559+ Some ( Action :: ShutdownError ( _) )
560+ ) ) ;
561+ self . maybe_wakeup_reader ( ) ;
562+ return Poll :: Ready ( Err ( e) ) ;
563+ }
564+ Shutdown :: NeedWait => {
565+ if let Some ( rem) = self . inner . remaining_wait ( ) {
566+ let until = Instant :: now ( ) + rem;
567+ self . inner . sleep = Some ( Box :: pin ( time:: sleep_until ( until) ) ) ;
568+ } else {
569+ panic ! (
570+ "unexpected poll_shutdown, expect read or write {}" ,
571+ self . pmsg( )
572+ ) ;
573+ }
574+ }
575+ Shutdown :: NoActions => {
576+ if let Some ( action) = ready ! ( self . inner. poll_action( cx) ) {
577+ self . inner . actions . push_back ( action) ;
578+ } else {
579+ panic ! (
580+ "unexpected poll_shutdown, but actually no more sequenced actions {}" ,
581+ self . pmsg( )
582+ ) ;
583+ }
584+ }
585+ }
586+ }
477587 }
478588}
479589
@@ -496,7 +606,11 @@ impl Drop for Mock {
496606 "There is still data left to write. {}" ,
497607 self . pmsg( )
498608 ) ,
609+ Action :: Shutdown => panic ! ( "AsyncWrite::poll_shutdown was not called. {}" , self . pmsg( ) ) ,
499610 Action :: ReadError ( _) | Action :: WriteError ( _) | Action :: Wait ( _) => ( ) ,
611+ // Since the existing implementation ignores the read/write error, so we also ignore the
612+ // shutdown error here to keep the behavior consistent.
613+ Action :: ShutdownError ( _) => ( ) ,
500614 } ) ;
501615 }
502616}
0 commit comments