OLD | NEW |
| (Empty) |
1 // Copyright 2015 The Chromium Authors. All rights reserved. | |
2 // Use of this source code is governed by a BSD-style license that can be | |
3 // found in the LICENSE file. | |
4 | |
5 package lhttp | |
6 | |
7 import ( | |
8 "bytes" | |
9 "encoding/json" | |
10 "errors" | |
11 "fmt" | |
12 "io" | |
13 "io/ioutil" | |
14 "net/http" | |
15 "net/http/httptest" | |
16 "testing" | |
17 "time" | |
18 | |
19 "github.com/luci/luci-go/client/internal/retry" | |
20 "github.com/maruel/ut" | |
21 ) | |
22 | |
23 func TestNewRequestGET(t *testing.T) { | |
24 // First call returns HTTP 500, second succeeds. | |
25 serverCalls := 0 | |
26 ts := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r
*http.Request) { | |
27 serverCalls++ | |
28 content, err := ioutil.ReadAll(r.Body) | |
29 ut.ExpectEqual(t, nil, err) | |
30 ut.ExpectEqual(t, []byte{}, content) | |
31 if serverCalls == 1 { | |
32 w.WriteHeader(500) | |
33 } else { | |
34 fmt.Fprintf(w, "Hello, client\n") | |
35 } | |
36 })) | |
37 defer ts.Close() | |
38 | |
39 httpReq, err := http.NewRequest("GET", ts.URL, nil) | |
40 ut.AssertEqual(t, nil, err) | |
41 | |
42 clientCalls := 0 | |
43 clientReq, err := NewRequest(http.DefaultClient, httpReq, func(resp *htt
p.Response) error { | |
44 clientCalls++ | |
45 content, err := ioutil.ReadAll(resp.Body) | |
46 ut.AssertEqual(t, nil, err) | |
47 ut.AssertEqual(t, "Hello, client\n", string(content)) | |
48 ut.AssertEqual(t, nil, resp.Body.Close()) | |
49 return nil | |
50 }) | |
51 ut.AssertEqual(t, nil, err) | |
52 | |
53 ut.AssertEqual(t, nil, fast.Do(clientReq)) | |
54 ut.AssertEqual(t, 200, clientReq.Status()) | |
55 ut.AssertEqual(t, 2, serverCalls) | |
56 ut.AssertEqual(t, 1, clientCalls) | |
57 } | |
58 | |
59 func TestNewRequestPOST(t *testing.T) { | |
60 // First call returns HTTP 500, second succeeds. | |
61 serverCalls := 0 | |
62 ts := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r
*http.Request) { | |
63 serverCalls++ | |
64 content, err := ioutil.ReadAll(r.Body) | |
65 ut.ExpectEqual(t, nil, err) | |
66 // The same data is sent twice. | |
67 ut.ExpectEqual(t, "foo bar", string(content)) | |
68 if serverCalls == 1 { | |
69 w.WriteHeader(500) | |
70 } else { | |
71 fmt.Fprintf(w, "Hello, client\n") | |
72 } | |
73 })) | |
74 defer ts.Close() | |
75 | |
76 httpReq, err := http.NewRequest("POST", ts.URL, newReader([]byte("foo ba
r"))) | |
77 ut.AssertEqual(t, nil, err) | |
78 | |
79 clientCalls := 0 | |
80 clientReq, err := NewRequest(http.DefaultClient, httpReq, func(resp *htt
p.Response) error { | |
81 clientCalls++ | |
82 content, err := ioutil.ReadAll(resp.Body) | |
83 ut.AssertEqual(t, nil, err) | |
84 ut.AssertEqual(t, "Hello, client\n", string(content)) | |
85 ut.AssertEqual(t, nil, resp.Body.Close()) | |
86 return nil | |
87 }) | |
88 ut.AssertEqual(t, nil, err) | |
89 | |
90 ut.AssertEqual(t, nil, fast.Do(clientReq)) | |
91 ut.AssertEqual(t, 200, clientReq.Status()) | |
92 ut.AssertEqual(t, 2, serverCalls) | |
93 ut.AssertEqual(t, 1, clientCalls) | |
94 } | |
95 | |
96 func TestNewRequestNotSeeker(t *testing.T) { | |
97 // bytes.NewReader() doesn't implement io.Seeker. | |
98 ts := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r
*http.Request) { | |
99 t.Fail() | |
100 })) | |
101 defer ts.Close() | |
102 httpReq, err := http.NewRequest("POST", ts.URL, bytes.NewReader([]byte("
foo bar"))) | |
103 ut.AssertEqual(t, nil, err) | |
104 | |
105 clientReq, err := NewRequest(http.DefaultClient, httpReq, func(resp *htt
p.Response) error { | |
106 t.Fail() | |
107 return nil | |
108 }) | |
109 | |
110 ut.AssertEqual(t, nil, clientReq) | |
111 ut.AssertEqual(t, errors.New("req.Body must implement io.Seeker"), err) | |
112 } | |
113 | |
114 func TestNewRequestBadURL(t *testing.T) { | |
115 httpReq, err := http.NewRequest("GET", "invalid url", nil) | |
116 ut.AssertEqual(t, nil, err) | |
117 | |
118 clientReq, err := NewRequest(http.DefaultClient, httpReq, func(resp *htt
p.Response) error { | |
119 t.Fail() | |
120 return nil | |
121 }) | |
122 ut.AssertEqual(t, errors.New("unsupported protocol scheme \"\""), err) | |
123 ut.AssertEqual(t, nil, clientReq) | |
124 } | |
125 | |
126 func TestNewRequestGETFail(t *testing.T) { | |
127 serverCalls := 0 | |
128 ts := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r
*http.Request) { | |
129 serverCalls++ | |
130 w.WriteHeader(500) | |
131 })) | |
132 defer ts.Close() | |
133 | |
134 httpReq, err := http.NewRequest("GET", ts.URL, nil) | |
135 ut.AssertEqual(t, nil, err) | |
136 | |
137 clientReq, err := NewRequest(http.DefaultClient, httpReq, func(resp *htt
p.Response) error { | |
138 t.Fail() | |
139 return nil | |
140 }) | |
141 | |
142 ut.AssertEqual(t, retry.Error{errors.New("http request failed: Internal
Server Error (HTTP 500)")}, fast.Do(clientReq)) | |
143 ut.AssertEqual(t, 500, clientReq.Status()) | |
144 ut.AssertEqual(t, fast.MaxTries, serverCalls) | |
145 } | |
146 | |
147 func TestNewRequestJSONBadURL(t *testing.T) { | |
148 clientReq, err := NewRequestJSON(http.DefaultClient, "GET", "invalid url
", nil, nil) | |
149 ut.AssertEqual(t, errors.New("unsupported protocol scheme \"\""), err) | |
150 ut.AssertEqual(t, nil, clientReq) | |
151 } | |
152 | |
153 func TestGetJSON(t *testing.T) { | |
154 // First call returns HTTP 500, second succeeds. | |
155 serverCalls := 0 | |
156 ts := httptest.NewServer(handlerJSON(t, func(body io.Reader) interface{}
{ | |
157 serverCalls++ | |
158 content, err := ioutil.ReadAll(body) | |
159 ut.ExpectEqual(t, nil, err) | |
160 ut.ExpectEqual(t, []byte{}, content) | |
161 if serverCalls == 1 { | |
162 return nil | |
163 } | |
164 return map[string]string{"success": "yeah"} | |
165 })) | |
166 defer ts.Close() | |
167 | |
168 actual := map[string]string{} | |
169 status, err := GetJSON(fast, http.DefaultClient, ts.URL, &actual) | |
170 ut.AssertEqual(t, nil, err) | |
171 ut.AssertEqual(t, 200, status) | |
172 ut.AssertEqual(t, map[string]string{"success": "yeah"}, actual) | |
173 ut.AssertEqual(t, 2, serverCalls) | |
174 } | |
175 | |
176 func TestGetJSONBadResult(t *testing.T) { | |
177 serverCalls := 0 | |
178 ts := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r
*http.Request) { | |
179 serverCalls++ | |
180 w.Header().Set("Content-Type", jsonContentType) | |
181 _, err := io.WriteString(w, "yo") | |
182 ut.ExpectEqual(t, nil, err) | |
183 })) | |
184 defer ts.Close() | |
185 | |
186 actual := map[string]string{} | |
187 status, err := GetJSON(fast, http.DefaultClient, ts.URL, &actual) | |
188 ut.AssertEqual(t, retry.Error{errors.New("bad response " + ts.URL + ": i
nvalid character 'y' looking for beginning of value")}, err) | |
189 ut.AssertEqual(t, 200, status) | |
190 ut.AssertEqual(t, map[string]string{}, actual) | |
191 ut.AssertEqual(t, fast.MaxTries, serverCalls) | |
192 } | |
193 | |
194 func TestGetJSONBadResultIgnore(t *testing.T) { | |
195 serverCalls := 0 | |
196 ts := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r
*http.Request) { | |
197 serverCalls++ | |
198 w.Header().Set("Content-Type", jsonContentType) | |
199 _, err := io.WriteString(w, "yo") | |
200 ut.ExpectEqual(t, nil, err) | |
201 })) | |
202 defer ts.Close() | |
203 | |
204 status, err := GetJSON(fast, http.DefaultClient, ts.URL, nil) | |
205 ut.AssertEqual(t, retry.Error{errors.New("bad response " + ts.URL + ": i
nvalid character 'y' looking for beginning of value")}, err) | |
206 ut.AssertEqual(t, 200, status) | |
207 } | |
208 | |
209 func TestGetJSONBadContentTypeIgnore(t *testing.T) { | |
210 ts := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r
*http.Request) { | |
211 _, err := io.WriteString(w, "{}") | |
212 ut.ExpectEqual(t, nil, err) | |
213 })) | |
214 defer ts.Close() | |
215 | |
216 status, err := GetJSON(fast, http.DefaultClient, ts.URL, nil) | |
217 ut.AssertEqual(t, errors.New("unexpected Content-Type, expected \"applic
ation/json; charset=utf-8\", got \"text/plain; charset=utf-8\""), err) | |
218 ut.AssertEqual(t, 200, status) | |
219 } | |
220 | |
221 func TestPostJSON(t *testing.T) { | |
222 // First call returns HTTP 500, second succeeds. | |
223 serverCalls := 0 | |
224 ts := httptest.NewServer(handlerJSON(t, func(body io.Reader) interface{}
{ | |
225 serverCalls++ | |
226 data := map[string]string{} | |
227 ut.ExpectEqual(t, nil, json.NewDecoder(body).Decode(&data)) | |
228 ut.ExpectEqual(t, map[string]string{"in": "all"}, data) | |
229 if serverCalls == 1 { | |
230 return nil | |
231 } | |
232 return map[string]string{"success": "yeah"} | |
233 })) | |
234 defer ts.Close() | |
235 | |
236 in := map[string]string{"in": "all"} | |
237 actual := map[string]string{} | |
238 status, err := PostJSON(fast, http.DefaultClient, ts.URL, in, &actual) | |
239 ut.AssertEqual(t, nil, err) | |
240 ut.AssertEqual(t, 200, status) | |
241 ut.AssertEqual(t, map[string]string{"success": "yeah"}, actual) | |
242 ut.AssertEqual(t, 2, serverCalls) | |
243 } | |
244 | |
245 // Private details. | |
246 | |
247 var fast = &retry.Config{ | |
248 MaxTries: 3, | |
249 SleepMax: 0, | |
250 } | |
251 | |
252 // slow is to be used when no retry should happen. The test will hang in that | |
253 // case. | |
254 var slow = &retry.Config{ | |
255 MaxTries: 3, | |
256 SleepMax: time.Hour, | |
257 SleepBase: time.Hour, | |
258 } | |
259 | |
260 type jsonAPI func(body io.Reader) interface{} | |
261 | |
262 // handlerJSON converts a jsonAPI http handler to a proper http.Handler. | |
263 func handlerJSON(t *testing.T, handler jsonAPI) http.Handler { | |
264 return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { | |
265 //ut.ExpectEqual(t, jsonContentType, r.Header.Get("Content-Type"
)) | |
266 defer r.Body.Close() | |
267 out := handler(r.Body) | |
268 if out == nil { | |
269 w.WriteHeader(500) | |
270 } else { | |
271 w.Header().Set("Content-Type", jsonContentType) | |
272 ut.ExpectEqual(t, nil, json.NewEncoder(w).Encode(out)) | |
273 } | |
274 }) | |
275 } | |
OLD | NEW |