source sync 20190409
[platform/core/system/edge-orchestration.git] / vendor / golang.org / x / net / http2 / http2_test.go
1 // Copyright 2014 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 package http2
6
7 import (
8         "bytes"
9         "errors"
10         "flag"
11         "fmt"
12         "net/http"
13         "os/exec"
14         "strconv"
15         "strings"
16         "testing"
17         "time"
18
19         "golang.org/x/net/http2/hpack"
20 )
21
22 var knownFailing = flag.Bool("known_failing", false, "Run known-failing tests.")
23
24 func condSkipFailingTest(t *testing.T) {
25         if !*knownFailing {
26                 t.Skip("Skipping known-failing test without --known_failing")
27         }
28 }
29
30 func init() {
31         inTests = true
32         DebugGoroutines = true
33         flag.BoolVar(&VerboseLogs, "verboseh2", VerboseLogs, "Verbose HTTP/2 debug logging")
34 }
35
36 func TestSettingString(t *testing.T) {
37         tests := []struct {
38                 s    Setting
39                 want string
40         }{
41                 {Setting{SettingMaxFrameSize, 123}, "[MAX_FRAME_SIZE = 123]"},
42                 {Setting{1<<16 - 1, 123}, "[UNKNOWN_SETTING_65535 = 123]"},
43         }
44         for i, tt := range tests {
45                 got := fmt.Sprint(tt.s)
46                 if got != tt.want {
47                         t.Errorf("%d. for %#v, string = %q; want %q", i, tt.s, got, tt.want)
48                 }
49         }
50 }
51
52 type twriter struct {
53         t  testing.TB
54         st *serverTester // optional
55 }
56
57 func (w twriter) Write(p []byte) (n int, err error) {
58         if w.st != nil {
59                 ps := string(p)
60                 for _, phrase := range w.st.logFilter {
61                         if strings.Contains(ps, phrase) {
62                                 return len(p), nil // no logging
63                         }
64                 }
65         }
66         w.t.Logf("%s", p)
67         return len(p), nil
68 }
69
70 // like encodeHeader, but don't add implicit pseudo headers.
71 func encodeHeaderNoImplicit(t *testing.T, headers ...string) []byte {
72         var buf bytes.Buffer
73         enc := hpack.NewEncoder(&buf)
74         for len(headers) > 0 {
75                 k, v := headers[0], headers[1]
76                 headers = headers[2:]
77                 if err := enc.WriteField(hpack.HeaderField{Name: k, Value: v}); err != nil {
78                         t.Fatalf("HPACK encoding error for %q/%q: %v", k, v, err)
79                 }
80         }
81         return buf.Bytes()
82 }
83
84 // Verify that curl has http2.
85 func requireCurl(t *testing.T) {
86         out, err := dockerLogs(curl(t, "--version"))
87         if err != nil {
88                 t.Skipf("failed to determine curl features; skipping test")
89         }
90         if !strings.Contains(string(out), "HTTP2") {
91                 t.Skip("curl doesn't support HTTP2; skipping test")
92         }
93 }
94
95 func curl(t *testing.T, args ...string) (container string) {
96         out, err := exec.Command("docker", append([]string{"run", "-d", "--net=host", "gohttp2/curl"}, args...)...).Output()
97         if err != nil {
98                 t.Skipf("Failed to run curl in docker: %v, %s", err, out)
99         }
100         return strings.TrimSpace(string(out))
101 }
102
103 // Verify that h2load exists.
104 func requireH2load(t *testing.T) {
105         out, err := dockerLogs(h2load(t, "--version"))
106         if err != nil {
107                 t.Skipf("failed to probe h2load; skipping test: %s", out)
108         }
109         if !strings.Contains(string(out), "h2load nghttp2/") {
110                 t.Skipf("h2load not present; skipping test. (Output=%q)", out)
111         }
112 }
113
114 func h2load(t *testing.T, args ...string) (container string) {
115         out, err := exec.Command("docker", append([]string{"run", "-d", "--net=host", "--entrypoint=/usr/local/bin/h2load", "gohttp2/curl"}, args...)...).Output()
116         if err != nil {
117                 t.Skipf("Failed to run h2load in docker: %v, %s", err, out)
118         }
119         return strings.TrimSpace(string(out))
120 }
121
122 type puppetCommand struct {
123         fn   func(w http.ResponseWriter, r *http.Request)
124         done chan<- bool
125 }
126
127 type handlerPuppet struct {
128         ch chan puppetCommand
129 }
130
131 func newHandlerPuppet() *handlerPuppet {
132         return &handlerPuppet{
133                 ch: make(chan puppetCommand),
134         }
135 }
136
137 func (p *handlerPuppet) act(w http.ResponseWriter, r *http.Request) {
138         for cmd := range p.ch {
139                 cmd.fn(w, r)
140                 cmd.done <- true
141         }
142 }
143
144 func (p *handlerPuppet) done() { close(p.ch) }
145 func (p *handlerPuppet) do(fn func(http.ResponseWriter, *http.Request)) {
146         done := make(chan bool)
147         p.ch <- puppetCommand{fn, done}
148         <-done
149 }
150 func dockerLogs(container string) ([]byte, error) {
151         out, err := exec.Command("docker", "wait", container).CombinedOutput()
152         if err != nil {
153                 return out, err
154         }
155         exitStatus, err := strconv.Atoi(strings.TrimSpace(string(out)))
156         if err != nil {
157                 return out, errors.New("unexpected exit status from docker wait")
158         }
159         out, err = exec.Command("docker", "logs", container).CombinedOutput()
160         exec.Command("docker", "rm", container).Run()
161         if err == nil && exitStatus != 0 {
162                 err = fmt.Errorf("exit status %d: %s", exitStatus, out)
163         }
164         return out, err
165 }
166
167 func kill(container string) {
168         exec.Command("docker", "kill", container).Run()
169         exec.Command("docker", "rm", container).Run()
170 }
171
172 func cleanDate(res *http.Response) {
173         if d := res.Header["Date"]; len(d) == 1 {
174                 d[0] = "XXX"
175         }
176 }
177
178 func TestSorterPoolAllocs(t *testing.T) {
179         ss := []string{"a", "b", "c"}
180         h := http.Header{
181                 "a": nil,
182                 "b": nil,
183                 "c": nil,
184         }
185         sorter := new(sorter)
186
187         if allocs := testing.AllocsPerRun(100, func() {
188                 sorter.SortStrings(ss)
189         }); allocs >= 1 {
190                 t.Logf("SortStrings allocs = %v; want <1", allocs)
191         }
192
193         if allocs := testing.AllocsPerRun(5, func() {
194                 if len(sorter.Keys(h)) != 3 {
195                         t.Fatal("wrong result")
196                 }
197         }); allocs > 0 {
198                 t.Logf("Keys allocs = %v; want <1", allocs)
199         }
200 }
201
202 // waitCondition reports whether fn eventually returned true,
203 // checking immediately and then every checkEvery amount,
204 // until waitFor has elapsed, at which point it returns false.
205 func waitCondition(waitFor, checkEvery time.Duration, fn func() bool) bool {
206         deadline := time.Now().Add(waitFor)
207         for time.Now().Before(deadline) {
208                 if fn() {
209                         return true
210                 }
211                 time.Sleep(checkEvery)
212         }
213         return false
214 }
215
216 // waitErrCondition is like waitCondition but with errors instead of bools.
217 func waitErrCondition(waitFor, checkEvery time.Duration, fn func() error) error {
218         deadline := time.Now().Add(waitFor)
219         var err error
220         for time.Now().Before(deadline) {
221                 if err = fn(); err == nil {
222                         return nil
223                 }
224                 time.Sleep(checkEvery)
225         }
226         return err
227 }
228
229 func equalError(a, b error) bool {
230         if a == nil {
231                 return b == nil
232         }
233         if b == nil {
234                 return a == nil
235         }
236         return a.Error() == b.Error()
237 }
238
239 // Tests that http2.Server.IdleTimeout is initialized from
240 // http.Server.{Idle,Read}Timeout. http.Server.IdleTimeout was
241 // added in Go 1.8.
242 func TestConfigureServerIdleTimeout_Go18(t *testing.T) {
243         const timeout = 5 * time.Second
244         const notThisOne = 1 * time.Second
245
246         // With a zero http2.Server, verify that it copies IdleTimeout:
247         {
248                 s1 := &http.Server{
249                         IdleTimeout: timeout,
250                         ReadTimeout: notThisOne,
251                 }
252                 s2 := &Server{}
253                 if err := ConfigureServer(s1, s2); err != nil {
254                         t.Fatal(err)
255                 }
256                 if s2.IdleTimeout != timeout {
257                         t.Errorf("s2.IdleTimeout = %v; want %v", s2.IdleTimeout, timeout)
258                 }
259         }
260
261         // And that it falls back to ReadTimeout:
262         {
263                 s1 := &http.Server{
264                         ReadTimeout: timeout,
265                 }
266                 s2 := &Server{}
267                 if err := ConfigureServer(s1, s2); err != nil {
268                         t.Fatal(err)
269                 }
270                 if s2.IdleTimeout != timeout {
271                         t.Errorf("s2.IdleTimeout = %v; want %v", s2.IdleTimeout, timeout)
272                 }
273         }
274
275         // Verify that s1's IdleTimeout doesn't overwrite an existing setting:
276         {
277                 s1 := &http.Server{
278                         IdleTimeout: notThisOne,
279                 }
280                 s2 := &Server{
281                         IdleTimeout: timeout,
282                 }
283                 if err := ConfigureServer(s1, s2); err != nil {
284                         t.Fatal(err)
285                 }
286                 if s2.IdleTimeout != timeout {
287                         t.Errorf("s2.IdleTimeout = %v; want %v", s2.IdleTimeout, timeout)
288                 }
289         }
290 }