1
2
3
4
5 package http2
6
7 import (
8 "bytes"
9 "compress/gzip"
10 "fmt"
11 "io"
12 "io/fs"
13 "strings"
14 "testing"
15 "time"
16 )
17
18 type panicReader struct{}
19
20 func (panicReader) Read([]byte) (int, error) { panic("unexpected Read") }
21 func (panicReader) Close() error { panic("unexpected Close") }
22
23 func TestActualContentLength(t *testing.T) {
24 tests := []struct {
25 req *ClientRequest
26 want int64
27 }{
28
29 0: {
30 req: &ClientRequest{Body: panicReader{}},
31 want: -1,
32 },
33
34 1: {
35 req: &ClientRequest{Body: nil, ContentLength: 5},
36 want: 0,
37 },
38
39 2: {
40 req: &ClientRequest{Body: panicReader{}, ContentLength: 5},
41 want: 5,
42 },
43
44 3: {
45 req: &ClientRequest{Body: NoBody},
46 want: 0,
47 },
48 }
49 for i, tt := range tests {
50 got := actualContentLength(tt.req)
51 if got != tt.want {
52 t.Errorf("test[%d]: got %d; want %d", i, got, tt.want)
53 }
54 }
55 }
56
57
58
59 func TestGzipReader_DoubleReadCrash(t *testing.T) {
60 gz := &gzipReader{
61 body: io.NopCloser(strings.NewReader("0123456789")),
62 }
63 var buf [1]byte
64 n, err1 := gz.Read(buf[:])
65 if n != 0 || !strings.Contains(fmt.Sprint(err1), "invalid header") {
66 t.Fatalf("Read = %v, %v; want 0, invalid header", n, err1)
67 }
68 n, err2 := gz.Read(buf[:])
69 if n != 0 || err2 != err1 {
70 t.Fatalf("second Read = %v, %v; want 0, %v", n, err2, err1)
71 }
72 }
73
74 func TestGzipReader_ReadAfterClose(t *testing.T) {
75 body := bytes.Buffer{}
76 w := gzip.NewWriter(&body)
77 w.Write([]byte("012345679"))
78 w.Close()
79 gz := &gzipReader{
80 body: io.NopCloser(&body),
81 }
82 var buf [1]byte
83 n, err := gz.Read(buf[:])
84 if n != 1 || err != nil {
85 t.Fatalf("first Read = %v, %v; want 1, nil", n, err)
86 }
87 if err := gz.Close(); err != nil {
88 t.Fatalf("gz Close error: %v", err)
89 }
90 n, err = gz.Read(buf[:])
91 if n != 0 || err != fs.ErrClosed {
92 t.Fatalf("Read after close = %v, %v; want 0, fs.ErrClosed", n, err)
93 }
94 }
95
96 func TestAuthorityAddr(t *testing.T) {
97 tests := []struct {
98 scheme, authority string
99 want string
100 }{
101 {"http", "foo.com", "foo.com:80"},
102 {"https", "foo.com", "foo.com:443"},
103 {"https", "foo.com:", "foo.com:443"},
104 {"https", "foo.com:1234", "foo.com:1234"},
105 {"https", "1.2.3.4:1234", "1.2.3.4:1234"},
106 {"https", "1.2.3.4", "1.2.3.4:443"},
107 {"https", "1.2.3.4:", "1.2.3.4:443"},
108 {"https", "[::1]:1234", "[::1]:1234"},
109 {"https", "[::1]", "[::1]:443"},
110 {"https", "[::1]:", "[::1]:443"},
111 }
112 for _, tt := range tests {
113 got := authorityAddr(tt.scheme, tt.authority)
114 if got != tt.want {
115 t.Errorf("authorityAddr(%q, %q) = %q; want %q", tt.scheme, tt.authority, got, tt.want)
116 }
117 }
118 }
119
120
121
122
123
124
125 func TestTransportUsesGetBodyWhenPresent(t *testing.T) {
126 calls := 0
127 someBody := func() io.ReadCloser {
128 return struct{ io.ReadCloser }{io.NopCloser(bytes.NewReader(nil))}
129 }
130 req := &ClientRequest{
131 Body: someBody(),
132 GetBody: func() (io.ReadCloser, error) {
133 calls++
134 return someBody(), nil
135 },
136 }
137
138 req2, err := shouldRetryRequest(req, errClientConnUnusable)
139 if err != nil {
140 t.Fatal(err)
141 }
142 if calls != 1 {
143 t.Errorf("Calls = %d; want 1", calls)
144 }
145 if req2 == req {
146 t.Error("req2 changed")
147 }
148 if req2 == nil {
149 t.Fatal("req2 is nil")
150 }
151 if req2.Body == nil {
152 t.Fatal("req2.Body is nil")
153 }
154 if req2.GetBody == nil {
155 t.Fatal("req2.GetBody is nil")
156 }
157 if req2.Body == req.Body {
158 t.Error("req2.Body unchanged")
159 }
160 }
161
162 func TestClientConnTooIdle(t *testing.T) {
163 tests := []struct {
164 cc func() *ClientConn
165 want bool
166 }{
167 {
168 func() *ClientConn {
169 return &ClientConn{idleTimeout: 5 * time.Second, lastIdle: time.Now().Add(-10 * time.Second)}
170 },
171 true,
172 },
173 {
174 func() *ClientConn {
175 return &ClientConn{idleTimeout: 5 * time.Second, lastIdle: time.Time{}}
176 },
177 false,
178 },
179 {
180 func() *ClientConn {
181 return &ClientConn{idleTimeout: 60 * time.Second, lastIdle: time.Now().Add(-10 * time.Second)}
182 },
183 false,
184 },
185 {
186 func() *ClientConn {
187 return &ClientConn{idleTimeout: 0, lastIdle: time.Now().Add(-10 * time.Second)}
188 },
189 false,
190 },
191 }
192 for i, tt := range tests {
193 got := tt.cc().tooIdleLocked()
194 if got != tt.want {
195 t.Errorf("%d. got %v; want %v", i, got, tt.want)
196 }
197 }
198 }
199
View as plain text