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.
19 "golang.org/x/net/http2/hpack"
22 var knownFailing = flag.Bool("known_failing", false, "Run known-failing tests.")
24 func condSkipFailingTest(t *testing.T) {
26 t.Skip("Skipping known-failing test without --known_failing")
32 DebugGoroutines = true
33 flag.BoolVar(&VerboseLogs, "verboseh2", VerboseLogs, "Verbose HTTP/2 debug logging")
36 func TestSettingString(t *testing.T) {
41 {Setting{SettingMaxFrameSize, 123}, "[MAX_FRAME_SIZE = 123]"},
42 {Setting{1<<16 - 1, 123}, "[UNKNOWN_SETTING_65535 = 123]"},
44 for i, tt := range tests {
45 got := fmt.Sprint(tt.s)
47 t.Errorf("%d. for %#v, string = %q; want %q", i, tt.s, got, tt.want)
54 st *serverTester // optional
57 func (w twriter) Write(p []byte) (n int, err error) {
60 for _, phrase := range w.st.logFilter {
61 if strings.Contains(ps, phrase) {
62 return len(p), nil // no logging
70 // like encodeHeader, but don't add implicit pseudo headers.
71 func encodeHeaderNoImplicit(t *testing.T, headers ...string) []byte {
73 enc := hpack.NewEncoder(&buf)
74 for len(headers) > 0 {
75 k, v := headers[0], headers[1]
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)
84 // Verify that curl has http2.
85 func requireCurl(t *testing.T) {
86 out, err := dockerLogs(curl(t, "--version"))
88 t.Skipf("failed to determine curl features; skipping test")
90 if !strings.Contains(string(out), "HTTP2") {
91 t.Skip("curl doesn't support HTTP2; skipping test")
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()
98 t.Skipf("Failed to run curl in docker: %v, %s", err, out)
100 return strings.TrimSpace(string(out))
103 // Verify that h2load exists.
104 func requireH2load(t *testing.T) {
105 out, err := dockerLogs(h2load(t, "--version"))
107 t.Skipf("failed to probe h2load; skipping test: %s", out)
109 if !strings.Contains(string(out), "h2load nghttp2/") {
110 t.Skipf("h2load not present; skipping test. (Output=%q)", out)
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()
117 t.Skipf("Failed to run h2load in docker: %v, %s", err, out)
119 return strings.TrimSpace(string(out))
122 type puppetCommand struct {
123 fn func(w http.ResponseWriter, r *http.Request)
127 type handlerPuppet struct {
128 ch chan puppetCommand
131 func newHandlerPuppet() *handlerPuppet {
132 return &handlerPuppet{
133 ch: make(chan puppetCommand),
137 func (p *handlerPuppet) act(w http.ResponseWriter, r *http.Request) {
138 for cmd := range p.ch {
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}
150 func dockerLogs(container string) ([]byte, error) {
151 out, err := exec.Command("docker", "wait", container).CombinedOutput()
155 exitStatus, err := strconv.Atoi(strings.TrimSpace(string(out)))
157 return out, errors.New("unexpected exit status from docker wait")
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)
167 func kill(container string) {
168 exec.Command("docker", "kill", container).Run()
169 exec.Command("docker", "rm", container).Run()
172 func cleanDate(res *http.Response) {
173 if d := res.Header["Date"]; len(d) == 1 {
178 func TestSorterPoolAllocs(t *testing.T) {
179 ss := []string{"a", "b", "c"}
185 sorter := new(sorter)
187 if allocs := testing.AllocsPerRun(100, func() {
188 sorter.SortStrings(ss)
190 t.Logf("SortStrings allocs = %v; want <1", allocs)
193 if allocs := testing.AllocsPerRun(5, func() {
194 if len(sorter.Keys(h)) != 3 {
195 t.Fatal("wrong result")
198 t.Logf("Keys allocs = %v; want <1", allocs)
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) {
211 time.Sleep(checkEvery)
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)
220 for time.Now().Before(deadline) {
221 if err = fn(); err == nil {
224 time.Sleep(checkEvery)
229 func equalError(a, b error) bool {
236 return a.Error() == b.Error()
239 // Tests that http2.Server.IdleTimeout is initialized from
240 // http.Server.{Idle,Read}Timeout. http.Server.IdleTimeout was
242 func TestConfigureServerIdleTimeout_Go18(t *testing.T) {
243 const timeout = 5 * time.Second
244 const notThisOne = 1 * time.Second
246 // With a zero http2.Server, verify that it copies IdleTimeout:
249 IdleTimeout: timeout,
250 ReadTimeout: notThisOne,
253 if err := ConfigureServer(s1, s2); err != nil {
256 if s2.IdleTimeout != timeout {
257 t.Errorf("s2.IdleTimeout = %v; want %v", s2.IdleTimeout, timeout)
261 // And that it falls back to ReadTimeout:
264 ReadTimeout: timeout,
267 if err := ConfigureServer(s1, s2); err != nil {
270 if s2.IdleTimeout != timeout {
271 t.Errorf("s2.IdleTimeout = %v; want %v", s2.IdleTimeout, timeout)
275 // Verify that s1's IdleTimeout doesn't overwrite an existing setting:
278 IdleTimeout: notThisOne,
281 IdleTimeout: timeout,
283 if err := ConfigureServer(s1, s2); err != nil {
286 if s2.IdleTimeout != timeout {
287 t.Errorf("s2.IdleTimeout = %v; want %v", s2.IdleTimeout, timeout)