OSDN Git Service

new repo
[bytom/vapor.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
18         "golang.org/x/net/http2/hpack"
19 )
20
21 var knownFailing = flag.Bool("known_failing", false, "Run known-failing tests.")
22
23 func condSkipFailingTest(t *testing.T) {
24         if !*knownFailing {
25                 t.Skip("Skipping known-failing test without --known_failing")
26         }
27 }
28
29 func init() {
30         inTests = true
31         DebugGoroutines = true
32         flag.BoolVar(&VerboseLogs, "verboseh2", VerboseLogs, "Verbose HTTP/2 debug logging")
33 }
34
35 func TestSettingString(t *testing.T) {
36         tests := []struct {
37                 s    Setting
38                 want string
39         }{
40                 {Setting{SettingMaxFrameSize, 123}, "[MAX_FRAME_SIZE = 123]"},
41                 {Setting{1<<16 - 1, 123}, "[UNKNOWN_SETTING_65535 = 123]"},
42         }
43         for i, tt := range tests {
44                 got := fmt.Sprint(tt.s)
45                 if got != tt.want {
46                         t.Errorf("%d. for %#v, string = %q; want %q", i, tt.s, got, tt.want)
47                 }
48         }
49 }
50
51 type twriter struct {
52         t  testing.TB
53         st *serverTester // optional
54 }
55
56 func (w twriter) Write(p []byte) (n int, err error) {
57         if w.st != nil {
58                 ps := string(p)
59                 for _, phrase := range w.st.logFilter {
60                         if strings.Contains(ps, phrase) {
61                                 return len(p), nil // no logging
62                         }
63                 }
64         }
65         w.t.Logf("%s", p)
66         return len(p), nil
67 }
68
69 // like encodeHeader, but don't add implicit pseudo headers.
70 func encodeHeaderNoImplicit(t *testing.T, headers ...string) []byte {
71         var buf bytes.Buffer
72         enc := hpack.NewEncoder(&buf)
73         for len(headers) > 0 {
74                 k, v := headers[0], headers[1]
75                 headers = headers[2:]
76                 if err := enc.WriteField(hpack.HeaderField{Name: k, Value: v}); err != nil {
77                         t.Fatalf("HPACK encoding error for %q/%q: %v", k, v, err)
78                 }
79         }
80         return buf.Bytes()
81 }
82
83 // Verify that curl has http2.
84 func requireCurl(t *testing.T) {
85         out, err := dockerLogs(curl(t, "--version"))
86         if err != nil {
87                 t.Skipf("failed to determine curl features; skipping test")
88         }
89         if !strings.Contains(string(out), "HTTP2") {
90                 t.Skip("curl doesn't support HTTP2; skipping test")
91         }
92 }
93
94 func curl(t *testing.T, args ...string) (container string) {
95         out, err := exec.Command("docker", append([]string{"run", "-d", "--net=host", "gohttp2/curl"}, args...)...).Output()
96         if err != nil {
97                 t.Skipf("Failed to run curl in docker: %v, %s", err, out)
98         }
99         return strings.TrimSpace(string(out))
100 }
101
102 // Verify that h2load exists.
103 func requireH2load(t *testing.T) {
104         out, err := dockerLogs(h2load(t, "--version"))
105         if err != nil {
106                 t.Skipf("failed to probe h2load; skipping test: %s", out)
107         }
108         if !strings.Contains(string(out), "h2load nghttp2/") {
109                 t.Skipf("h2load not present; skipping test. (Output=%q)", out)
110         }
111 }
112
113 func h2load(t *testing.T, args ...string) (container string) {
114         out, err := exec.Command("docker", append([]string{"run", "-d", "--net=host", "--entrypoint=/usr/local/bin/h2load", "gohttp2/curl"}, args...)...).Output()
115         if err != nil {
116                 t.Skipf("Failed to run h2load in docker: %v, %s", err, out)
117         }
118         return strings.TrimSpace(string(out))
119 }
120
121 type puppetCommand struct {
122         fn   func(w http.ResponseWriter, r *http.Request)
123         done chan<- bool
124 }
125
126 type handlerPuppet struct {
127         ch chan puppetCommand
128 }
129
130 func newHandlerPuppet() *handlerPuppet {
131         return &handlerPuppet{
132                 ch: make(chan puppetCommand),
133         }
134 }
135
136 func (p *handlerPuppet) act(w http.ResponseWriter, r *http.Request) {
137         for cmd := range p.ch {
138                 cmd.fn(w, r)
139                 cmd.done <- true
140         }
141 }
142
143 func (p *handlerPuppet) done() { close(p.ch) }
144 func (p *handlerPuppet) do(fn func(http.ResponseWriter, *http.Request)) {
145         done := make(chan bool)
146         p.ch <- puppetCommand{fn, done}
147         <-done
148 }
149 func dockerLogs(container string) ([]byte, error) {
150         out, err := exec.Command("docker", "wait", container).CombinedOutput()
151         if err != nil {
152                 return out, err
153         }
154         exitStatus, err := strconv.Atoi(strings.TrimSpace(string(out)))
155         if err != nil {
156                 return out, errors.New("unexpected exit status from docker wait")
157         }
158         out, err = exec.Command("docker", "logs", container).CombinedOutput()
159         exec.Command("docker", "rm", container).Run()
160         if err == nil && exitStatus != 0 {
161                 err = fmt.Errorf("exit status %d: %s", exitStatus, out)
162         }
163         return out, err
164 }
165
166 func kill(container string) {
167         exec.Command("docker", "kill", container).Run()
168         exec.Command("docker", "rm", container).Run()
169 }
170
171 func cleanDate(res *http.Response) {
172         if d := res.Header["Date"]; len(d) == 1 {
173                 d[0] = "XXX"
174         }
175 }
176
177 func TestSorterPoolAllocs(t *testing.T) {
178         ss := []string{"a", "b", "c"}
179         h := http.Header{
180                 "a": nil,
181                 "b": nil,
182                 "c": nil,
183         }
184         sorter := new(sorter)
185
186         if allocs := testing.AllocsPerRun(100, func() {
187                 sorter.SortStrings(ss)
188         }); allocs >= 1 {
189                 t.Logf("SortStrings allocs = %v; want <1", allocs)
190         }
191
192         if allocs := testing.AllocsPerRun(5, func() {
193                 if len(sorter.Keys(h)) != 3 {
194                         t.Fatal("wrong result")
195                 }
196         }); allocs > 0 {
197                 t.Logf("Keys allocs = %v; want <1", allocs)
198         }
199 }