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

     1  package ssh
     2  
     3  import (
     4  	"fmt"
     5  	"io"
     6  	"net"
     7  	"runtime/debug"
     8  	"testing"
     9  	"time"
    10  )
    11  
    12  func init() {
    13  	// see all goroutines on panic for proper debugging of tests.
    14  	debug.SetTraceback("all")
    15  }
    16  
    17  // Tests of the Timeout factility.
    18  //
    19  // 1. Given that we want to detect when the remote side
    20  // is not responding, when we set a read or
    21  // a write timeout, the ssh.Channel should
    22  // unblock our read (write) when the timeout
    23  // expires. The channel should remain open
    24  // (and not be auto closed) so that
    25  // subsequent attempts to read (write)
    26  // the slow-to-respond remote may actually
    27  // succeed if they come back to servicing
    28  // the ssh.Channel. In this respect we
    29  // allow an ssh.Channel to act like a
    30  // net.Conn with its deadline based timeouts.
    31  //
    32  // 2. When I/O does happen on an ssh.Channel, it
    33  // should automatically bump the timeout
    34  // into the future, so that the client
    35  // reading (writing) doesn't have to keep
    36  // re-setting the timeout manually, and
    37  // more importantly, so transfers that
    38  // take a long time but are actively
    39  // moving bytes don't timeout simply
    40  // because we didn't magically anticipate
    41  // this and know it was going
    42  // to be a large and lengthy file transfer.
    43  //
    44  // We call this facility
    45  // SetIdleTimeout(dur time.Duration).
    46  //
    47  // It is the main API for ssh timeouts, and
    48  // avoids requiring that client users need to
    49  // manually re-impliment timeout handling logic
    50  // after every Read and Write. In contrast, when
    51  // using net.Conn deadlines, idle timeouts must
    52  // be done very manually. Moreover cannot use
    53  // standard appliances like io.Copy() because
    54  // the Reads inside each require a prior
    55  // deadline setting.
    56  //
    57  // See cts_test.go in addition to this file.
    58  
    59  /* // write timeouts don't actuall work.
    60  func TestSimpleWriteTimeout(t *testing.T) {
    61  	defer xtestend(xtestbegin(t))
    62  	halt := NewHalter()
    63  	defer halt.RequestStop()
    64  
    65  	r, w, mux := channelPair(t, halt)
    66  	defer w.Close()
    67  	defer r.Close()
    68  	defer mux.Close()
    69  
    70  	abandon := "should never be written"
    71  	magic := "expected saluations"
    72  	go func() {
    73  		// use a quick timeout so the test runs quickly.
    74  		_, err := w.SetWriteIdleTimeout(50 * time.Millisecond)
    75  		if err != nil {
    76  			t.Fatalf("SetIdleTimeout: %v", err)
    77  		}
    78  		wt := w.GetWriteIdleTimer()
    79  		wt.BeginAttempt()
    80  		time.Sleep(100 * time.Millisecond)
    81  		n, err := w.Write([]byte(abandon))
    82  		if err == nil || !err.(net.Error).Timeout() {
    83  			panic(fmt.Sprintf("expected to get a net.Error that had Timeout() true: '%v'. wrote n=%v", err, n))
    84  		}
    85  
    86  		_, err = w.SetWriteIdleTimeout(0)
    87  		if err != nil {
    88  			t.Fatalf("canceling idle timeout: %v", err)
    89  		}
    90  		time.Sleep(200 * time.Millisecond)
    91  		p("SimpleTimeout: about to write which should succeed")
    92  		_, err = w.Write([]byte(magic))
    93  		if err != nil {
    94  			p("SimpleTimeout: just write failed unexpectedly")
    95  			panic(fmt.Sprintf("write after cancelling write deadline: %v", err)) // timeout after canceling!
    96  		}
    97  		p("SimpleTimeout: just write which did succeed")
    98  	}()
    99  
   100  	var buf [1024]byte
   101  	n, err := r.Read(buf[:])
   102  	if err != nil {
   103  		panic(fmt.Sprintf("Read: %v", err))
   104  	}
   105  	got := string(buf[:n])
   106  	if got != magic {
   107  		panic(fmt.Sprintf("Read: got %q want %q", got, magic))
   108  	}
   109  
   110  	err = w.Close()
   111  	switch {
   112  	case err == nil:
   113  		//ok
   114  	case err == io.EOF:
   115  		// ok
   116  	default:
   117  		panic(fmt.Sprintf("Close: %v", err))
   118  	}
   119  }
   120  */
   121  
   122  func TestSimpleReadTimeout(t *testing.T) {
   123  	defer xtestend(xtestbegin(t))
   124  	halt := NewHalter()
   125  	defer halt.RequestStop()
   126  
   127  	r, w, mux := channelPair(t, halt)
   128  	defer w.Close()
   129  	defer r.Close()
   130  	defer mux.Close()
   131  
   132  	var buf [1024]byte
   133  	cancel := make(chan bool)
   134  
   135  	go func() {
   136  		select {
   137  		case <-time.After(100 * time.Second):
   138  			panic("2 msec Read timeout did not fire after 100 sec")
   139  		case <-cancel:
   140  		}
   141  	}()
   142  
   143  	// use a quick timeout so the test runs quickly.
   144  	err := r.SetReadIdleTimeout(2 * time.Millisecond)
   145  	if err != nil {
   146  		panic(fmt.Sprintf("SetIdleTimeout: %v", err))
   147  	}
   148  
   149  	// no writer, so this should timeout.
   150  	n, err := r.Read(buf[:])
   151  
   152  	if err == nil || !err.(net.Error).Timeout() || n > 0 {
   153  		panic(fmt.Sprintf("expected to get a net.Error that had Timeout() true with n = 0"))
   154  	}
   155  	cancel <- true
   156  
   157  	err = w.Close()
   158  	switch {
   159  	case err == nil:
   160  		//ok
   161  	case err == io.EOF:
   162  		// ok
   163  	default:
   164  		panic(fmt.Sprintf("Close: %v", err))
   165  	}
   166  }
   167  
   168  func TestSimpleReadAfterTimeout(t *testing.T) {
   169  	defer xtestend(xtestbegin(t))
   170  	halt := NewHalter()
   171  	defer halt.RequestStop()
   172  
   173  	r, w, mux := channelPair(t, halt)
   174  	defer w.Close()
   175  	defer r.Close()
   176  	defer mux.Close()
   177  
   178  	var buf [1024]byte
   179  	cancel := make(chan bool)
   180  
   181  	go func() {
   182  		select {
   183  		case <-time.After(100 * time.Second):
   184  			panic("2 msec Read timeout did not fire after 100 sec")
   185  		case <-cancel:
   186  		}
   187  	}()
   188  
   189  	// use a quick timeout so the test runs quickly.
   190  	err := r.SetReadIdleTimeout(2 * time.Millisecond)
   191  	if err != nil {
   192  		panic(fmt.Sprintf("SetIdleTimeout: %v", err))
   193  	}
   194  
   195  	// no writer, so this should timeout.
   196  	n, err := r.Read(buf[:])
   197  
   198  	if err == nil || !err.(net.Error).Timeout() || n > 0 {
   199  		panic(fmt.Sprintf("expected to get a net.Error that had Timeout() true with n = 0"))
   200  	}
   201  	cancel <- true
   202  
   203  	// And we *must* reset the timeout status before trying to Read again.
   204  	err = r.SetReadIdleTimeout(0)
   205  	if err != nil {
   206  		panic(fmt.Sprintf("reset with SetIdleTimeout: %v", err))
   207  	}
   208  
   209  	// now start a writer and verify that we can read okay
   210  	// even after a prior timeout.
   211  
   212  	magic := "expected saluations"
   213  	go func() {
   214  		_, werr := w.Write([]byte(magic))
   215  		if werr != nil {
   216  			panic(fmt.Sprintf("write after cancelling write deadline: %v", werr))
   217  		}
   218  	}()
   219  
   220  	n, err = r.Read(buf[:])
   221  	if err != nil {
   222  		panic(fmt.Sprintf("Read after timed-out Read got err: %v", err))
   223  	}
   224  	if n != len(magic) {
   225  		panic(fmt.Sprintf("short Read after timed-out Read"))
   226  	}
   227  	got := string(buf[:n])
   228  	if got != magic {
   229  		panic(fmt.Sprintf("Read: got %q want %q", got, magic))
   230  	}
   231  
   232  	err = w.Close()
   233  	switch {
   234  	case err == nil:
   235  		//ok
   236  	case err == io.EOF:
   237  		// ok
   238  	default:
   239  		panic(fmt.Sprintf("Close: %v", err))
   240  	}
   241  }
   242  
   243  // deadlines
   244  
   245  func TestSimpleReadDeadline(t *testing.T) {
   246  	defer xtestend(xtestbegin(t))
   247  
   248  	halt := NewHalter()
   249  	defer halt.RequestStop()
   250  
   251  	r, w, mux := channelPair(t, halt)
   252  	defer w.Close()
   253  	defer r.Close()
   254  	defer mux.Close()
   255  
   256  	var buf [1024]byte
   257  	cancel := make(chan bool)
   258  
   259  	go func() {
   260  		select {
   261  		case <-time.After(10 * time.Second):
   262  			panic("20 msec Read timeout did not fire after 10 sec")
   263  		case <-cancel:
   264  		}
   265  	}()
   266  
   267  	// use a quick timeout so the test runs quickly.
   268  	err := r.SetReadDeadline(time.Now().Add(20 * time.Millisecond))
   269  	if err != nil {
   270  		panic(fmt.Sprintf("SetReadDeadline: %v", err))
   271  	}
   272  
   273  	// no writer, so this should timeout.
   274  	n, err := r.Read(buf[:])
   275  
   276  	if err == nil || !err.(net.Error).Timeout() || n > 0 {
   277  		panic(fmt.Sprintf("expected to get a net.Error that had Timeout() true with n = 0"))
   278  	}
   279  	cancel <- true
   280  
   281  	err = w.Close()
   282  	switch {
   283  	case err == nil:
   284  		//ok
   285  	case err == io.EOF:
   286  		// ok
   287  	default:
   288  		panic(fmt.Sprintf("Close: %v", err))
   289  	}
   290  }