| 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 |