http2_test.go 6.9 KB

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