github.com/slayercat/go@v0.0.0-20170428012452-c51559813f61/src/net/http/transport_internal_test.go (about)

     1  // Copyright 2016 The Go Authors. All rights reserved.
     2  // Use of this source code is governed by a BSD-style
     3  // license that can be found in the LICENSE file.
     4  
     5  // White-box tests for transport.go (in package http instead of http_test).
     6  
     7  package http
     8  
     9  import (
    10  	"errors"
    11  	"net"
    12  	"testing"
    13  )
    14  
    15  // Issue 15446: incorrect wrapping of errors when server closes an idle connection.
    16  func TestTransportPersistConnReadLoopEOF(t *testing.T) {
    17  	ln := newLocalListener(t)
    18  	defer ln.Close()
    19  
    20  	connc := make(chan net.Conn, 1)
    21  	go func() {
    22  		defer close(connc)
    23  		c, err := ln.Accept()
    24  		if err != nil {
    25  			t.Error(err)
    26  			return
    27  		}
    28  		connc <- c
    29  	}()
    30  
    31  	tr := new(Transport)
    32  	req, _ := NewRequest("GET", "http://"+ln.Addr().String(), nil)
    33  	req = req.WithT(t)
    34  	treq := &transportRequest{Request: req}
    35  	cm := connectMethod{targetScheme: "http", targetAddr: ln.Addr().String()}
    36  	pc, err := tr.getConn(treq, cm)
    37  	if err != nil {
    38  		t.Fatal(err)
    39  	}
    40  	defer pc.close(errors.New("test over"))
    41  
    42  	conn := <-connc
    43  	if conn == nil {
    44  		// Already called t.Error in the accept goroutine.
    45  		return
    46  	}
    47  	conn.Close() // simulate the server hanging up on the client
    48  
    49  	_, err = pc.roundTrip(treq)
    50  	if !isTransportReadFromServerError(err) && err != errServerClosedIdle {
    51  		t.Errorf("roundTrip = %#v, %v; want errServerClosedIdle or transportReadFromServerError", err, err)
    52  	}
    53  
    54  	<-pc.closech
    55  	err = pc.closed
    56  	if !isTransportReadFromServerError(err) && err != errServerClosedIdle {
    57  		t.Errorf("pc.closed = %#v, %v; want errServerClosedIdle or transportReadFromServerError", err, err)
    58  	}
    59  }
    60  
    61  func isTransportReadFromServerError(err error) bool {
    62  	_, ok := err.(transportReadFromServerError)
    63  	return ok
    64  }
    65  
    66  func newLocalListener(t *testing.T) net.Listener {
    67  	ln, err := net.Listen("tcp", "127.0.0.1:0")
    68  	if err != nil {
    69  		ln, err = net.Listen("tcp6", "[::1]:0")
    70  	}
    71  	if err != nil {
    72  		t.Fatal(err)
    73  	}
    74  	return ln
    75  }
    76  
    77  func dummyRequest(method string) *Request {
    78  	req, err := NewRequest(method, "http://fake.tld/", nil)
    79  	if err != nil {
    80  		panic(err)
    81  	}
    82  	return req
    83  }
    84  
    85  func TestTransportShouldRetryRequest(t *testing.T) {
    86  	tests := []struct {
    87  		pc  *persistConn
    88  		req *Request
    89  
    90  		err  error
    91  		want bool
    92  	}{
    93  		0: {
    94  			pc:   &persistConn{reused: false},
    95  			req:  dummyRequest("POST"),
    96  			err:  nothingWrittenError{},
    97  			want: false,
    98  		},
    99  		1: {
   100  			pc:   &persistConn{reused: true},
   101  			req:  dummyRequest("POST"),
   102  			err:  nothingWrittenError{},
   103  			want: true,
   104  		},
   105  		2: {
   106  			pc:   &persistConn{reused: true},
   107  			req:  dummyRequest("POST"),
   108  			err:  http2ErrNoCachedConn,
   109  			want: true,
   110  		},
   111  		3: {
   112  			pc:   &persistConn{reused: true},
   113  			req:  dummyRequest("POST"),
   114  			err:  errMissingHost,
   115  			want: false,
   116  		},
   117  		4: {
   118  			pc:   &persistConn{reused: true},
   119  			req:  dummyRequest("POST"),
   120  			err:  transportReadFromServerError{},
   121  			want: false,
   122  		},
   123  		5: {
   124  			pc:   &persistConn{reused: true},
   125  			req:  dummyRequest("GET"),
   126  			err:  transportReadFromServerError{},
   127  			want: true,
   128  		},
   129  		6: {
   130  			pc:   &persistConn{reused: true},
   131  			req:  dummyRequest("GET"),
   132  			err:  errServerClosedIdle,
   133  			want: true,
   134  		},
   135  	}
   136  	for i, tt := range tests {
   137  		got := tt.pc.shouldRetryRequest(tt.req, tt.err)
   138  		if got != tt.want {
   139  			t.Errorf("%d. shouldRetryRequest = %v; want %v", i, got, tt.want)
   140  		}
   141  	}
   142  }