@@ -500,11 +500,40 @@ mod tests {
500500 use super :: * ;
501501 use serde:: Serializer ;
502502 use std:: sync:: atomic:: { AtomicUsize , Ordering } ;
503- use std:: sync:: mpsc:: { self , Receiver , Sender } ;
503+ use std:: sync:: mpsc:: { self , Receiver , Sender , SyncSender } ;
504504 use std:: time:: { Duration , Instant } ;
505505
506506 const TIMEOUT : Duration = Duration :: from_secs ( 5 ) ;
507507
508+ struct WaitBoundary {
509+ observed : SyncSender < ( ) > ,
510+ resume : Receiver < ( ) > ,
511+ }
512+
513+ impl WaitBoundary {
514+ fn observe ( self ) {
515+ self . observed
516+ . send ( ( ) )
517+ . expect ( "wait observation receiver dropped" ) ;
518+ self . resume
519+ . recv_timeout ( TIMEOUT )
520+ . expect ( "timed out resuming wait helper" ) ;
521+ }
522+ }
523+
524+ fn wait_boundary ( ) -> ( WaitBoundary , Receiver < ( ) > , SyncSender < ( ) > ) {
525+ let ( observed_tx, observed_rx) = mpsc:: sync_channel ( 1 ) ;
526+ let ( resume_tx, resume_rx) = mpsc:: sync_channel ( 1 ) ;
527+ (
528+ WaitBoundary {
529+ observed : observed_tx,
530+ resume : resume_rx,
531+ } ,
532+ observed_rx,
533+ resume_tx,
534+ )
535+ }
536+
508537 #[ derive( Clone , Default ) ]
509538 struct CapturedWriter {
510539 bytes : Arc < Mutex < Vec < u8 > > > ,
@@ -618,28 +647,83 @@ mod tests {
618647 }
619648 }
620649
621- fn wait_for_error ( output : & Output ) -> io:: Error {
650+ fn wait_for_error ( output : & Output , boundary : Option < WaitBoundary > ) -> io:: Error {
622651 let deadline = Instant :: now ( ) + TIMEOUT ;
652+ let mut boundary = boundary;
623653 loop {
624- if let Some ( error) = output. error ( ) {
654+ let error = output. error ( ) ;
655+ if let Some ( boundary) = boundary. take ( ) {
656+ boundary. observe ( ) ;
657+ }
658+ if let Some ( error) = error {
625659 return error;
626660 }
627661 assert ! ( Instant :: now( ) < deadline, "timed out waiting for error" ) ;
628662 thread:: yield_now ( ) ;
629663 }
630664 }
631665
632- fn wait_for_len ( bytes : & Arc < Mutex < Vec < u8 > > > , expected : usize ) {
666+ fn wait_for_len ( bytes : & Arc < Mutex < Vec < u8 > > > , expected : usize , boundary : Option < WaitBoundary > ) {
633667 let deadline = Instant :: now ( ) + TIMEOUT ;
668+ let mut boundary = boundary;
634669 loop {
635- if bytes. lock ( ) . expect ( "captured output lock poisoned" ) . len ( ) >= expected {
670+ let len = bytes. lock ( ) . expect ( "captured output lock poisoned" ) . len ( ) ;
671+ if let Some ( boundary) = boundary. take ( ) {
672+ boundary. observe ( ) ;
673+ }
674+ if len >= expected {
636675 return ;
637676 }
638677 assert ! ( Instant :: now( ) < deadline, "timed out waiting for output" ) ;
639678 thread:: yield_now ( ) ;
640679 }
641680 }
642681
682+ #[ test]
683+ fn wait_helpers_complete_after_observed_pending_state ( ) {
684+ let bytes = Arc :: new ( Mutex :: new ( Vec :: new ( ) ) ) ;
685+ let ( boundary, observed, resume) = wait_boundary ( ) ;
686+ let waiting_bytes = Arc :: clone ( & bytes) ;
687+ let length_waiter = thread:: spawn ( move || wait_for_len ( & waiting_bytes, 1 , Some ( boundary) ) ) ;
688+
689+ observed
690+ . recv_timeout ( TIMEOUT )
691+ . expect ( "length wait was not observed" ) ;
692+ bytes. lock ( ) . expect ( "captured output lock poisoned" ) . push ( 1 ) ;
693+ resume. send ( ( ) ) . expect ( "length wait helper dropped" ) ;
694+ length_waiter. join ( ) . expect ( "length wait helper panicked" ) ;
695+
696+ let output = Output :: new ( CapturedWriter :: default ( ) ) . expect ( "failed to create test output" ) ;
697+ let ( boundary, observed, resume) = wait_boundary ( ) ;
698+ let waiting_output = output. clone ( ) ;
699+ let error_waiter = thread:: spawn ( move || wait_for_error ( & waiting_output, Some ( boundary) ) ) ;
700+
701+ observed
702+ . recv_timeout ( TIMEOUT )
703+ . expect ( "error wait was not observed" ) ;
704+ output. fail ( io:: Error :: new (
705+ io:: ErrorKind :: BrokenPipe ,
706+ "observed failure" ,
707+ ) ) ;
708+ resume. send ( ( ) ) . expect ( "error wait helper dropped" ) ;
709+ let error = error_waiter. join ( ) . expect ( "error wait helper panicked" ) ;
710+ assert_eq ! ( error. kind( ) , io:: ErrorKind :: BrokenPipe ) ;
711+ }
712+
713+ #[ test]
714+ fn wait_helpers_complete_from_initially_ready_state ( ) {
715+ let bytes = Arc :: new ( Mutex :: new ( vec ! [ 1 ] ) ) ;
716+ wait_for_len ( & bytes, 1 , None ) ;
717+
718+ let output = Output :: new ( CapturedWriter :: default ( ) ) . expect ( "failed to create test output" ) ;
719+ output. fail ( io:: Error :: new (
720+ io:: ErrorKind :: ConnectionReset ,
721+ "initial failure" ,
722+ ) ) ;
723+ let error = wait_for_error ( & output, None ) ;
724+ assert_eq ! ( error. kind( ) , io:: ErrorKind :: ConnectionReset ) ;
725+ }
726+
643727 fn frames ( bytes : & [ u8 ] ) -> Vec < & [ u8 ] > {
644728 let mut remaining = bytes;
645729 let mut result = Vec :: new ( ) ;
@@ -719,7 +803,7 @@ mod tests {
719803 + 2 * ( HEADER_PREFIX . len ( ) + HEADER_SUFFIX . len ( ) )
720804 + expected_first. len ( ) . to_string ( ) . len ( )
721805 + expected_second. len ( ) . to_string ( ) . len ( ) ;
722- wait_for_len ( & bytes, expected_len) ;
806+ wait_for_len ( & bytes, expected_len, None ) ;
723807 output. close ( ) ;
724808
725809 let bytes = bytes. lock ( ) . expect ( "captured output lock poisoned" ) ;
@@ -896,7 +980,7 @@ mod tests {
896980 . expect ( "failed to create output" ) ;
897981
898982 output. send ( & "message" ) ;
899- let first = wait_for_error ( & output) ;
983+ let first = wait_for_error ( & output, None ) ;
900984 assert_eq ! ( first. kind( ) , io:: ErrorKind :: BrokenPipe ) ;
901985 assert ! ( first. to_string( ) . contains( "deliberate write failure" ) ) ;
902986
@@ -919,7 +1003,7 @@ mod tests {
9191003 . expect ( "failed to create output" ) ;
9201004
9211005 output. send ( & "message" ) ;
922- let error = wait_for_error ( & output) ;
1006+ let error = wait_for_error ( & output, None ) ;
9231007 assert_eq ! ( error. kind( ) , io:: ErrorKind :: ConnectionAborted ) ;
9241008 assert ! ( error. to_string( ) . contains( "failed to flush JSONRPC output" ) ) ;
9251009 assert ! ( error. to_string( ) . contains( "deliberate flush failure" ) ) ;
@@ -1092,7 +1176,7 @@ mod tests {
10921176 . sum ( ) ;
10931177 let minimum_len =
10941178 expected_payload_len + messages * ( HEADER_PREFIX . len ( ) + HEADER_SUFFIX . len ( ) + 1 ) ;
1095- wait_for_len ( & bytes, minimum_len) ;
1179+ wait_for_len ( & bytes, minimum_len, None ) ;
10961180 output. close ( ) ;
10971181
10981182 let bytes = bytes. lock ( ) . expect ( "captured output lock poisoned" ) ;
0 commit comments