http2_test.go 4.8 KB

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