1package httpmock 2 3import ( 4 "encoding/json" 5 "encoding/xml" 6 "errors" 7 "io/ioutil" 8 "net/http" 9 "testing" 10) 11 12func TestResponderFromResponse(t *testing.T) { 13 responder := ResponderFromResponse(NewStringResponse(200, "hello world")) 14 15 req, err := http.NewRequest(http.MethodGet, testURL, nil) 16 if err != nil { 17 t.Fatal("Error creating request") 18 } 19 response1, err := responder(req) 20 if err != nil { 21 t.Error("Error should be nil") 22 } 23 24 testURLWithQuery := testURL + "?a=1" 25 req, err = http.NewRequest(http.MethodGet, testURLWithQuery, nil) 26 if err != nil { 27 t.Fatal("Error creating request") 28 } 29 response2, err := responder(req) 30 if err != nil { 31 t.Error("Error should be nil") 32 } 33 34 // Body should be the same for both responses 35 assertBody(t, response1, "hello world") 36 assertBody(t, response2, "hello world") 37 38 // Request should be non-nil and different for each response 39 if response1.Request != nil && response2.Request != nil { 40 if response1.Request.URL.String() != testURL { 41 t.Errorf("Expected request url %s, got: %s", testURL, response1.Request.URL.String()) 42 } 43 if response2.Request.URL.String() != testURLWithQuery { 44 t.Errorf("Expected request url %s, got: %s", testURLWithQuery, response2.Request.URL.String()) 45 } 46 } else { 47 t.Error("response.Request should not be nil") 48 } 49} 50 51func TestNewNotFoundResponder(t *testing.T) { 52 responder := NewNotFoundResponder(func(args ...interface{}) {}) 53 54 req, err := http.NewRequest("GET", "http://foo.bar/path", nil) 55 if err != nil { 56 t.Fatal("Error creating request") 57 } 58 59 const title = "Responder not found for GET http://foo.bar/path" 60 61 resp, err := responder(req) 62 if resp != nil { 63 t.Error("resp should be nil") 64 } 65 if err == nil { 66 t.Error("err should be not nil") 67 } else if err.Error() != title { 68 t.Errorf(`err mismatch, got: "%s", expected: "%s"`, 69 err, "Responder not found for: GET http://foo.bar/path") 70 } else if ne, ok := err.(stackTracer); !ok { 71 t.Errorf(`err type mismatch, got %T, expected httpmock.notFound`, err) 72 } else if ne.customFn == nil { 73 t.Error(`err customFn mismatch, got: nil, expected: non-nil`) 74 } 75 76 // nil fn 77 responder = NewNotFoundResponder(nil) 78 79 resp, err = responder(req) 80 if resp != nil { 81 t.Error("resp should be nil") 82 } 83 if err == nil { 84 t.Error("err should be not nil") 85 } else if err.Error() != title { 86 t.Errorf(`err mismatch, got: "%s", expected: "%s"`, 87 err, "Responder not found for: GET http://foo.bar/path") 88 } else if ne, ok := err.(stackTracer); !ok { 89 t.Errorf(`err type mismatch, got %T, expected httpmock.notFound`, err) 90 } else if ne.customFn != nil { 91 t.Errorf(`err customFn mismatch, got: %p, expected: nil`, ne.customFn) 92 } 93} 94 95func TestNewStringResponse(t *testing.T) { 96 body := "hello world" 97 status := 200 98 response := NewStringResponse(status, body) 99 100 data, err := ioutil.ReadAll(response.Body) 101 if err != nil { 102 t.Fatal(err) 103 } 104 105 if string(data) != body { 106 t.FailNow() 107 } 108 109 if response.StatusCode != status { 110 t.FailNow() 111 } 112} 113 114func TestNewBytesResponse(t *testing.T) { 115 body := []byte("hello world") 116 status := 200 117 response := NewBytesResponse(status, body) 118 119 data, err := ioutil.ReadAll(response.Body) 120 if err != nil { 121 t.Fatal(err) 122 } 123 124 if string(data) != string(body) { 125 t.FailNow() 126 } 127 128 if response.StatusCode != status { 129 t.FailNow() 130 } 131} 132 133func TestNewJsonResponse(t *testing.T) { 134 type schema struct { 135 Hello string `json:"hello"` 136 } 137 138 body := &schema{"world"} 139 status := 200 140 141 response, err := NewJsonResponse(status, body) 142 if err != nil { 143 t.Fatal(err) 144 } 145 146 if response.StatusCode != status { 147 t.FailNow() 148 } 149 150 if response.Header.Get("Content-Type") != "application/json" { 151 t.FailNow() 152 } 153 154 checkBody := &schema{} 155 if err := json.NewDecoder(response.Body).Decode(checkBody); err != nil { 156 t.Fatal(err) 157 } 158 159 if checkBody.Hello != body.Hello { 160 t.FailNow() 161 } 162} 163 164func TestNewXmlResponse(t *testing.T) { 165 type schema struct { 166 Hello string `xml:"hello"` 167 } 168 169 body := &schema{"world"} 170 status := 200 171 172 response, err := NewXmlResponse(status, body) 173 if err != nil { 174 t.Fatal(err) 175 } 176 177 if response.StatusCode != status { 178 t.FailNow() 179 } 180 181 if response.Header.Get("Content-Type") != "application/xml" { 182 t.FailNow() 183 } 184 185 checkBody := &schema{} 186 if err := xml.NewDecoder(response.Body).Decode(checkBody); err != nil { 187 t.Fatal(err) 188 } 189 190 if checkBody.Hello != body.Hello { 191 t.FailNow() 192 } 193} 194 195func TestNewErrorResponder(t *testing.T) { 196 // From go1.13, a stack frame is stored into errors issued by errors.New() 197 origError := errors.New("oh no") 198 responder := NewErrorResponder(origError) 199 req, err := http.NewRequest(http.MethodGet, testURL, nil) 200 if err != nil { 201 t.Fatal("Error creating request") 202 } 203 response, err := responder(req) 204 if response != nil { 205 t.Error("Response should be nil") 206 } 207 if err != origError { 208 t.Errorf("Expected error %#v, got: %#v", origError, err) 209 } 210} 211 212func TestRewindResponse(t *testing.T) { 213 body := []byte("hello world") 214 status := 200 215 responses := []*http.Response{ 216 NewBytesResponse(status, body), 217 NewStringResponse(status, string(body)), 218 } 219 220 for _, response := range responses { 221 222 data, err := ioutil.ReadAll(response.Body) 223 if err != nil { 224 t.Fatal(err) 225 } 226 227 if string(data) != string(body) { 228 t.FailNow() 229 } 230 231 if response.StatusCode != status { 232 t.FailNow() 233 } 234 235 data, err = ioutil.ReadAll(response.Body) 236 if err != nil { 237 t.Fatal(err) 238 } 239 240 if string(data) != string(body) { 241 t.FailNow() 242 } 243 244 if response.StatusCode != status { 245 t.FailNow() 246 } 247 } 248} 249 250func TestResponder(t *testing.T) { 251 req, err := http.NewRequest(http.MethodGet, "http://foo.bar", nil) 252 if err != nil { 253 t.Fatal("Error creating request") 254 } 255 resp := &http.Response{} 256 257 chk := func(r Responder, expectedResp *http.Response, expectedErr string) { 258 //t.Helper // Only available since 1.9 259 gotResp, gotErr := r(req) 260 if gotResp != expectedResp { 261 t.Errorf(`Response mismatch, expected: %v, got: %v`, expectedResp, gotResp) 262 } 263 var gotErrStr string 264 if gotErr != nil { 265 gotErrStr = gotErr.Error() 266 } 267 if gotErrStr != expectedErr { 268 t.Errorf(`Error mismatch, expected: %v, got: %v`, expectedErr, gotErrStr) 269 } 270 } 271 called := false 272 chkNotCalled := func() { 273 if called { 274 //t.Helper // Only available since 1.9 275 t.Errorf("Original responder should not be called") 276 called = false 277 } 278 } 279 chkCalled := func() { 280 if !called { 281 //t.Helper // Only available since 1.9 282 t.Errorf("Original responder should be called") 283 } 284 called = false 285 } 286 287 r := Responder(func(*http.Request) (*http.Response, error) { 288 called = true 289 return resp, nil 290 }) 291 chk(r, resp, "") 292 chkCalled() 293 294 // 295 // Once 296 ro := r.Once() 297 chk(ro, resp, "") 298 chkCalled() 299 300 chk(ro, nil, "Responder not found for GET http://foo.bar (coz Once and already called 2 times)") 301 chkNotCalled() 302 303 chk(ro, nil, "Responder not found for GET http://foo.bar (coz Once and already called 3 times)") 304 chkNotCalled() 305 306 ro = r.Once(func(args ...interface{}) {}) 307 chk(ro, resp, "") 308 chkCalled() 309 310 chk(ro, nil, "Responder not found for GET http://foo.bar (coz Once and already called 2 times)") 311 chkNotCalled() 312 313 // 314 // Times 315 rt := r.Times(2) 316 chk(rt, resp, "") 317 chkCalled() 318 319 chk(rt, resp, "") 320 chkCalled() 321 322 chk(rt, nil, "Responder not found for GET http://foo.bar (coz Times and already called 3 times)") 323 chkNotCalled() 324 325 chk(rt, nil, "Responder not found for GET http://foo.bar (coz Times and already called 4 times)") 326 chkNotCalled() 327 328 rt = r.Times(1, func(args ...interface{}) {}) 329 chk(rt, resp, "") 330 chkCalled() 331 332 chk(rt, nil, "Responder not found for GET http://foo.bar (coz Times and already called 2 times)") 333 chkNotCalled() 334 335 // 336 // Trace 337 rt = r.Trace(func(args ...interface{}) {}) 338 chk(rt, resp, "") 339 chkCalled() 340 341 chk(rt, resp, "") 342 chkCalled() 343} 344