http2_test.go 3.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118
  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. // See https://code.google.com/p/go/source/browse/CONTRIBUTORS
  5. // Licensed under the same terms as Go itself:
  6. // https://code.google.com/p/go/source/browse/LICENSE
  7. package http2
  8. import (
  9. "errors"
  10. "fmt"
  11. "net/http"
  12. "net/http/httptest"
  13. "os/exec"
  14. "strconv"
  15. "strings"
  16. "sync/atomic"
  17. "testing"
  18. "time"
  19. )
  20. func TestServer(t *testing.T) {
  21. requireCurl(t)
  22. ts := httptest.NewUnstartedServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
  23. // TODO: add a bunch of different tests with different
  24. // behavior, as a function of r or a table.
  25. // -- with request body, without.
  26. // -- no interaction with w.
  27. // -- panic
  28. // -- modify Header only, but no writes or writeheader (this test)
  29. // -- WriteHeader only
  30. // -- Write only
  31. // -- WriteString
  32. // -- both
  33. // -- huge headers over a frame size so we get continuation headers.
  34. // Look at net/http's Server tests for inspiration.
  35. w.Header().Set("Foo", "Bar")
  36. }))
  37. ConfigureServer(ts.Config, &Server{})
  38. ts.TLS = ts.Config.TLSConfig // the httptest.Server has its own copy of this TLS config
  39. ts.StartTLS()
  40. defer ts.Close()
  41. var gotConn int32
  42. testHookOnConn = func() { atomic.StoreInt32(&gotConn, 1) }
  43. t.Logf("Running test server for curl to hit at: %s", ts.URL)
  44. container := curl(t, "--silent", "--http2", "--insecure", "-v", ts.URL)
  45. defer kill(container)
  46. resc := make(chan interface{}, 1)
  47. go func() {
  48. res, err := dockerLogs(container)
  49. if err != nil {
  50. resc <- err
  51. } else {
  52. resc <- res
  53. }
  54. }()
  55. select {
  56. case res := <-resc:
  57. if err, ok := res.(error); ok {
  58. t.Fatal(err)
  59. }
  60. if !strings.Contains(string(res.([]byte)), "< foo:Bar") {
  61. t.Errorf("didn't see foo:Bar header")
  62. t.Logf("Got: %s", res)
  63. }
  64. case <-time.After(3 * time.Second):
  65. t.Errorf("timeout waiting for curl")
  66. }
  67. if atomic.LoadInt32(&gotConn) == 0 {
  68. t.Error("never saw an http2 connection")
  69. }
  70. }
  71. func dockerLogs(container string) ([]byte, error) {
  72. out, err := exec.Command("docker", "wait", container).CombinedOutput()
  73. if err != nil {
  74. return out, err
  75. }
  76. exitStatus, err := strconv.Atoi(strings.TrimSpace(string(out)))
  77. if err != nil {
  78. return out, errors.New("unexpected exit status from docker wait")
  79. }
  80. out, err = exec.Command("docker", "logs", container).CombinedOutput()
  81. exec.Command("docker", "rm", container).Run()
  82. if err == nil && exitStatus != 0 {
  83. err = fmt.Errorf("exit status %d", exitStatus)
  84. }
  85. return out, err
  86. }
  87. func kill(container string) {
  88. exec.Command("docker", "kill", container).Run()
  89. exec.Command("docker", "rm", container).Run()
  90. }
  91. // Verify that curl has http2.
  92. func requireCurl(t *testing.T) {
  93. out, err := dockerLogs(curl(t, "--version"))
  94. if err != nil {
  95. t.Skipf("failed to determine curl features; skipping test")
  96. }
  97. if !strings.Contains(string(out), "HTTP2") {
  98. t.Skip("curl doesn't support HTTP2; skipping test")
  99. }
  100. }
  101. func curl(t *testing.T, args ...string) (container string) {
  102. out, err := exec.Command("docker", append([]string{"run", "-d", "--net=host", "gohttp2/curl"}, args...)...).CombinedOutput()
  103. if err != nil {
  104. t.Skipf("Failed to run curl in docker: %v, %s", err, out)
  105. }
  106. return strings.TrimSpace(string(out))
  107. }