http2_test.go 3.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117
  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. // Look at net/http's Server tests for inspiration.
  34. w.Header().Set("Foo", "Bar")
  35. }))
  36. ConfigureServer(ts.Config, &Server{})
  37. ts.TLS = ts.Config.TLSConfig // the httptest.Server has its own copy of this TLS config
  38. ts.StartTLS()
  39. defer ts.Close()
  40. var gotConn int32
  41. testHookOnConn = func() { atomic.StoreInt32(&gotConn, 1) }
  42. t.Logf("Running test server for curl to hit at: %s", ts.URL)
  43. container := curl(t, "--silent", "--http2", "--insecure", "-v", ts.URL)
  44. defer kill(container)
  45. resc := make(chan interface{}, 1)
  46. go func() {
  47. res, err := dockerLogs(container)
  48. if err != nil {
  49. resc <- err
  50. } else {
  51. resc <- res
  52. }
  53. }()
  54. select {
  55. case res := <-resc:
  56. if err, ok := res.(error); ok {
  57. t.Fatal(err)
  58. }
  59. if !strings.Contains(string(res.([]byte)), "< foo:Bar") {
  60. t.Errorf("didn't see foo:Bar header")
  61. t.Logf("Got: %s", res)
  62. }
  63. case <-time.After(3 * time.Second):
  64. t.Errorf("timeout waiting for curl")
  65. }
  66. if atomic.LoadInt32(&gotConn) == 0 {
  67. t.Error("never saw an http2 connection")
  68. }
  69. }
  70. func dockerLogs(container string) ([]byte, error) {
  71. out, err := exec.Command("docker", "wait", container).CombinedOutput()
  72. if err != nil {
  73. return out, err
  74. }
  75. exitStatus, err := strconv.Atoi(strings.TrimSpace(string(out)))
  76. if err != nil {
  77. return out, errors.New("unexpected exit status from docker wait")
  78. }
  79. out, err = exec.Command("docker", "logs", container).CombinedOutput()
  80. exec.Command("docker", "rm", container).Run()
  81. if err == nil && exitStatus != 0 {
  82. err = fmt.Errorf("exit status %d", exitStatus)
  83. }
  84. return out, err
  85. }
  86. func kill(container string) {
  87. exec.Command("docker", "kill", container).Run()
  88. exec.Command("docker", "rm", container).Run()
  89. }
  90. // Verify that curl has http2.
  91. func requireCurl(t *testing.T) {
  92. out, err := dockerLogs(curl(t, "--version"))
  93. if err != nil {
  94. t.Skipf("failed to determine curl features; skipping test")
  95. }
  96. if !strings.Contains(string(out), "HTTP2") {
  97. t.Skip("curl doesn't support HTTP2; skipping test")
  98. }
  99. }
  100. func curl(t *testing.T, args ...string) (container string) {
  101. out, err := exec.Command("docker", append([]string{"run", "-d", "--net=host", "gohttp2/curl"}, args...)...).CombinedOutput()
  102. if err != nil {
  103. t.Skipf("Failed to run curl in docker: %v, %s", err, out)
  104. }
  105. return strings.TrimSpace(string(out))
  106. }