1
2
3
4
5
6
7
8
9
10
11
12
13
14
15 package proxy
16
17 import (
18 "io"
19 "net/http"
20 "net/url"
21 "strings"
22 "testing"
23
24 "cloud.google.com/go/internal/testutil"
25 "github.com/google/go-cmp/cmp/cmpopts"
26 "github.com/google/martian/v3"
27 )
28
29 func TestLogger(t *testing.T) {
30 req := &http.Request{
31 Method: "POST",
32 URL: &url.URL{
33 Scheme: "https",
34 Host: "example.com",
35 Path: "a/b/c",
36 },
37 Header: http.Header{"H1": {"v1", "v2"}, "Content-Type": {"text/plain"}},
38 Body: io.NopCloser(strings.NewReader("hello")),
39 Trailer: http.Header{"T1": {"v3", "v4"}},
40 }
41 res := &http.Response{
42 Request: req,
43 StatusCode: 204,
44 Body: io.NopCloser(strings.NewReader("goodbye")),
45 Header: http.Header{"H2": {"v5"}},
46 Trailer: http.Header{"T2": {"v6", "v7"}},
47 }
48 l := newLogger()
49 _, remove, err := martian.TestContext(req, nil, nil)
50 if err != nil {
51 t.Fatal(err)
52 }
53 defer remove()
54 if err := l.ModifyRequest(req); err != nil {
55 t.Fatal(err)
56 }
57 if err := l.ModifyResponse(res); err != nil {
58 t.Fatal(err)
59 }
60 lg := l.Extract()
61 want := []*Entry{
62 {
63 ID: lg.Entries[0].ID,
64 Request: &Request{
65 Method: "POST",
66 URL: "https://example.com/a/b/c",
67 Header: http.Header{"H1": {"v1", "v2"}},
68 MediaType: "text/plain",
69 BodyParts: [][]byte{[]byte("hello")},
70 Trailer: http.Header{"T1": {"v3", "v4"}},
71 },
72 Response: &Response{
73 StatusCode: 204,
74 Body: []byte("goodbye"),
75 Header: http.Header{"H2": {"v5"}},
76 Trailer: http.Header{"T2": {"v6", "v7"}},
77 },
78 },
79 }
80 if diff := testutil.Diff(lg.Entries, want); diff != "" {
81 t.Error(diff)
82 }
83 }
84
85 func TestToHTTPResponse(t *testing.T) {
86 for _, test := range []struct {
87 desc string
88 lr *Response
89 req *http.Request
90 want *http.Response
91 }{
92 {
93 desc: "GET request",
94 lr: &Response{
95 StatusCode: 201,
96 Proto: "1.1",
97 Header: http.Header{"h": {"v"}},
98 Body: []byte("text"),
99 },
100 req: &http.Request{Method: "GET"},
101 want: &http.Response{
102 Request: &http.Request{Method: "GET"},
103 StatusCode: 201,
104 Proto: "1.1",
105 Header: http.Header{"h": {"v"}},
106 ContentLength: 4,
107 },
108 },
109 {
110 desc: "HEAD request with no Content-Length header",
111 lr: &Response{
112 StatusCode: 201,
113 Proto: "1.1",
114 Header: http.Header{"h": {"v"}},
115 Body: []byte("text"),
116 },
117 req: &http.Request{Method: "HEAD"},
118 want: &http.Response{
119 Request: &http.Request{Method: "HEAD"},
120 StatusCode: 201,
121 Proto: "1.1",
122 Header: http.Header{"h": {"v"}},
123 ContentLength: -1,
124 },
125 },
126 {
127 desc: "HEAD request with Content-Length header",
128 lr: &Response{
129 StatusCode: 201,
130 Proto: "1.1",
131 Header: http.Header{"h": {"v"}, "Content-Length": {"17"}},
132 Body: []byte("text"),
133 },
134 req: &http.Request{Method: "HEAD"},
135 want: &http.Response{
136 Request: &http.Request{Method: "HEAD"},
137 StatusCode: 201,
138 Proto: "1.1",
139 Header: http.Header{"h": {"v"}, "Content-Length": {"17"}},
140 ContentLength: 17,
141 },
142 },
143 } {
144 got := toHTTPResponse(test.lr, test.req)
145 got.Body = nil
146 if diff := testutil.Diff(got, test.want, cmpopts.IgnoreUnexported(http.Request{})); diff != "" {
147 t.Errorf("%s: %s", test.desc, diff)
148 }
149 }
150 }
151
152 func TestEmptyBody(t *testing.T) {
153
154
155 req := &http.Request{
156 Method: "POST",
157 URL: &url.URL{
158 Scheme: "https",
159 Host: "example.com",
160 Path: "a/b/c",
161 },
162 Body: io.NopCloser(strings.NewReader("")),
163 }
164 l := newLogger()
165 _, remove, err := martian.TestContext(req, nil, nil)
166 if err != nil {
167 t.Fatal(err)
168 }
169 defer remove()
170 if err := l.ModifyRequest(req); err != nil {
171 t.Fatal(err)
172 }
173 if req.Body != nil {
174 t.Error("got non-nil req.Body, want nil")
175 }
176 }
177
View as plain text