Você não pode selecionar mais de 25 tópicos Os tópicos devem começar com uma letra ou um número, podem incluir traços ('-') e podem ter até 35 caracteres.
 
 
 

229 linhas
5.4 KiB

  1. // Copyright 2018 Google LLC
  2. //
  3. // Licensed under the Apache License, Version 2.0 (the "License");
  4. // you may not use this file except in compliance with the License.
  5. // You may obtain a copy of the License at
  6. //
  7. // http://www.apache.org/licenses/LICENSE-2.0
  8. //
  9. // Unless required by applicable law or agreed to in writing, software
  10. // distributed under the License is distributed on an "AS IS" BASIS,
  11. // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  12. // See the License for the specific language governing permissions and
  13. // limitations under the License.
  14. package main_test
  15. import (
  16. "context"
  17. "crypto/tls"
  18. "crypto/x509"
  19. "errors"
  20. "fmt"
  21. "io/ioutil"
  22. "net"
  23. "net/http"
  24. "net/url"
  25. "os"
  26. "os/exec"
  27. "strings"
  28. "testing"
  29. "time"
  30. "cloud.google.com/go/internal/testutil"
  31. "cloud.google.com/go/storage"
  32. "golang.org/x/oauth2"
  33. "google.golang.org/api/option"
  34. )
  35. const initial = "initial state"
  36. func TestIntegration_HTTPR(t *testing.T) {
  37. if testing.Short() {
  38. t.Skip("Integration tests skipped in short mode")
  39. }
  40. if testutil.ProjID() == "" {
  41. t.Fatal("set GCLOUD_TESTS_GOLANG_PROJECT_ID and GCLOUD_TESTS_GOLANG_KEY")
  42. }
  43. // Get a unique temporary filename.
  44. f, err := ioutil.TempFile("", "httpreplay")
  45. if err != nil {
  46. t.Fatal(err)
  47. }
  48. replayFilename := f.Name()
  49. if err := f.Close(); err != nil {
  50. t.Fatal(err)
  51. }
  52. defer os.Remove(replayFilename)
  53. if err := exec.Command("go", "build").Run(); err != nil {
  54. t.Fatalf("running 'go build': %v", err)
  55. }
  56. defer os.Remove("./httpr")
  57. want := runRecord(t, replayFilename)
  58. got := runReplay(t, replayFilename)
  59. if got != want {
  60. t.Fatalf("got %q, want %q", got, want)
  61. }
  62. }
  63. func runRecord(t *testing.T, filename string) string {
  64. cmd, tr, cport, err := start("-record", filename)
  65. if err != nil {
  66. t.Fatal(err)
  67. }
  68. defer stop(t, cmd)
  69. ctx := context.Background()
  70. hc := &http.Client{
  71. Transport: &oauth2.Transport{
  72. Base: tr,
  73. Source: testutil.TokenSource(ctx, storage.ScopeFullControl),
  74. },
  75. }
  76. res, err := http.Post(
  77. fmt.Sprintf("http://localhost:%s/initial", cport),
  78. "text/plain",
  79. strings.NewReader(initial))
  80. if err != nil {
  81. t.Fatal(err)
  82. }
  83. if res.StatusCode != 200 {
  84. t.Fatalf("from POST: %s", res.Status)
  85. }
  86. info, err := getBucketInfo(ctx, hc)
  87. if err != nil {
  88. t.Fatal(err)
  89. }
  90. return info
  91. }
  92. func runReplay(t *testing.T, filename string) string {
  93. cmd, tr, cport, err := start("-replay", filename)
  94. if err != nil {
  95. t.Fatal(err)
  96. }
  97. defer stop(t, cmd)
  98. hc := &http.Client{Transport: tr}
  99. res, err := http.Get(fmt.Sprintf("http://localhost:%s/initial", cport))
  100. if err != nil {
  101. t.Fatal(err)
  102. }
  103. if res.StatusCode != 200 {
  104. t.Fatalf("from GET: %s", res.Status)
  105. }
  106. bytes, err := ioutil.ReadAll(res.Body)
  107. res.Body.Close()
  108. if err != nil {
  109. t.Fatal(err)
  110. }
  111. if got, want := string(bytes), initial; got != want {
  112. t.Errorf("initial: got %q, want %q", got, want)
  113. }
  114. info, err := getBucketInfo(context.Background(), hc)
  115. if err != nil {
  116. t.Fatal(err)
  117. }
  118. return info
  119. }
  120. // Start the proxy binary and wait for it to come up.
  121. // Return a transport that talks to the proxy, as well as the control port.
  122. // modeFlag must be either "-record" or "-replay".
  123. func start(modeFlag, filename string) (*exec.Cmd, *http.Transport, string, error) {
  124. pport, err := pickPort()
  125. if err != nil {
  126. return nil, nil, "", err
  127. }
  128. cport, err := pickPort()
  129. if err != nil {
  130. return nil, nil, "", err
  131. }
  132. cmd := exec.Command("./httpr", "-port", pport, "-control-port", cport, modeFlag, filename, "-debug-headers")
  133. if err := cmd.Start(); err != nil {
  134. return nil, nil, "", err
  135. }
  136. // Wait for the server to come up.
  137. serverUp := false
  138. for i := 0; i < 10; i++ {
  139. if conn, err := net.Dial("tcp", "localhost:"+cport); err == nil {
  140. conn.Close()
  141. serverUp = true
  142. break
  143. }
  144. time.Sleep(time.Second)
  145. }
  146. if !serverUp {
  147. return nil, nil, "", errors.New("server never came up")
  148. }
  149. tr, err := proxyTransport(pport, cport)
  150. if err != nil {
  151. return nil, nil, "", err
  152. }
  153. return cmd, tr, cport, nil
  154. }
  155. func stop(t *testing.T, cmd *exec.Cmd) {
  156. if err := cmd.Process.Signal(os.Interrupt); err != nil {
  157. t.Fatal(err)
  158. }
  159. }
  160. // pickPort picks an unused port.
  161. func pickPort() (string, error) {
  162. l, err := net.Listen("tcp", ":0")
  163. if err != nil {
  164. return "", err
  165. }
  166. addr := l.Addr().String()
  167. _, port, err := net.SplitHostPort(addr)
  168. if err != nil {
  169. return "", err
  170. }
  171. l.Close()
  172. return port, nil
  173. }
  174. func proxyTransport(pport, cport string) (*http.Transport, error) {
  175. caCert, err := getBody(fmt.Sprintf("http://localhost:%s/authority.cer", cport))
  176. if err != nil {
  177. return nil, err
  178. }
  179. caCertPool := x509.NewCertPool()
  180. if !caCertPool.AppendCertsFromPEM([]byte(caCert)) {
  181. return nil, errors.New("bad CA Cert")
  182. }
  183. return &http.Transport{
  184. Proxy: http.ProxyURL(&url.URL{Host: "localhost:" + pport}),
  185. TLSClientConfig: &tls.Config{RootCAs: caCertPool},
  186. }, nil
  187. }
  188. func getBucketInfo(ctx context.Context, hc *http.Client) (string, error) {
  189. client, err := storage.NewClient(ctx, option.WithHTTPClient(hc))
  190. if err != nil {
  191. return "", err
  192. }
  193. defer client.Close()
  194. b := client.Bucket(testutil.ProjID())
  195. attrs, err := b.Attrs(ctx)
  196. if err != nil {
  197. return "", err
  198. }
  199. return fmt.Sprintf("name:%s reqpays:%v location:%s sclass:%s",
  200. attrs.Name, attrs.RequesterPays, attrs.Location, attrs.StorageClass), nil
  201. }
  202. func getBody(url string) ([]byte, error) {
  203. res, err := http.Get(url)
  204. if err != nil {
  205. return nil, err
  206. }
  207. if res.StatusCode != 200 {
  208. return nil, fmt.Errorf("response: %s", res.Status)
  209. }
  210. defer res.Body.Close()
  211. return ioutil.ReadAll(res.Body)
  212. }