github.com/glycerine/xcryptossh@v7.0.4+incompatible/writeto_test.go (about)

     1  package ssh
     2  
     3  // Write timeouts don't actually work.
     4  // This is because the underlying ssh
     5  // returns err==nil when the write has
     6  // only been buffered locally.
     7  /*
     8  import (
     9  	"fmt"
    10  	"io"
    11  	"net"
    12  	"testing"
    13  	"time"
    14  )
    15  
    16  // Given a 1000 msec idle write timeout, when reads stop, the Write() calls
    17  // should return Timeout() == true errors. The is the compliment
    18  // to the phase_test.go.
    19  //
    20  func TestTimeout007WriteIdlesOutWhenReadsStop(t *testing.T) {
    21  	defer xtestend(xtestbegin(t))
    22  	halt := NewHalter()
    23  	defer halt.RequestStop()
    24  
    25  	r, w, mux := channelPair(t, halt)
    26  
    27  	idleout := 1000 * time.Millisecond
    28  	overall := 3 * idleout
    29  
    30  	t0 := time.Now()
    31  	tstop := t0.Add(overall)
    32  
    33  	// set the read timeout on the writer
    34  	err := w.SetIdleTimeout(idleout)
    35  	if err != nil {
    36  		panic(fmt.Sprintf("w.SetIdleTimeout: %v", err))
    37  	}
    38  
    39  	readErr := make(chan error)
    40  	writeErr := make(chan error)
    41  	var seq *seqWords
    42  	var ring *infiniteRing
    43  	var whenLastWriteTimedout time.Time
    44  
    45  	go to007ReaderToRing(idleout, r, overall, tstop, readErr, &ring)
    46  
    47  	go to007SeqWordsToWriter(w, tstop, writeErr, &seq, &whenLastWriteTimedout)
    48  
    49  	// wait for our overall time, and for both to return
    50  	var rerr, werr error
    51  	var rok, wok bool
    52  	complete := func() bool {
    53  		return rok && wok
    54  	}
    55  collectionLoop:
    56  	for {
    57  		select {
    58  		case <-time.After(2 * overall):
    59  			panic(fmt.Sprintf("TestTimeout007WriteIdlesOutWhenReadsStop: waited " +
    60  				"two overall, yet still no idle timeout!"))
    61  
    62  		case rerr = <-readErr:
    63  			pp("got rerr: '%#v'", rerr)
    64  			now := time.Now()
    65  			if now.Before(tstop) {
    66  				panic(fmt.Sprintf("rerr: '%v', stopped too early, before '%v'. now=%v. now-before=%v", rerr, tstop, now, now.Sub(tstop))) // panicing here
    67  			}
    68  			rok = true
    69  
    70  			if complete() {
    71  				break collectionLoop
    72  			}
    73  
    74  		case werr = <-writeErr:
    75  			pp("got werr")
    76  			now := time.Now()
    77  			if now.Before(tstop) {
    78  				panic(fmt.Sprintf("werr: '%v', stopped too early, before '%v'. now=%v. now-before=%v", werr, tstop, now, now.Sub(tstop)))
    79  			}
    80  			wok = true
    81  
    82  			// verify that write got a timeout: this is the main point of this test.
    83  			nerr, ok := werr.(net.Error)
    84  			if !ok || !nerr.Timeout() {
    85  				panic(fmt.Sprintf("big problem: expected a timeout error back from Write()."+
    86  					" instead got '%v'", werr))
    87  			}
    88  
    89  			if complete() {
    90  				break collectionLoop
    91  			}
    92  		}
    93  
    94  	}
    95  	p("done with collection loop")
    96  
    97  	p("whenLastWriteTimedout=%v, tstop=%v, idleout=%v", whenLastWriteTimedout, tstop, idleout)
    98  
    99  	// sanity check that whenLastWriteTimedout in when we expect
   100  	if whenLastWriteTimedout.Before(tstop) {
   101  		panic("premature timeout, very bad")
   102  	}
   103  	if whenLastWriteTimedout.After(tstop.Add(3 * idleout)) {
   104  		panic("too slow a time out, very bad")
   105  	}
   106  
   107  	w.Close()
   108  	r.Close()
   109  	mux.Close()
   110  
   111  }
   112  
   113  // setup reader r -> infiniteRing ring. returns
   114  // readOk upon success.
   115  func to007ReaderToRing(idleout time.Duration, r Channel, overall time.Duration, tstop time.Time, readErr chan error, pRing **infiniteRing) (err error) {
   116  	defer func() {
   117  		p("readerToRing returning on readErr, err = '%v'", err)
   118  		readErr <- err
   119  	}()
   120  
   121  	ring := newInfiniteRing()
   122  	*pRing = ring
   123  
   124  	src := r
   125  	dst := ring
   126  	buf := make([]byte, 32*1024)
   127  
   128  	for {
   129  		nr, er := src.Read(buf)
   130  		if nr > 0 {
   131  			nw, ew := dst.Write(buf[0:nr])
   132  			if ew != nil {
   133  				err = ew
   134  				p("readerToRing sees Write err %v", ew)
   135  				break
   136  			}
   137  			if nr != nw {
   138  				err = io.ErrShortWrite
   139  				break
   140  			}
   141  		}
   142  
   143  		if time.Now().After(tstop) {
   144  			p("reader: reached tstop, bailing out of copy loop.")
   145  			return readOk
   146  		}
   147  
   148  		if er != nil {
   149  			p("readerToRing sees Read err %v", er)
   150  			if er != io.EOF {
   151  				err = er
   152  			}
   153  			break
   154  		}
   155  	} //end for
   156  
   157  	return err
   158  }
   159  
   160  // read from the integers 0,1,2,... and write to w until tstop.
   161  // returns writeOk upon success
   162  func to007SeqWordsToWriter(w Channel, tstop time.Time, writeErr chan error, pSeqWords **seqWords, whenerr *time.Time) (err error) {
   163  	defer func() {
   164  		p("to007SeqWordsToWriter returning err = '%v'", err)
   165  		writeErr <- err
   166  	}()
   167  	src := newSequentialWords()
   168  	*pSeqWords = src
   169  	dst := w
   170  	buf := make([]byte, 32*1024)
   171  	for {
   172  		nr, er := src.Read(buf)
   173  		if nr > 0 {
   174  			nw, ew := dst.Write(buf[0:nr])
   175  			*whenerr = time.Now()
   176  			if ew != nil {
   177  				pp("seqWriter sees Write err %v", ew)
   178  				err = ew
   179  				break
   180  			}
   181  			if nr != nw {
   182  				err = io.ErrShortWrite
   183  				break
   184  			}
   185  		}
   186  		if er != nil {
   187  			if er != io.EOF {
   188  				err = er
   189  			}
   190  			break
   191  		}
   192  	}
   193  
   194  	return err
   195  }
   196  */